From c60d02d42414a80d8ca56c2ea39e143040483615 Mon Sep 17 00:00:00 2001 From: Sehr Moosabhoy Date: Thu, 13 Jul 2023 14:36:42 -0400 Subject: [PATCH] ctf.core: Parse event fragments and strings Implement parsing of all json events and add null-terminated string handling. Data stream fragment handling has not been implemented yet, but the if-statement was added. To test, use [1] succeed1 CTF2 trace. [1] https://review.lttng.org/plugins/gitiles/babeltrace/+/refs/heads/ctf2/tests/data/ctf-traces/2/succeed/succeed1/ Change-Id: I710e7f58ac934feaa165ea92336ad0e94d3dd701 Signed-off-by: Sehr Moosabhoy Reviewed-on: https://git.eclipse.org/r/c/tracecompass/org.eclipse.tracecompass/+/203147 Tested-by: Trace Compass Bot Tested-by: Marco Miller Reviewed-by: Marco Miller --- .../ctf/core/event/metadata/IOStructGen.java | 8 +- .../event/metadata/tsdl/TypeAliasParser.java | 3 + .../tsdl/event/EventDeclarationParser.java | 209 +++++++++++------- .../metadata/tsdl/event/EventParser.java | 37 ++-- .../tsdl/string/StringDeclarationParser.java | 3 +- .../ctf/core/utils/JsonMetadataStrings.java | 5 + 6 files changed, 168 insertions(+), 97 deletions(-) diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java index 0529a5a904..6a3d143af9 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/IOStructGen.java @@ -154,7 +154,7 @@ private void parseRoot(ICTFMetadataNode root) throws ParseException { } else if (CTFParser.tokenNames[CTFParser.STREAM].equals(type)) { StreamParser.INSTANCE.parse(child, new StreamParser.Param(fTrace, fRoot)); hasStreams = true; - } else if (CTFParser.tokenNames[CTFParser.EVENT].equals(type)) { + } else if (CTFParser.tokenNames[CTFParser.EVENT].equals(type) || JsonMetadataStrings.FRAGMENT_EVENT_RECORD.equals(type)) { events.add(child); } else if (CTFParser.tokenNames[CTFParser.CLOCK].equals(type)) { CTFClock ctfClock = ClockParser.INSTANCE.parse(child, null); @@ -165,7 +165,11 @@ private void parseRoot(ICTFMetadataNode root) throws ParseException { } else if (CTFParser.tokenNames[CTFParser.CALLSITE].equals(type)) { callsites.add(CallSiteParser.INSTANCE.parse(child, null)); } else if (JsonMetadataStrings.FRAGMENT_PREAMBLE.equals(type)) { - // Do nothing for now + // FIXME: support Preamble fragment (CTF2 spec 5.5) + // https://diamon.org/ctf/files/CTF2-SPECRC-7.0rA.html#preamble-frag + } else if (JsonMetadataStrings.FRAGMENT_DATA_STREAM.equals(type)) { + // FIXME: support Data Stream fragment (CTF2 spec 5.9) + // https://diamon.org/ctf/files/CTF2-SPECRC-7.0rA.html#dsc-frag } else { throw childTypeError(child); } diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java index afcf6448da..2e865cbe6d 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/TypeAliasParser.java @@ -24,6 +24,7 @@ import org.eclipse.tracecompass.internal.ctf.core.event.metadata.JsonStructureFieldMemberMetadataNode; import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException; import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.integer.IntegerDeclarationParser; +import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.string.StringDeclarationParser; import org.eclipse.tracecompass.internal.ctf.core.event.types.ICTFMetadataNode; import org.eclipse.tracecompass.internal.ctf.core.utils.JsonMetadataStrings; @@ -101,6 +102,8 @@ public IDeclaration parse(ICTFMetadataNode typealias, ICommonTreeParserParameter targetDeclaration = IntegerDeclarationParser.INSTANCE.parse(typealias, new IntegerDeclarationParser.Param(trace)); } else if (JsonMetadataStrings.STATIC_LENGTH_BLOB.equals(type)) { targetDeclaration = BlobDeclarationParser.INSTANCE.parse(typealias, null); + } else if (JsonMetadataStrings.NULL_TERMINATED_STRING.equals(type)) { + targetDeclaration = StringDeclarationParser.INSTANCE.parse(typealias, null); } else { throw new ParseException("Invalid field class"); //$NON-NLS-1$ } diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventDeclarationParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventDeclarationParser.java index 78d43166de..9d4cd3e88a 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventDeclarationParser.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventDeclarationParser.java @@ -24,6 +24,10 @@ import org.eclipse.tracecompass.ctf.parser.CTFParser; import org.eclipse.tracecompass.internal.ctf.core.event.EventDeclaration; import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser; +import org.eclipse.tracecompass.internal.ctf.core.event.metadata.CTFAntlrMetadataNode; +import org.eclipse.tracecompass.internal.ctf.core.event.metadata.CTFJsonMetadataNode; +import org.eclipse.tracecompass.internal.ctf.core.event.metadata.JsonEventRecordMetadataNode; +import org.eclipse.tracecompass.internal.ctf.core.event.metadata.JsonStructureFieldMetadataNode; import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings; import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException; import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeSpecifierListParser; @@ -88,107 +92,156 @@ public EventDeclaration parse(ICTFMetadataNode eventDecl, ICommonTreeParserParam EventDeclaration event = ((Param) param).fEvent; CTFTrace fTrace = ((Param) param).fTrace; - /* There should be a left and right */ + if (eventDecl instanceof CTFJsonMetadataNode) { + JsonEventRecordMetadataNode rec = (JsonEventRecordMetadataNode) eventDecl; - ICTFMetadataNode leftNode = eventDecl.getChild(0); - ICTFMetadataNode rightNode = eventDecl.getChild(1); + String name = rec.getName(); + if (name != null) { + event.setName(name); + } - List leftStrings = leftNode.getChildren(); + // default is 0 + long id = rec.getId(); + verifyEventId(event, id); + event.setId(id); - if (!isAnyUnaryString(leftStrings.get(0))) { - throw new ParseException("Left side of CTF assignment must be a string"); //$NON-NLS-1$ - } + // default is 0 + long streamId = rec.getDataStreamClassId(); + CTFStream ctfStream = verifyStream(fTrace, streamId); + event.setStream(ctfStream); - String left = concatenateUnaryStrings(leftStrings); + JsonStructureFieldMetadataNode context = rec.getSpecificContextClass(); + if (context != null) { + IDeclaration contextDecl = TypeSpecifierListParser.INSTANCE.parse(rec.getSpecificContextClass(), new TypeSpecifierListParser.Param(fTrace, null, null, scope)); + verifyContext(contextDecl); + event.setContext((StructDeclaration) contextDecl); + } - if (left.equals(MetadataStrings.NAME2)) { - if (event.nameIsSet()) { - throw new ParseException("name already defined"); //$NON-NLS-1$ + JsonStructureFieldMetadataNode payload = rec.getPayloadFieldClass(); + if (payload != null) { + IDeclaration fieldsDecl = TypeSpecifierListParser.INSTANCE.parse(rec.getPayloadFieldClass(), new TypeSpecifierListParser.Param(fTrace, null, null, scope)); + StructDeclaration fields = verifyFieldsDeclaration(fieldsDecl); + event.setFields(fields); } - String name = EventNameParser.INSTANCE.parse(rightNode, null); + } else if (eventDecl instanceof CTFAntlrMetadataNode) { + /* There should be a left and right */ - event.setName(name); - } else if (left.equals(MetadataStrings.ID)) { - if (event.idIsSet()) { - throw new ParseException("id already defined"); //$NON-NLS-1$ - } + ICTFMetadataNode leftNode = eventDecl.getChild(0); + ICTFMetadataNode rightNode = eventDecl.getChild(1); - long id = EventIDParser.INSTANCE.parse(rightNode, null); - if (id > Integer.MAX_VALUE) { - throw new ParseException("id is greater than int.maxvalue, unsupported. id : " + id); //$NON-NLS-1$ - } - if (id < 0) { - throw new ParseException("negative id, unsupported. id : " + id); //$NON-NLS-1$ - } - event.setId((int) id); - } else if (left.equals(MetadataStrings.STREAM_ID)) { - if (event.streamIsSet()) { - throw new ParseException("stream id already defined"); //$NON-NLS-1$ + List leftStrings = leftNode.getChildren(); + + if (!isAnyUnaryString(leftStrings.get(0))) { + throw new ParseException("left side of CTF assignment must be a string"); //$NON-NLS-1$ } - long streamId = StreamIdParser.INSTANCE.parse(rightNode, null); + String left = concatenateUnaryStrings(leftStrings); - /* - * If the event has a stream and it is defined, look up the stream, - * if it is the available, assign it. If not, the event is - * malformed. - */ - ICTFStream iStream = fTrace.getStream(streamId); - if (!(iStream instanceof CTFStream)) { - throw new ParseException("Event specified stream with ID " + streamId + ". But no stream with that ID was defined"); //$NON-NLS-1$ //$NON-NLS-2$ - } - CTFStream ctfStream = (CTFStream) iStream; - event.setStream(ctfStream); - } else if (left.equals(MetadataStrings.CONTEXT)) { - if (event.contextIsSet()) { - throw new ParseException("context already defined"); //$NON-NLS-1$ - } + if (left.equals(MetadataStrings.NAME2)) { + if (event.nameIsSet()) { + throw new ParseException("name already defined"); //$NON-NLS-1$ + } - ICTFMetadataNode typeSpecifier = rightNode.getChild(0); + String name = EventNameParser.INSTANCE.parse(rightNode, null); - if (!(CTFParser.tokenNames[CTFParser.TYPE_SPECIFIER_LIST].equals(typeSpecifier.getType()))) { - throw new ParseException("context expects a type specifier"); //$NON-NLS-1$ - } + event.setName(name); + } else if (left.equals(MetadataStrings.ID)) { + long id = EventIDParser.INSTANCE.parse(rightNode, null); - IDeclaration contextDecl = TypeSpecifierListParser.INSTANCE.parse(typeSpecifier, new TypeSpecifierListParser.Param(fTrace, null, null, scope)); + verifyEventId(event, id); + event.setId((int) id); + } else if (left.equals(MetadataStrings.STREAM_ID)) { + if (event.streamIsSet()) { + throw new ParseException("stream id already defined"); //$NON-NLS-1$ + } - if (!(contextDecl instanceof StructDeclaration)) { - throw new ParseException("context expects a struct"); //$NON-NLS-1$ - } + long streamId = StreamIdParser.INSTANCE.parse(rightNode, null); - event.setContext((StructDeclaration) contextDecl); - } else if (left.equals(MetadataStrings.FIELDS_STRING)) { - if (event.fieldsIsSet()) { - throw new ParseException("fields already defined"); //$NON-NLS-1$ - } + CTFStream ctfStream = verifyStream(fTrace, streamId); + event.setStream(ctfStream); + } else if (left.equals(MetadataStrings.CONTEXT)) { + if (event.contextIsSet()) { + throw new ParseException("context already defined"); //$NON-NLS-1$ + } - ICTFMetadataNode typeSpecifier = rightNode.getChild(0); + ICTFMetadataNode typeSpecifier = rightNode.getChild(0); - if (!(CTFParser.tokenNames[CTFParser.TYPE_SPECIFIER_LIST].equals(typeSpecifier.getType()))) { - throw new ParseException("fields expects a type specifier"); //$NON-NLS-1$ - } + if (!(CTFParser.tokenNames[CTFParser.TYPE_SPECIFIER_LIST].equals(typeSpecifier.getType()))) { + throw new ParseException("context expects a type specifier"); //$NON-NLS-1$ + } + + IDeclaration contextDecl = TypeSpecifierListParser.INSTANCE.parse(typeSpecifier, new TypeSpecifierListParser.Param(fTrace, null, null, scope)); + + verifyContext(contextDecl); + + event.setContext((StructDeclaration) contextDecl); + } else if (left.equals(MetadataStrings.FIELDS_STRING)) { + if (event.fieldsIsSet()) { + throw new ParseException("fields already defined"); //$NON-NLS-1$ + } - IDeclaration fieldsDecl; - fieldsDecl = TypeSpecifierListParser.INSTANCE.parse(typeSpecifier, new TypeSpecifierListParser.Param(fTrace, null, null, scope)); + ICTFMetadataNode typeSpecifier = rightNode.getChild(0); - if (!(fieldsDecl instanceof StructDeclaration)) { - throw new ParseException("fields expects a struct"); //$NON-NLS-1$ + if (!(CTFParser.tokenNames[CTFParser.TYPE_SPECIFIER_LIST].equals(typeSpecifier.getType()))) { + throw new ParseException("fields expects a type specifier"); //$NON-NLS-1$ + } + + IDeclaration fieldsDecl; + fieldsDecl = TypeSpecifierListParser.INSTANCE.parse(typeSpecifier, new TypeSpecifierListParser.Param(fTrace, null, null, scope)); + + final StructDeclaration fields = verifyFieldsDeclaration(fieldsDecl); + event.setFields(fields); + } else if (left.equals(MetadataStrings.LOGLEVEL2)) { + long logLevel = UnaryIntegerParser.INSTANCE.parse(rightNode.getChild(0), null); + event.setLogLevel(logLevel); + } else { + /* Custom event attribute, we'll add it to the attributes map */ + String right = UnaryStringParser.INSTANCE.parse(rightNode.getChild(0), null); + event.setCustomAttribute(left, right); } - /* - * The underscores in the event names. These underscores were added - * by the LTTng tracer. - */ - final StructDeclaration fields = (StructDeclaration) fieldsDecl; - event.setFields(fields); - } else if (left.equals(MetadataStrings.LOGLEVEL2)) { - long logLevel = UnaryIntegerParser.INSTANCE.parse(rightNode.getChild(0), null); - event.setLogLevel(logLevel); - } else { - /* Custom event attribute, we'll add it to the attributes map */ - String right = UnaryStringParser.INSTANCE.parse(rightNode.getChild(0), null); - event.setCustomAttribute(left, right); } return event; } + + private static void verifyContext(IDeclaration contextDecl) throws ParseException { + if (!(contextDecl instanceof StructDeclaration)) { + throw new ParseException("context expects a struct"); //$NON-NLS-1$ + } + } + + private static StructDeclaration verifyFieldsDeclaration(IDeclaration fieldsDecl) throws ParseException { + if (!(fieldsDecl instanceof StructDeclaration)) { + throw new ParseException("fields expects a struct"); //$NON-NLS-1$ + } + /* + * The underscores in the event names. These underscores were added by + * the LTTng tracer. + */ + return (StructDeclaration) fieldsDecl; + } + + /* + * If the event has a stream and it is defined, look up the stream, if it is + * available, assign it. If not, the event is malformed. + */ + private static CTFStream verifyStream(CTFTrace fTrace, long streamId) throws ParseException { + ICTFStream iStream = fTrace.getStream(streamId); + if (!(iStream instanceof CTFStream)) { + throw new ParseException("Event specified stream with ID " + streamId + ". But no stream with that ID was defined"); //$NON-NLS-1$ //$NON-NLS-2$ + } + return (CTFStream) iStream; + } + + private static void verifyEventId(EventDeclaration event, long id) throws ParseException { + if (event.idIsSet()) { + throw new ParseException("id already defined"); //$NON-NLS-1$ + } + if (id > Integer.MAX_VALUE) { + throw new ParseException("id is greater than int.maxvalue, unsupported. id : " + id); //$NON-NLS-1$ + } + if (id < 0) { + throw new ParseException("negative id, unsupported. id : " + id); //$NON-NLS-1$ + } + } } diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventParser.java index e2cce30175..043408dec9 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventParser.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/event/EventParser.java @@ -22,6 +22,7 @@ import org.eclipse.tracecompass.ctf.parser.CTFParser; import org.eclipse.tracecompass.internal.ctf.core.event.EventDeclaration; import org.eclipse.tracecompass.internal.ctf.core.event.metadata.AbstractScopedCommonTreeParser; +import org.eclipse.tracecompass.internal.ctf.core.event.metadata.CTFJsonMetadataNode; import org.eclipse.tracecompass.internal.ctf.core.event.metadata.MetadataStrings; import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException; import org.eclipse.tracecompass.internal.ctf.core.event.metadata.tsdl.TypeAliasParser; @@ -101,25 +102,29 @@ public EventDeclaration parse(ICTFMetadataNode eventNode, ICommonTreeParserParam } Param parameter = (Param) param; CTFTrace trace = ((Param) param).fTrace; - List children = eventNode.getChildren(); - if (children == null) { - throw new ParseException("Empty event block"); //$NON-NLS-1$ - } - EventDeclaration event = new EventDeclaration(); - DeclarationScope scope = new DeclarationScope(parameter.fCurrentScope, MetadataStrings.EVENT); - for (ICTFMetadataNode child : children) { - String type = child.getType(); - if (CTFParser.tokenNames[CTFParser.TYPEALIAS].equals(type)) { - TypeAliasParser.INSTANCE.parse(child, new TypeAliasParser.Param(trace, scope)); - } else if (CTFParser.tokenNames[CTFParser.TYPEDEF].equals(type)) { - TypedefParser.INSTANCE.parse(child, new TypedefParser.Param(trace, scope)); - } else if (CTFParser.tokenNames[CTFParser.CTF_EXPRESSION_TYPE].equals(type) || CTFParser.tokenNames[CTFParser.CTF_EXPRESSION_VAL].equals(type)) { - EventDeclarationParser.INSTANCE.parse(child, new EventDeclarationParser.Param(trace, event, scope)); - } else { - throw childTypeError(child); + if (eventNode instanceof CTFJsonMetadataNode) { + EventDeclarationParser.INSTANCE.parse(eventNode, new EventDeclarationParser.Param(trace, event, scope)); + } else { + List children = eventNode.getChildren(); + if (children == null) { + throw new ParseException("Empty event block"); //$NON-NLS-1$ + } + + for (ICTFMetadataNode child : children) { + String type = child.getType(); + if (CTFParser.tokenNames[CTFParser.TYPEALIAS].equals(type)) { + TypeAliasParser.INSTANCE.parse(child, new TypeAliasParser.Param(trace, scope)); + } else if (CTFParser.tokenNames[CTFParser.TYPEDEF].equals(type)) { + TypedefParser.INSTANCE.parse(child, new TypedefParser.Param(trace, scope)); + } else if (CTFParser.tokenNames[CTFParser.CTF_EXPRESSION_TYPE].equals(type) + || CTFParser.tokenNames[CTFParser.CTF_EXPRESSION_VAL].equals(type)) { + EventDeclarationParser.INSTANCE.parse(child, new EventDeclarationParser.Param(trace, event, scope)); + } else { + throw childTypeError(child); + } } } diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/string/StringDeclarationParser.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/string/StringDeclarationParser.java index cd47ac6c38..cc12c7b434 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/string/StringDeclarationParser.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/event/metadata/tsdl/string/StringDeclarationParser.java @@ -21,6 +21,7 @@ import org.eclipse.tracecompass.ctf.core.event.types.StringDeclaration; import org.eclipse.tracecompass.ctf.parser.CTFParser; import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ICommonTreeParser; +import org.eclipse.tracecompass.internal.ctf.core.event.metadata.JsonStructureFieldMemberMetadataNode; import org.eclipse.tracecompass.internal.ctf.core.event.metadata.ParseException; import org.eclipse.tracecompass.internal.ctf.core.event.types.ICTFMetadataNode; @@ -77,7 +78,7 @@ public StringDeclaration parse(ICTFMetadataNode string, ICommonTreeParserParamet List children = string.getChildren(); StringDeclaration stringDeclaration = null; - if (children == null) { + if (string instanceof JsonStructureFieldMemberMetadataNode || children == null) { stringDeclaration = StringDeclaration.getStringDeclaration(Encoding.UTF8); } else { Encoding encoding = Encoding.UTF8; diff --git a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java index 1cd2bcfd83..b9c15a9eca 100644 --- a/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java +++ b/ctf/org.eclipse.tracecompass.ctf.core/src/org/eclipse/tracecompass/internal/ctf/core/utils/JsonMetadataStrings.java @@ -82,4 +82,9 @@ private JsonMetadataStrings() { * Type string for a static length blob field class */ public static final String STATIC_LENGTH_BLOB = "static-length-blob"; //$NON-NLS-1$ + + /** + * Type string for a null terminated string field class + */ + public static final String NULL_TERMINATED_STRING = "null-terminated-string"; //$NON-NLS-1$ }