Commit | Line | Data |
---|---|---|
b1ea73b5 MK |
1 | /******************************************************************************* |
2 | * Copyright (c) 2015 Ericsson | |
3 | * | |
4 | * All rights reserved. This program and the accompanying materials | |
5 | * are made available under the terms of the Eclipse Public License v1.0 | |
6 | * which accompanies this distribution, and is available at | |
7 | * http://www.eclipse.org/legal/epl-v10.html | |
8 | *******************************************************************************/ | |
9 | ||
10 | package org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.trace; | |
11 | ||
12 | import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.concatenateUnaryStrings; | |
13 | import static org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TsdlUtils.isAnyUnaryString; | |
14 | ||
15 | import java.nio.ByteOrder; | |
16 | import java.util.List; | |
17 | import java.util.Map.Entry; | |
18 | import java.util.UUID; | |
19 | ||
20 | import org.antlr.runtime.tree.CommonTree; | |
21 | import org.eclipse.core.runtime.IStatus; | |
22 | import org.eclipse.jdt.annotation.NonNullByDefault; | |
23 | import org.eclipse.tracecompass.ctf.core.event.metadata.DeclarationScope; | |
24 | import org.eclipse.tracecompass.ctf.core.event.types.EnumDeclaration; | |
25 | import org.eclipse.tracecompass.ctf.core.event.types.EnumDeclaration.Pair; | |
26 | import org.eclipse.tracecompass.ctf.core.event.types.FloatDeclaration; | |
27 | import org.eclipse.tracecompass.ctf.core.event.types.IDeclaration; | |
28 | import org.eclipse.tracecompass.ctf.core.event.types.IntegerDeclaration; | |
29 | import org.eclipse.tracecompass.ctf.core.event.types.StructDeclaration; | |
30 | import org.eclipse.tracecompass.ctf.core.event.types.VariantDeclaration; | |
31 | import org.eclipse.tracecompass.ctf.core.trace.CTFTrace; | |
32 | import org.eclipse.tracecompass.ctf.parser.CTFParser; | |
33 | import org.eclipse.tracecompass.internal.ctf.core.Activator; | |
34 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser; | |
35 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.Messages; | |
36 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings; | |
37 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException; | |
38 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.ByteOrderParser; | |
39 | import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeSpecifierListParser; | |
40 | ||
41 | /** | |
42 | * | |
43 | * A <em>trace<em> is divided into multiple event streams. Each event stream | |
44 | * contains a subset of the trace event types. <br> | |
45 | * The final output of the trace, after its generation and optional transport | |
46 | * over the network, is expected to be either on permanent or temporary storage | |
47 | * in a virtual file system. Because each event stream is appended to while a | |
48 | * trace is being recorded, each is associated with a distinct set of files for | |
49 | * output. Therefore, a stored trace can be represented as a directory | |
50 | * containing zero, one or more files per stream. <br> | |
51 | * Metadata description associated with the trace contains information on trace | |
52 | * event types expressed in the _Trace Stream Description Language_ (TSDL). This | |
53 | * language describes: <br> | |
54 | * <ul> | |
55 | * <li>Trace version</li> | |
56 | * <li>Types available</li> | |
57 | * <li>Per-trace event header description</li> | |
58 | * <li>Per-stream event header description</li> | |
59 | * <li>Per-stream event context description</li> | |
60 | * <li>Per-event | |
61 | * <ul> | |
62 | * <li>Event type to stream mapping</li> | |
63 | * <li>Event type to name mapping</li> | |
64 | * <li>Event type to ID mapping</li> | |
65 | * <li>Event context description</li> | |
66 | * <li>Event fields description</li> | |
67 | * </ul> | |
68 | * </ul> | |
69 | * | |
70 | * @author Matthew Khouzam | |
71 | * | |
72 | */ | |
4055c3a1 | 73 | public final class TraceDeclarationParser extends AbstractScopedCommonTreeParser { |
b1ea73b5 MK |
74 | |
75 | /** | |
76 | * Parameter object | |
77 | * | |
78 | * @author Matthew Khouzam | |
79 | * | |
80 | */ | |
81 | @NonNullByDefault | |
82 | public static final class Param implements ICommonTreeParserParameter { | |
83 | ||
84 | private final DeclarationScope fCurrentScope; | |
85 | private final CTFTrace fTrace; | |
86 | ||
87 | /** | |
88 | * Parameter Object | |
89 | * | |
90 | * @param trace | |
91 | * the trace | |
92 | * @param currentScope | |
93 | * the current scope | |
94 | */ | |
95 | public Param(CTFTrace trace, DeclarationScope currentScope) { | |
96 | fTrace = trace; | |
97 | fCurrentScope = currentScope; | |
98 | } | |
99 | ||
100 | } | |
101 | ||
102 | /** | |
103 | * Parser instance | |
104 | */ | |
105 | public static final TraceDeclarationParser INSTANCE = new TraceDeclarationParser(); | |
106 | ||
107 | private TraceDeclarationParser() { | |
108 | } | |
109 | ||
110 | /** | |
111 | * Parse a trace AST node | |
112 | * | |
113 | * @param traceDecl | |
114 | * trace AST node | |
115 | * @param param | |
116 | * A parameter object of the type {@link Param} | |
117 | * @return a {@link CTFTrace} that is populated | |
118 | * @throws ParseException | |
119 | * if the AST is malformed | |
120 | */ | |
121 | @Override | |
122 | public CTFTrace parse(CommonTree traceDecl, ICommonTreeParserParameter param) throws ParseException { | |
123 | if (!(param instanceof Param)) { | |
124 | throw new IllegalArgumentException("Param must be a " + Param.class.getCanonicalName()); //$NON-NLS-1$ | |
125 | } | |
126 | CTFTrace trace = ((Param) param).fTrace; | |
127 | DeclarationScope scope = ((Param) param).fCurrentScope; | |
128 | ||
129 | /* There should be a left and right */ | |
130 | CommonTree leftNode = (CommonTree) traceDecl.getChild(0); | |
131 | CommonTree rightNode = (CommonTree) traceDecl.getChild(1); | |
132 | ||
133 | List<CommonTree> leftStrings = leftNode.getChildren(); | |
134 | ||
135 | if (!isAnyUnaryString(leftStrings.get(0))) { | |
136 | throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$ | |
137 | } | |
138 | ||
139 | String left = concatenateUnaryStrings(leftStrings); | |
140 | ||
141 | if (left.equals(MetadataStrings.MAJOR)) { | |
142 | if (trace.majorIsSet()) { | |
143 | throw new ParseException("major is already set"); //$NON-NLS-1$ | |
144 | } | |
145 | ||
146 | trace.setMajor(VersionNumberParser.INSTANCE.parse(rightNode, null)); | |
147 | } else if (left.equals(MetadataStrings.MINOR)) { | |
148 | if (trace.minorIsSet()) { | |
149 | throw new ParseException("minor is already set"); //$NON-NLS-1$ | |
150 | } | |
151 | ||
152 | trace.setMinor(VersionNumberParser.INSTANCE.parse(rightNode, null)); | |
153 | } else if (left.equals(MetadataStrings.UUID_STRING)) { | |
154 | UUID uuid = UUIDParser.INSTANCE.parse(rightNode, null); | |
155 | ||
156 | /* | |
157 | * If uuid was already set by a metadata packet, compare it to see | |
158 | * if it matches | |
159 | */ | |
160 | if (trace.uuidIsSet()) { | |
161 | if (trace.getUUID().compareTo(uuid) != 0) { | |
162 | throw new ParseException("UUID mismatch. Packet says " //$NON-NLS-1$ | |
163 | + trace.getUUID() + " but metadata says " + uuid); //$NON-NLS-1$ | |
164 | } | |
165 | } else { | |
166 | trace.setUUID(uuid); | |
167 | } | |
168 | ||
169 | } else if (left.equals(MetadataStrings.BYTE_ORDER)) { | |
170 | ByteOrder byteOrder = ByteOrderParser.INSTANCE.parse(rightNode, new ByteOrderParser.Param(trace)); | |
171 | ||
172 | /* | |
173 | * If byte order was already set by a metadata packet, compare it to | |
174 | * see if it matches | |
175 | */ | |
176 | if (trace.getByteOrder() != null) { | |
177 | if (trace.getByteOrder() != byteOrder) { | |
178 | throw new ParseException( | |
179 | "Endianness mismatch. Magic number says " //$NON-NLS-1$ | |
180 | + trace.getByteOrder() | |
181 | + " but metadata says " + byteOrder); //$NON-NLS-1$ | |
182 | } | |
183 | } else { | |
184 | trace.setByteOrder(byteOrder); | |
185 | ||
186 | final DeclarationScope currentScope = scope; | |
187 | for (String type : currentScope.getTypeNames()) { | |
188 | IDeclaration d = currentScope.lookupType(type); | |
189 | if (d instanceof IntegerDeclaration) { | |
190 | addByteOrder(byteOrder, currentScope, type, (IntegerDeclaration) d); | |
191 | } else if (d instanceof FloatDeclaration) { | |
192 | addByteOrder(byteOrder, currentScope, type, (FloatDeclaration) d); | |
193 | } else if (d instanceof EnumDeclaration) { | |
194 | addByteOrder(byteOrder, currentScope, type, (EnumDeclaration) d); | |
195 | } else if (d instanceof StructDeclaration) { | |
196 | setAlign(currentScope, (StructDeclaration) d, byteOrder); | |
197 | } | |
198 | } | |
199 | } | |
200 | } else if (left.equals(MetadataStrings.PACKET_HEADER)) { | |
201 | if (trace.packetHeaderIsSet()) { | |
202 | throw new ParseException("packet.header already defined"); //$NON-NLS-1$ | |
203 | } | |
204 | ||
205 | CommonTree typeSpecifier = (CommonTree) rightNode.getChild(0); | |
206 | ||
207 | if (typeSpecifier.getType() != CTFParser.TYPE_SPECIFIER_LIST) { | |
208 | throw new ParseException("packet.header expects a type specifier"); //$NON-NLS-1$ | |
209 | } | |
210 | ||
211 | IDeclaration packetHeaderDecl = TypeSpecifierListParser.INSTANCE.parse(typeSpecifier, new TypeSpecifierListParser.Param(trace, null, null, scope)); | |
212 | ||
213 | if (!(packetHeaderDecl instanceof StructDeclaration)) { | |
214 | throw new ParseException("packet.header expects a struct"); //$NON-NLS-1$ | |
215 | } | |
216 | ||
217 | trace.setPacketHeader((StructDeclaration) packetHeaderDecl); | |
218 | } else { | |
219 | Activator.log(IStatus.WARNING, Messages.IOStructGen_UnknownTraceAttributeWarning + " " + left); //$NON-NLS-1$ | |
220 | } | |
221 | return trace; | |
222 | } | |
223 | ||
224 | private static void addByteOrder(ByteOrder byteOrder, | |
225 | final DeclarationScope parentScope, String name, | |
226 | IntegerDeclaration decl) throws ParseException { | |
227 | ||
228 | if (!decl.isByteOrderSet()) { | |
229 | IntegerDeclaration newI; | |
230 | newI = IntegerDeclaration.createDeclaration(decl.getLength(), decl.isSigned(), | |
231 | decl.getBase(), byteOrder, decl.getEncoding(), | |
232 | decl.getClock(), decl.getAlignment()); | |
233 | parentScope.replaceType(name, newI); | |
234 | } | |
235 | } | |
236 | ||
237 | private static void addByteOrder(ByteOrder byteOrder, DeclarationScope parentScope, String name, EnumDeclaration decl) throws ParseException { | |
238 | if (!decl.isByteOrderSet()) { | |
239 | final IntegerDeclaration containerType = decl.getContainerType(); | |
240 | EnumDeclaration newEnum = new EnumDeclaration(IntegerDeclaration.createDeclaration(containerType.getLength(), containerType.isSigned(), | |
241 | containerType.getBase(), byteOrder, containerType.getEncoding(), | |
242 | containerType.getClock(), containerType.getAlignment())); | |
243 | for (Entry<String, Pair> entry : decl.getEnumTable().entrySet()) { | |
244 | newEnum.add(entry.getValue().getFirst(), entry.getValue().getSecond(), entry.getKey()); | |
245 | } | |
246 | ||
247 | parentScope.replaceType(name, newEnum); | |
248 | } | |
249 | } | |
250 | ||
251 | private static void addByteOrder(ByteOrder byteOrder, DeclarationScope parentScope, String name, FloatDeclaration decl) throws ParseException { | |
252 | if (!decl.isByteOrderSet()) { | |
253 | FloatDeclaration newFloat = new FloatDeclaration(decl.getExponent(), decl.getMantissa(), byteOrder, decl.getAlignment()); | |
254 | parentScope.replaceType(name, newFloat); | |
255 | } | |
256 | } | |
257 | ||
258 | private void setAlign(DeclarationScope parentScope, StructDeclaration sd, | |
259 | ByteOrder byteOrder) throws ParseException { | |
260 | ||
261 | for (String s : sd.getFieldsList()) { | |
262 | IDeclaration d = sd.getField(s); | |
263 | ||
264 | if (d instanceof StructDeclaration) { | |
265 | setAlign(parentScope, (StructDeclaration) d, byteOrder); | |
266 | ||
267 | } else if (d instanceof VariantDeclaration) { | |
268 | setAlign(parentScope, (VariantDeclaration) d, byteOrder); | |
269 | } else if (d instanceof IntegerDeclaration) { | |
270 | IntegerDeclaration decl = (IntegerDeclaration) d; | |
271 | if (decl.getByteOrder() != byteOrder) { | |
272 | IntegerDeclaration newI; | |
273 | newI = IntegerDeclaration.createDeclaration(decl.getLength(), | |
274 | decl.isSigned(), decl.getBase(), byteOrder, | |
275 | decl.getEncoding(), decl.getClock(), | |
276 | decl.getAlignment()); | |
277 | sd.getFields().put(s, newI); | |
278 | } | |
279 | } | |
280 | } | |
281 | } | |
282 | ||
283 | private void setAlign(DeclarationScope parentScope, VariantDeclaration vd, | |
284 | ByteOrder byteOrder) throws ParseException { | |
285 | ||
286 | for (String s : vd.getFields().keySet()) { | |
287 | IDeclaration d = vd.getFields().get(s); | |
288 | ||
289 | if (d instanceof StructDeclaration) { | |
290 | setAlign(parentScope, (StructDeclaration) d, byteOrder); | |
291 | ||
292 | } else if (d instanceof IntegerDeclaration) { | |
293 | IntegerDeclaration decl = (IntegerDeclaration) d; | |
294 | IntegerDeclaration newI; | |
295 | newI = IntegerDeclaration.createDeclaration(decl.getLength(), | |
296 | decl.isSigned(), decl.getBase(), byteOrder, | |
297 | decl.getEncoding(), decl.getClock(), | |
298 | decl.getAlignment()); | |
299 | vd.getFields().put(s, newI); | |
300 | } | |
301 | } | |
302 | } | |
303 | } |