1 /*******************************************************************************
2 * Copyright (c) 2015 Ericsson
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 *******************************************************************************/
10 package org
.eclipse
.tracecompass
.internal
.ctf
.core
.event
.metadata
.tsdl
.trace
;
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
;
15 import java
.nio
.ByteOrder
;
16 import java
.util
.List
;
17 import java
.util
.Map
.Entry
;
18 import java
.util
.UUID
;
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
;
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>
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>
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>
70 * @author Matthew Khouzam
73 public final class TraceDeclarationParser
extends AbstractScopedCommonTreeParser
{
78 * @author Matthew Khouzam
82 public static final class Param
implements ICommonTreeParserParameter
{
84 private final DeclarationScope fCurrentScope
;
85 private final CTFTrace fTrace
;
95 public Param(CTFTrace trace
, DeclarationScope currentScope
) {
97 fCurrentScope
= currentScope
;
105 public static final TraceDeclarationParser INSTANCE
= new TraceDeclarationParser();
107 private TraceDeclarationParser() {
111 * Parse a trace AST node
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
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$
126 CTFTrace trace
= ((Param
) param
).fTrace
;
127 DeclarationScope scope
= ((Param
) param
).fCurrentScope
;
129 /* There should be a left and right */
130 CommonTree leftNode
= (CommonTree
) traceDecl
.getChild(0);
131 CommonTree rightNode
= (CommonTree
) traceDecl
.getChild(1);
133 List
<CommonTree
> leftStrings
= leftNode
.getChildren();
135 if (!isAnyUnaryString(leftStrings
.get(0))) {
136 throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$
139 String left
= concatenateUnaryStrings(leftStrings
);
141 if (left
.equals(MetadataStrings
.MAJOR
)) {
142 if (trace
.majorIsSet()) {
143 throw new ParseException("major is already set"); //$NON-NLS-1$
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$
152 trace
.setMinor(VersionNumberParser
.INSTANCE
.parse(rightNode
, null));
153 } else if (left
.equals(MetadataStrings
.UUID_STRING
)) {
154 UUID uuid
= UUIDParser
.INSTANCE
.parse(rightNode
, null);
157 * If uuid was already set by a metadata packet, compare it to see
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$
169 } else if (left
.equals(MetadataStrings
.BYTE_ORDER
)) {
170 ByteOrder byteOrder
= ByteOrderParser
.INSTANCE
.parse(rightNode
, new ByteOrderParser
.Param(trace
));
173 * If byte order was already set by a metadata packet, compare it to
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$
184 trace
.setByteOrder(byteOrder
);
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
);
200 } else if (left
.equals(MetadataStrings
.PACKET_HEADER
)) {
201 if (trace
.packetHeaderIsSet()) {
202 throw new ParseException("packet.header already defined"); //$NON-NLS-1$
205 CommonTree typeSpecifier
= (CommonTree
) rightNode
.getChild(0);
207 if (typeSpecifier
.getType() != CTFParser
.TYPE_SPECIFIER_LIST
) {
208 throw new ParseException("packet.header expects a type specifier"); //$NON-NLS-1$
211 IDeclaration packetHeaderDecl
= TypeSpecifierListParser
.INSTANCE
.parse(typeSpecifier
, new TypeSpecifierListParser
.Param(trace
, null, null, scope
));
213 if (!(packetHeaderDecl
instanceof StructDeclaration
)) {
214 throw new ParseException("packet.header expects a struct"); //$NON-NLS-1$
217 trace
.setPacketHeader((StructDeclaration
) packetHeaderDecl
);
219 Activator
.log(IStatus
.WARNING
, Messages
.IOStructGen_UnknownTraceAttributeWarning
+ " " + left
); //$NON-NLS-1$
224 private static void addByteOrder(ByteOrder byteOrder
,
225 final DeclarationScope parentScope
, String name
,
226 IntegerDeclaration decl
) throws ParseException
{
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
);
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());
247 parentScope
.replaceType(name
, newEnum
);
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
);
258 private void setAlign(DeclarationScope parentScope
, StructDeclaration sd
,
259 ByteOrder byteOrder
) throws ParseException
{
261 for (String s
: sd
.getFieldsList()) {
262 IDeclaration d
= sd
.getField(s
);
264 if (d
instanceof StructDeclaration
) {
265 setAlign(parentScope
, (StructDeclaration
) d
, byteOrder
);
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
);
283 private void setAlign(DeclarationScope parentScope
, VariantDeclaration vd
,
284 ByteOrder byteOrder
) throws ParseException
{
286 for (String s
: vd
.getFields().keySet()) {
287 IDeclaration d
= vd
.getFields().get(s
);
289 if (d
instanceof StructDeclaration
) {
290 setAlign(parentScope
, (StructDeclaration
) d
, byteOrder
);
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
);