X-Git-Url: http://git.efficios.com/?p=ctf.git;a=blobdiff_plain;f=common-trace-format-proposal.txt;h=4cd7e7c751fcdbb851ac1f0c500471826827a269;hp=fcc3432ba54542df866759dab77abcb05f63ff27;hb=b9606a77153ca805c474ad34693085fdebcbc36d;hpb=2152348f6b8364f63e186967690795729c099949 diff --git a/common-trace-format-proposal.txt b/common-trace-format-proposal.txt index fcc3432..4cd7e7c 100644 --- a/common-trace-format-proposal.txt +++ b/common-trace-format-proposal.txt @@ -1,5 +1,5 @@ -RFC: Common Trace Format (CTF) Proposal (v1.6) +RFC: Common Trace Format (CTF) Proposal (pre-v1.7) Mathieu Desnoyers, EfficiOS Inc. @@ -68,14 +68,10 @@ A metadata event stream contains information on trace event types. It describes: 3. Event stream An event stream is divided in contiguous event packets of variable size. These -subdivisions have a variable size. An event packet can contain a certain amount -of padding at the end. The rationale for the event stream design choices is -explained in Appendix B. Stream Header Rationale. - -An event stream is divided in contiguous event packets of variable size. These -subdivisions have a variable size. An event packet can contain a certain amount -of padding at the end. The stream header is repeated at the beginning of each -event packet. +subdivisions have a variable size. An event packet can contain a certain +amount of padding at the end. The stream header is repeated at the +beginning of each event packet. The rationale for the event stream +design choices is explained in Appendix B. Stream Header Rationale. The event stream header will therefore be referred to as the "event packet header" throughout the rest of this document. @@ -83,9 +79,13 @@ header" throughout the rest of this document. 4. Types +Types are organized as type classes. Each type class belong to either of two +kind of types: basic types or compound types. + 4.1 Basic types -A basic type is a scalar type, as described in this section. +A basic type is a scalar type, as described in this section. It includes +integers, GNU/C bitfields, enumerations, and floating point values. 4.1.1 Type inheritance @@ -181,19 +181,19 @@ Metadata representation: Example of type inheritance (creation of a uint32_t named type): -typedef integer { +typealias integer { size = 32; signed = false; align = 32; -} uint32_t; +} : uint32_t; Definition of a named 5-bit signed bitfield: -typedef integer { +typealias integer { size = 5; signed = true; align = 1; -} int5_t; +} : int5_t; 4.1.6 GNU/C bitfields @@ -248,11 +248,11 @@ floating_point { Example of type inheritance: -typedef floating_point { +typealias floating_point { exp_dig = 8; /* sizeof(float) * CHAR_BIT - FLT_MANT_DIG */ mant_dig = 24; /* FLT_MANT_DIG */ byte_order = native; -} float; +} : float; TODO: define NaN, +inf, -inf behavior. @@ -268,14 +268,13 @@ description within the metadata. The mapping table maps inclusive value ranges values to strings. An enumeration from the C language can be represented in this format by having the same start_value and end_value for each element, which is in fact a range of size 1. This single-value range is supported without -repeating the start and end values with the value = string declaration. If the - is omitted, the type chosen by the C compiler to hold the -enumeration is used. The specifier can only be omitted for -enumerations containing only simple "value -> string" mappings (compatible with -C). - -enum name { - string = start_value1 ... end_value1, +repeating the start and end values with the value = string declaration. + +If a numeric value is encountered between < >, it represents the integer type +size used to hold the enumeration, in bits. + +enum name { + somestring = start_value1 ... end_value1, "other string" = start_value2 ... end_value2, yet_another_string, /* will be assigned to end_value2 + 1 */ "some other string" = value, @@ -285,7 +284,7 @@ enum name { If the values are omitted, the enumeration starts at 0 and increment of 1 for each entry: -enum name { +enum name <32> { ZERO, ONE, TWO, @@ -301,8 +300,12 @@ enum { ... } + 4.2 Compound types +Compound are aggregation of type declarations. Compound types include +structures, variant, arrays, sequences, and strings. + 4.2.1 Structures Structures are aligned on the largest alignment required by basic types @@ -336,7 +339,125 @@ struct { ... } -4.2.2 Arrays +4.2.2 Variants (Discriminated/Tagged Unions) + +A CTF variant is a selection between different types. A CTF variant must +always be defined within the scope of a structure or within fields +contained within a structure (defined recursively). A "tag" enumeration +field must appear in either the same lexical scope, prior to the variant +field (in field declaration order), in an uppermost lexical scope (see +Section 7.2.1), or in an uppermost dynamic scope (see Section 7.2.2). +The type selection is indicated by the mapping from the enumeration +value to the string used as variant type selector. The field to use as +tag is specified by the "tag_field", specified between "< >" after the +"variant" keyword for unnamed variants, and after "variant name" for +named variants. + +The alignment of the variant is the alignment of the type as selected by the tag +value for the specific instance of the variant. The alignment of the type +containing the variant is independent of the variant alignment. The size of the +variant is the size as selected by the tag value for the specific instance of +the variant. + +A named variant declaration followed by its definition within a structure +declaration: + +variant name { + field_type sel1; + field_type sel2; + field_type sel3; + ... +}; + +struct { + enum { sel1, sel2, sel3, ... } tag_field; + ... + variant name v; +} + +An unnamed variant definition within a structure is expressed by the following +metadata: + +struct { + enum { sel1, sel2, sel3, ... } tag_field; + ... + variant { + field_type sel1; + field_type sel2; + field_type sel3; + ... + } v; +} + +Example of a named variant within a sequence that refers to a single tag field: + +variant example { + uint32_t a; + uint64_t b; + short c; +}; + +struct { + enum { a, b, c } choice; + variant example v[unsigned int]; +} + +Example of an unnamed variant: + +struct { + enum { a, b, c, d } choice; + /* Unrelated fields can be added between the variant and its tag */ + int32_t somevalue; + variant { + uint32_t a; + uint64_t b; + short c; + struct { + unsigned int field1; + uint64_t field2; + } d; + } s; +} + +Example of an unnamed variant within an array: + +struct { + enum { a, b, c } choice; + variant { + uint32_t a; + uint64_t b; + short c; + } v[10]; +} + +Example of a variant type definition within a structure, where the defined type +is then declared within an array of structures. This variant refers to a tag +located in an upper lexical scope. This example clearly shows that a variant +type definition referring to the tag "x" uses the closest preceding field from +the lexical scope of the type definition. + +struct { + enum { a, b, c, d } x; + + typedef variant { /* + * "x" refers to the preceding "x" enumeration in the + * lexical scope of the type definition. + */ + uint32_t a; + uint64_t b; + short c; + } example_variant; + + struct { + enum { x, y, z } x; /* This enumeration is not used by "v". */ + example_variant v; /* + * "v" uses the "enum { a, b, c, d }" + * tag. + */ + } a[10]; +} + +4.2.3 Arrays Arrays are fixed-length. Their length is declared in the type declaration within the metadata. They contain an array of "inner type" elements, which can refer to @@ -352,7 +473,7 @@ A nameless array can be declared as a field type within a structure, e.g.: uint8_t field_name[10]; -4.2.3 Sequences +4.2.4 Sequences Sequences are dynamically-sized arrays. They start with an integer that specify the length of the sequence, followed by an array of "inner type" elements. @@ -369,7 +490,7 @@ long field_name[int]; The length type follows the integer types specifications, and the sequence elements follow the "array" specifications. -4.2.4 Strings +4.2.5 Strings Strings are an array of bytes of variable size and are terminated by a '\0' "NULL" character. Their encoding is described in the metadata. In absence of @@ -377,9 +498,9 @@ encoding attribute information, the default encoding is UTF-8. Metadata representation of a named string type: -typedef string { +typealias string { encoding = UTF8 OR ASCII; -} name; +} : name; A nameless string type can be declared as a field type: @@ -476,21 +597,31 @@ struct event_packet_context { uint8_t stream_packet_count_bits; /* Significant counter bits */ uint8_t compression_scheme; uint8_t encryption_scheme; - uint8_t checksum; + uint8_t checksum_scheme; }; + 6. Event Structure The overall structure of an event is: - - Event Header (as specifed by the stream metadata) - - Extended Event Header (as specified by the event header) - - Event Context (as specified by the stream metadata) - - Event Payload (as specified by the event metadata) +1 - Stream Packet Context (as specified by the stream metadata) + 2 - Event Header (as specified by the stream metadata) + 3 - Stream Event Context (as specified by the stream metadata) + 4 - Event Context (as specified by the event metadata) + 5 - Event Payload (as specified by the event metadata) +This structure defines an implicit dynamic scoping, where variants +located in inner structures (those with a higher number in the listing +above) can refer to the fields of outer structures (with lower number in +the listing above). See Section 7.2 Metadata Scopes for more detail. 6.1 Event Header +Event headers can be described within the metadata. We hereby propose, as an +example, two types of events headers. Type 1 accommodates streams with less than +31 event IDs. Type 2 accommodates streams with 31 or more event IDs. + One major factor can vary between streams: the number of event IDs assigned to a stream. Luckily, this information tends to stay relatively constant (modulo event registration while trace is being recorded), so we can specify different @@ -498,12 +629,8 @@ representations for streams containing few event IDs and streams containing many event IDs, so we end up representing the event ID and timestamp as densely as possible in each case. -We therefore provide two types of events headers. Type 1 accommodates streams -with less than 31 event IDs. Type 2 accommodates streams with 31 or more event -IDs. - -The "extended headers" are used in the rare occasions where the information -cannot be represented in the ranges available in the event header. They are also +The header is extended in the rare occasions where the information cannot be +represented in the ranges available in the standard event header. They are also used in the rare occasions where the data required for a field could not be collected: the flag corresponding to the missing field within the missing_fields array is then set to 1. @@ -515,89 +642,98 @@ Types uintX_t represent an X-bit unsigned integer. - Aligned on 32-bit (or 8-bit if byte-packed, depending on the architecture preference). - - Fixed size: 32 bits. - Native architecture byte ordering. + - For "compact" selection + - Fixed size: 32 bits. + - For "extended" selection + - Size depends on the architecture and variant alignment. struct event_header_1 { - uint5_t id; /* - * id: range: 0 - 30. - * id 31 is reserved to indicate a following - * extended header. - */ - uint27_t timestamp; + /* + * id: range: 0 - 30. + * id 31 is reserved to indicate an extended header. + */ + enum { compact = 0 ... 30, extended = 31 } id; + variant { + struct { + uint27_t timestamp; + } compact; + struct { + uint32_t id; /* 32-bit event IDs */ + uint64_t timestamp; /* 64-bit timestamps */ + } extended; + } v; }; -The end of a type 1 header is aligned on a 32-bit boundary (or packed). - - -6.1.2 Extended Type 1 Event Header - - Follows struct event_header_1, which is aligned on 32-bit, so no need to - realign. - - Variable size (depends on the number of fields per event). - - Native architecture byte ordering. - - NR_FIELDS is the number of fields within the event. - -struct event_header_1_ext { - uint32_t id; /* 32-bit event IDs */ - uint64_t timestamp; /* 64-bit timestamps */ - uint1_t missing_fields[NR_FIELDS]; /* missing event fields bitmap */ -}; +6.1.2 Type 2 - Many event IDs - -6.1.3 Type 2 - Many event IDs - - - Aligned on 32-bit (or 8-bit if byte-packed, depending on the architecture + - Aligned on 16-bit (or 8-bit if byte-packed, depending on the architecture preference). - - Fixed size: 48 bits. - Native architecture byte ordering. + - For "compact" selection + - Size depends on the architecture and variant alignment. + - For "extended" selection + - Size depends on the architecture and variant alignment. struct event_header_2 { - uint32_t timestamp; - uint16_t id; /* - * id: range: 0 - 65534. - * id 65535 is reserved to indicate a following - * extended header. - */ -}; - -The end of a type 2 header is aligned on a 16-bit boundary (or 8-bit if -byte-packed). - - -6.1.4 Extended Type 2 Event Header - - - Follows struct event_header_2, which alignment end on a 16-bit boundary, so - we need to align on 64-bit integer architecture alignment (or 8-bit if - byte-packed). - - Variable size (depends on the number of fields per event). - - Native architecture byte ordering. - - NR_FIELDS is the number of fields within the event. - -struct event_header_2_ext { - uint64_t timestamp; /* 64-bit timestamps */ - uint32_t id; /* 32-bit event IDs */ - uint1_t missing_fields[NR_FIELDS]; /* missing event fields bitmap */ + /* + * id: range: 0 - 65534. + * id 65535 is reserved to indicate an extended header. + */ + enum { compact = 0 ... 65534, extended = 65535 } id; + variant { + struct { + uint32_t timestamp; + } compact; + struct { + uint32_t id; /* 32-bit event IDs */ + uint64_t timestamp; /* 64-bit timestamps */ + } extended; + } v; }; 6.2 Event Context The event context contains information relative to the current event. The choice -and meaning of this information is specified by the metadata "stream" -information. For this trace format, event context is usually empty, except when -the metadata "stream" information specifies otherwise by declaring a non-empty -structure for the event context. An example of event context is to save the -event payload size with each event, or to save the current PID with each event. -These are declared within the stream declaration within the metadata. +and meaning of this information is specified by the metadata "stream" and +"event" information. The "stream" context is applied to all events within the +stream. The "stream" context structure follows the event header. The "event" +context is applied to specific events. Its structure follows the "stream" +context stucture. -An example event context type: +An example of stream-level event context is to save the event payload size with +each event, or to save the current PID with each event. These are declared +within the stream declaration within the metadata: - struct event_context { + stream { + ... + event { + ... + context := struct { uint pid; uint16_t payload_size; }; + } + }; +An example of event-specific event context is to declare a bitmap of missing +fields, only appended after the stream event context if the extended event +header is selected. NR_FIELDS is the number of fields within the event (a +numeric value). + + event { + context = struct { + variant { + struct { } compact; + struct { + uint1_t missing_fields[NR_FIELDS]; /* missing event fields bitmap */ + } extended; + } v; + }; + ... + } 6.3 Event Payload @@ -623,7 +759,6 @@ The event payload is aligned on the largest alignment required by types contained within the payload. (This follows the ISO/C standard for structures) - 7. Metadata The meta-data is located in a stream named "metadata". It is made of "event @@ -632,36 +767,111 @@ the metadata stream have no event header nor event context. Each event only contains a null-terminated "string" payload, which is a metadata description entry. The events are packed one next to another. Each event packet start with an event packet header, which contains, amongst other fields, the magic number -and trace UUID. +and trace UUID. The trace UUID is represented as a string of hexadecimal digits +and dashes "-". The metadata can be parsed by reading through the metadata strings, skipping -newlines and null-characters. Type names may contain spaces. +newlines and null-characters. Type names are made of a single identifier, and +can be surrounded by prefix/postfix. Text contained within "/*" and "*/", as +well as within "//" and end of line, are treated as comments. Boolean values can +be represented as true, TRUE, or 1 for true, and false, FALSE, or 0 for false. + + +7.1 Declaration vs Definition + +A declaration associates a layout to a type, without specifying where +this type is located in the event structure hierarchy (see Section 6). +This therefore includes typedef, typealias, as well as all type +specifiers. In certain circumstances (typedef, structure field and +variant field), a declaration is followed by a declarator, which specify +the newly defined type name (for typedef), or the field name (for +declarations located within structure and variants). Array and sequence, +declared with square brackets ("[" "]"), are part of the declarator, +similarly to C99. The enumeration type specifier and variant tag name +(both specified with "<" ">") are part of the type specifier. + +A definition associates a type to a location in the event structure +hierarchy (see Section 6). This association is denoted by ":=", as shown +in Section 7.3. + + +7.2 Metadata Scopes + +CTF metadata uses two different types of scoping: a lexical scope is +used for declarations and type definitions, and a dynamic scope is used +for variants references to tag fields. + +7.2.1 Lexical Scope + +Each of "trace", "stream", "event", "struct" and "variant" have their own +nestable declaration scope, within which types can be declared using "typedef" +and "typealias". A root declaration scope also contains all declarations +located outside of any of the aforementioned declarations. An inner +declaration scope can refer to type declared within its container +lexical scope prior to the inner declaration scope. Redefinition of a +typedef or typealias is not valid, although hiding an upper scope +typedef or typealias is allowed within a sub-scope. + +7.2.2 Dynamic Scope + +A dynamic scope consists in the lexical scope augmented with the +implicit event structure definition hierarchy presented at Section 6. +The dynamic scope is only used for variant tag definitions. It is used +at definition time to look up the location of the tag field associated +with a variant. + +Therefore, variants in lower levels in the dynamic scope (e.g. event +context) can refer to a tag field located in upper levels (e.g. in the +event header) by specifying, in this case, the associated tag with +. This allows, for instance, the event context to +define a variant referring to the "id" field of the event header as +selector. + +The target dynamic scope must be specified explicitly when referring to +a field outside of the local static scope. The dynamic scope prefixes +are thus: + + - Stream Packet Context: , + - Event Header: , + - Stream Event Context: , + - Event Context: , + - Event Payload: . + +Multiple declarations of the same field name within a single scope is +not valid. It is however valid to re-use the same field name in +different scopes. There is no possible conflict, because the dynamic +scope must be specified when a variant refers to a tag field located in +a different dynamic scope. + +The information available in the dynamic scopes can be thought of as the +current tracing context. At trace production, information about the +current context is saved into the specified scope field levels. At trace +consumption, for each event, the current trace context is therefore +readable by accessing the upper dynamic scopes. + + +7.3 Metadata Examples + +The grammar representing the CTF metadata is presented in +Appendix C. CTF Metadata Grammar. This section presents a rather ligher +reading that consists in examples of CTF metadata, with template values: trace { - major = value; /* Trace format version */ + major = value; /* Trace format version */ minor = value; - uuid = value; /* Trace UUID */ + uuid = "aaaaaaaa-aaaa-aaaa-aaaa-aaaaaaaaaaaa"; /* Trace UUID */ word_size = value; }; stream { id = stream_id; - event { - /* Type 1 - Few event IDs; Type 2 - Many event IDs. See section 6.1. */ - header_type = event_header_1 OR event_header_2; - /* - * Extended event header type. Only present if specified in event header - * on a per-event basis. - */ - header_type_ext = event_header_1_ext OR event_header_2_ext; - context_type = struct { - ... - }; + /* Type 1 - Few event IDs; Type 2 - Many event IDs. See section 6.1. */ + event.header := event_header_1 OR event_header_2; + event.context := struct { + ... }; - packet { - context_type = struct { - ... - }; + packet.context := struct { + ... }; }; @@ -669,7 +879,10 @@ event { name = event_name; id = value; /* Numeric identifier within the stream */ stream = stream_id; - fields = struct { + context := struct { + ... + }; + fields := struct { ... }; }; @@ -679,44 +892,68 @@ event { /* * Named types: * - * A named type can only have a prefix and postfix if it aliases a CTF basic - * type. A type name aliasing another type name cannot have prefix nor postfix, - * but the type aliased can have a prefix and/or postfix. + * Type declarations behave similarly to the C standard. */ typedef aliased_type_prefix aliased_type new_type aliased_type_postfix; /* e.g.: typedef struct example new_type_name[10]; */ -typedef type_class { +/* + * typealias + * + * The "typealias" declaration can be used to give a name (including + * prefix/postfix) to a type. It should also be used to map basic C types + * (float, int, unsigned long, ...) to a CTF type. Typealias is a superset of + * "typedef": it also allows assignment of a simple variable identifier to a + * type. + */ + +typealias type_class { ... -} new_type_prefix new_type new_type_postfix; +} : new_type_prefix new_type new_type_postfix; /* * e.g.: - * typedef integer { + * typealias integer { * size = 32; * align = 32; * signed = false; - * } struct page *; + * } : struct page *; + * + * typealias integer { + * size = 32; + * align = 32; + * signed = true; + * } : int; */ struct name { ... }; -enum name { +variant name { ... }; +enum name { + ... +}; -/* Unnamed types, contained within compound type fields or typedef. */ + +/* + * Unnamed types, contained within compound type fields, typedef or typealias. + */ struct { ... } -enum { +variant { + ... +} + +enum { ... } @@ -748,6 +985,7 @@ struct { string field_name; } + A. Helper macros The two following macros keep track of the size of a GNU/C structure without @@ -786,3 +1024,383 @@ flexibility in terms of: The event stream header will therefore be referred to as the "event packet header" throughout the rest of this document. + +C. CTF Metadata Grammar + +/* + * Common Trace Format (CTF) Metadata Grammar. + * + * Inspired from the C99 grammar: + * http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1124.pdf (Annex A) + * + * Specialized for CTF needs by including only constant and declarations from + * C99 (excluding function declarations), and by adding support for variants, + * sequences and CTF-specific specifiers. + */ + +1) Lexical grammar + +1.1) Lexical elements + +token: + keyword + identifier + constant + string-literal + punctuator + +1.2) Keywords + +keyword: is one of + +const +char +double +enum +event +floating_point +float +integer +int +long +short +signed +stream +string +struct +trace +typealias +typedef +unsigned +variant +void +_Bool +_Complex +_Imaginary + + +1.3) Identifiers + +identifier: + identifier-nondigit + identifier identifier-nondigit + identifier digit + +identifier-nondigit: + nondigit + universal-character-name + any other implementation-defined characters + +nondigit: + _ + [a-zA-Z] /* regular expression */ + +digit: + [0-9] /* regular expression */ + +1.4) Universal character names + +universal-character-name: + \u hex-quad + \U hex-quad hex-quad + +hex-quad: + hexadecimal-digit hexadecimal-digit hexadecimal-digit hexadecimal-digit + +1.5) Constants + +constant: + integer-constant + enumeration-constant + character-constant + +integer-constant: + decimal-constant integer-suffix-opt + octal-constant integer-suffix-opt + hexadecimal-constant integer-suffix-opt + +decimal-constant: + nonzero-digit + decimal-constant digit + +octal-constant: + 0 + octal-constant octal-digit + +hexadecimal-constant: + hexadecimal-prefix hexadecimal-digit + hexadecimal-constant hexadecimal-digit + +hexadecimal-prefix: + 0x + 0X + +nonzero-digit: + [1-9] + +integer-suffix: + unsigned-suffix long-suffix-opt + unsigned-suffix long-long-suffix + long-suffix unsigned-suffix-opt + long-long-suffix unsigned-suffix-opt + +unsigned-suffix: + u + U + +long-suffix: + l + L + +long-long-suffix: + ll + LL + +digit-sequence: + digit + digit-sequence digit + +hexadecimal-digit-sequence: + hexadecimal-digit + hexadecimal-digit-sequence hexadecimal-digit + +enumeration-constant: + identifier + string-literal + +character-constant: + ' c-char-sequence ' + L' c-char-sequence ' + +c-char-sequence: + c-char + c-char-sequence c-char + +c-char: + any member of source charset except single-quote ('), backslash + (\), or new-line character. + escape-sequence + +escape-sequence: + simple-escape-sequence + octal-escape-sequence + hexadecimal-escape-sequence + universal-character-name + +simple-escape-sequence: one of + \' \" \? \\ \a \b \f \n \r \t \v + +octal-escape-sequence: + \ octal-digit + \ octal-digit octal-digit + \ octal-digit octal-digit octal-digit + +hexadecimal-escape-sequence: + \x hexadecimal-digit + hexadecimal-escape-sequence hexadecimal-digit + +1.6) String literals + +string-literal: + " s-char-sequence-opt " + L" s-char-sequence-opt " + +s-char-sequence: + s-char + s-char-sequence s-char + +s-char: + any member of source charset except double-quote ("), backslash + (\), or new-line character. + escape-sequence + +1.7) Punctuators + +punctuator: one of + [ ] ( ) { } . -> * + - < > : ; ... = , + + +2) Phrase structure grammar + +primary-expression: + identifier + constant + string-literal + ( unary-expression ) + +postfix-expression: + primary-expression + postfix-expression [ unary-expression ] + postfix-expression . identifier + postfix-expressoin -> identifier + +unary-expression: + postfix-expression + unary-operator postfix-expression + +unary-operator: one of + + - + +assignment-operator: + = + +type-assignment-operator: + := + +constant-expression: + unary-expression + +constant-expression-range: + constant-expression ... constant-expression + +2.2) Declarations: + +declaration: + declaration-specifiers ; + declaration-specifiers storage-class-specifier declaration-specifiers declarator-list ; + ctf-specifier ; + +declaration-specifiers: + type-specifier declaration-specifiers-opt + type-qualifier declaration-specifiers-opt + +declarator-list: + declarator + declarator-list , declarator + +abstract-declarator-list: + abstract-declarator + abstract-declarator-list , abstract-declarator + +storage-class-specifier: + typedef + +type-specifier: + void + char + short + int + long + float + double + signed + unsigned + _Bool + _Complex + _Imaginary + struct-specifier + variant-specifier + enum-specifier + typedef-name + ctf-type-specifier + +struct-specifier: + struct identifier-opt { struct-or-variant-declaration-list-opt } + struct identifier + +struct-or-variant-declaration-list: + struct-or-variant-declaration + struct-or-variant-declaration-list struct-or-variant-declaration + +struct-or-variant-declaration: + specifier-qualifier-list struct-or-variant-declarator-list ; + declaration-specifiers storage-class-specifier declaration-specifiers declarator-list ; + typealias declaration-specifiers abstract-declarator-list : declaration-specifiers abstract-declarator-list ; + typealias declaration-specifiers abstract-declarator-list : declarator-list ; + +specifier-qualifier-list: + type-specifier specifier-qualifier-list-opt + type-qualifier specifier-qualifier-list-opt + +struct-or-variant-declarator-list: + struct-or-variant-declarator + struct-or-variant-declarator-list , struct-or-variant-declarator + +struct-or-variant-declarator: + declarator + declarator-opt : constant-expression + +variant-specifier: + variant identifier-opt variant-tag-opt { struct-or-variant-declaration-list } + variant identifier variant-tag + +variant-tag: + < identifier > + +enum-specifier: + enum identifier-opt { enumerator-list } + enum identifier-opt { enumerator-list , } + enum identifier + enum identifier-opt < declaration-specifiers > { enumerator-list } + enum identifier-opt < declaration-specifiers > { enumerator-list , } + enum identifier < declaration-specifiers > + enum identifier-opt < integer-constant > { enumerator-list } + enum identifier-opt < integer-constant > { enumerator-list , } + enum identifier < integer-constant > + +enumerator-list: + enumerator + enumerator-list , enumerator + +enumerator: + enumeration-constant + enumeration-constant = constant-expression + enumeration-constant = constant-expression-range + +type-qualifier: + const + +declarator: + pointer-opt direct-declarator + +direct-declarator: + identifier + ( declarator ) + direct-declarator [ type-specifier ] + direct-declarator [ constant-expression ] + +abstract-declarator: + pointer-opt direct-abstract-declarator + +direct-abstract-declarator: + identifier-opt + ( abstract-declarator ) + direct-abstract-declarator [ type-specifier ] + direct-abstract-declarator [ constant-expression ] + direct-abstract-declarator [ ] + +pointer: + * type-qualifier-list-opt + * type-qualifier-list-opt pointer + +type-qualifier-list: + type-qualifier + type-qualifier-list type-qualifier + +typedef-name: + identifier + +2.3) CTF-specific declarations + +ctf-specifier: + event { ctf-assignment-expression-list-opt } + stream { ctf-assignment-expression-list-opt } + trace { ctf-assignment-expression-list-opt } + typealias declaration-specifiers abstract-declarator-list : declaration-specifiers abstract-declarator-list ; + typealias declaration-specifiers abstract-declarator-list : declarator-list ; + +ctf-type-specifier: + floating_point { ctf-assignment-expression-list-opt } + integer { ctf-assignment-expression-list-opt } + string { ctf-assignment-expression-list-opt } + +ctf-assignment-expression-list: + ctf-assignment-expression + ctf-assignment-expression-list ; ctf-assignment-expression + +ctf-assignment-expression: + unary-expression assignment-operator unary-expression + unary-expression type-assignment-operator type-specifier + declaration-specifiers storage-class-specifier declaration-specifiers declarator-list + typealias declaration-specifiers abstract-declarator-list : declaration-specifiers abstract-declarator-list + typealias declaration-specifiers abstract-declarator-list : declarator-list