Skip to content

Commit

Permalink
ctf.core: Parse event fragments and strings
Browse files Browse the repository at this point in the history
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 <sehr.moosabhoy@ericsson.com>
Reviewed-on: https://git.eclipse.org/r/c/tracecompass/org.eclipse.tracecompass/+/203147
Tested-by: Trace Compass Bot <tracecompass-bot@eclipse.org>
Tested-by: Marco Miller <marco.miller@ericsson.com>
Reviewed-by: Marco Miller <marco.miller@ericsson.com>
  • Loading branch information
Sehr Moosabhoy authored and marco-miller committed Jul 27, 2023
1 parent e6381dc commit c60d02d
Show file tree
Hide file tree
Showing 6 changed files with 168 additions and 97 deletions.
Expand Up @@ -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);
Expand All @@ -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);
}
Expand Down
Expand Up @@ -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;

Expand Down Expand Up @@ -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$
}
Expand Down
Expand Up @@ -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;
Expand Down Expand Up @@ -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<ICTFMetadataNode> 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<ICTFMetadataNode> 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$
}
}
}
Expand Up @@ -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;
Expand Down Expand Up @@ -101,25 +102,29 @@ public EventDeclaration parse(ICTFMetadataNode eventNode, ICommonTreeParserParam
}
Param parameter = (Param) param;
CTFTrace trace = ((Param) param).fTrace;
List<ICTFMetadataNode> 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<ICTFMetadataNode> 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);
}
}
}

Expand Down
Expand Up @@ -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;

Expand Down Expand Up @@ -77,7 +78,7 @@ public StringDeclaration parse(ICTFMetadataNode string, ICommonTreeParserParamet
List<ICTFMetadataNode> 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;
Expand Down
Expand Up @@ -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$
}

0 comments on commit c60d02d

Please sign in to comment.