1 /* Simplified ASN.1 notation parser
3 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
6 * This program is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU General Public Licence
8 * as published by the Free Software Foundation; either version
9 * 2 of the Licence, or (at your option) any later version.
21 #include <linux/asn1_ber_bytecode.h>
27 DIRECTIVE_APPLICATION
,
39 DIRECTIVE_CONSTRAINED
,
43 DIRECTIVE_DEFINITIONS
,
46 DIRECTIVE_ENCODING_CONTROL
,
52 DIRECTIVE_EXTENSIBILITY
,
56 DIRECTIVE_GeneralString
,
57 DIRECTIVE_GeneralizedTime
,
58 DIRECTIVE_GraphicString
,
66 DIRECTIVE_INSTRUCTIONS
,
68 DIRECTIVE_INTERSECTION
,
69 DIRECTIVE_ISO646String
,
72 DIRECTIVE_MINUS_INFINITY
,
74 DIRECTIVE_NumericString
,
79 DIRECTIVE_ObjectDescriptor
,
82 DIRECTIVE_PLUS_INFINITY
,
85 DIRECTIVE_PrintableString
,
87 DIRECTIVE_RELATIVE_OID
,
96 DIRECTIVE_TeletexString
,
101 DIRECTIVE_UTF8String
,
102 DIRECTIVE_UniversalString
,
103 DIRECTIVE_VideotexString
,
104 DIRECTIVE_VisibleString
,
107 TOKEN_ASSIGNMENT
= NR__DIRECTIVES
,
121 static const unsigned char token_to_tag
[NR__TOKENS
] = {
123 [DIRECTIVE_BOOLEAN
] = ASN1_BOOL
,
124 [DIRECTIVE_INTEGER
] = ASN1_INT
,
125 [DIRECTIVE_BIT
] = ASN1_BTS
,
126 [DIRECTIVE_OCTET
] = ASN1_OTS
,
127 [DIRECTIVE_NULL
] = ASN1_NULL
,
128 [DIRECTIVE_OBJECT
] = ASN1_OID
,
129 [DIRECTIVE_ObjectDescriptor
] = ASN1_ODE
,
130 [DIRECTIVE_EXTERNAL
] = ASN1_EXT
,
131 [DIRECTIVE_REAL
] = ASN1_REAL
,
132 [DIRECTIVE_ENUMERATED
] = ASN1_ENUM
,
133 [DIRECTIVE_EMBEDDED
] = 0,
134 [DIRECTIVE_UTF8String
] = ASN1_UTF8STR
,
135 [DIRECTIVE_RELATIVE_OID
] = ASN1_RELOID
,
138 [DIRECTIVE_SEQUENCE
] = ASN1_SEQ
,
139 [DIRECTIVE_SET
] = ASN1_SET
,
140 [DIRECTIVE_NumericString
] = ASN1_NUMSTR
,
141 [DIRECTIVE_PrintableString
] = ASN1_PRNSTR
,
142 [DIRECTIVE_T61String
] = ASN1_TEXSTR
,
143 [DIRECTIVE_TeletexString
] = ASN1_TEXSTR
,
144 [DIRECTIVE_VideotexString
] = ASN1_VIDSTR
,
145 [DIRECTIVE_IA5String
] = ASN1_IA5STR
,
146 [DIRECTIVE_UTCTime
] = ASN1_UNITIM
,
147 [DIRECTIVE_GeneralizedTime
] = ASN1_GENTIM
,
148 [DIRECTIVE_GraphicString
] = ASN1_GRASTR
,
149 [DIRECTIVE_VisibleString
] = ASN1_VISSTR
,
150 [DIRECTIVE_GeneralString
] = ASN1_GENSTR
,
151 [DIRECTIVE_UniversalString
] = ASN1_UNITIM
,
152 [DIRECTIVE_CHARACTER
] = ASN1_CHRSTR
,
153 [DIRECTIVE_BMPString
] = ASN1_BMPSTR
,
156 static const char asn1_classes
[4][5] = {
157 [ASN1_UNIV
] = "UNIV",
158 [ASN1_APPL
] = "APPL",
159 [ASN1_CONT
] = "CONT",
163 static const char asn1_methods
[2][5] = {
164 [ASN1_UNIV
] = "PRIM",
168 static const char *const asn1_universal_tags
[32] = {
203 static const char *filename
;
204 static const char *grammar_name
;
205 static const char *outputname
;
206 static const char *headername
;
208 static const char *const directives
[NR__DIRECTIVES
] = {
209 #define _(X) [DIRECTIVE_##X] = #X
232 [DIRECTIVE_ENCODING_CONTROL
] = "ENCODING-CONTROL",
258 [DIRECTIVE_MINUS_INFINITY
] = "MINUS-INFINITY",
259 [DIRECTIVE_NULL
] = "NULL",
268 [DIRECTIVE_PLUS_INFINITY
] = "PLUS-INFINITY",
273 [DIRECTIVE_RELATIVE_OID
] = "RELATIVE-OID",
300 static struct action
*action_list
;
301 static unsigned nr_actions
;
305 enum token_type token_type
: 8;
307 struct action
*action
;
312 static struct token
*token_list
;
313 static unsigned nr_tokens
;
314 static _Bool verbose
;
316 #define debug(fmt, ...) do { if (verbose) printf(fmt, ## __VA_ARGS__); } while (0)
318 static int directive_compare(const void *_key
, const void *_pdir
)
320 const struct token
*token
= _key
;
321 const char *const *pdir
= _pdir
, *dir
= *pdir
;
326 clen
= (dlen
< token
->size
) ? dlen
: token
->size
;
328 //debug("cmp(%*.*s,%s) = ",
329 // (int)token->size, (int)token->size, token->value,
332 val
= memcmp(token
->value
, dir
, clen
);
334 //debug("%d [cmp]\n", val);
338 if (dlen
== token
->size
) {
342 //debug("%d\n", (int)dlen - (int)token->size);
343 return dlen
- token
->size
; /* shorter -> negative */
347 * Tokenise an ASN.1 grammar
349 static void tokenise(char *buffer
, char *end
)
351 struct token
*tokens
;
352 char *line
, *nl
, *p
, *q
;
353 unsigned tix
, lineno
;
355 /* Assume we're going to have half as many tokens as we have
358 token_list
= tokens
= calloc((end
- buffer
) / 2, sizeof(struct token
));
366 while (buffer
< end
) {
367 /* First of all, break out a line */
370 nl
= memchr(line
, '\n', end
- buffer
);
378 /* Remove "--" comments */
381 while ((p
= memchr(p
, '-', nl
- p
))) {
383 /* Found a comment; see if there's a terminator */
385 while ((q
= memchr(q
, '-', nl
- q
))) {
387 /* There is - excise the comment */
389 memmove(p
, q
, nl
- q
);
404 /* Skip white space */
405 while (p
< nl
&& isspace(*p
))
410 tokens
[tix
].line
= lineno
;
411 tokens
[tix
].value
= p
;
413 /* Handle string tokens */
417 /* Can be a directive, type name or element
418 * name. Find the end of the name.
421 while (q
< nl
&& (isalnum(*q
) || *q
== '-' || *q
== '_'))
423 tokens
[tix
].size
= q
- p
;
426 /* If it begins with a lowercase letter then
427 * it's an element name
429 if (islower(tokens
[tix
].value
[0])) {
430 tokens
[tix
++].token_type
= TOKEN_ELEMENT_NAME
;
434 /* Otherwise we need to search the directive
437 dir
= bsearch(&tokens
[tix
], directives
,
438 sizeof(directives
) / sizeof(directives
[1]),
439 sizeof(directives
[1]),
442 tokens
[tix
++].token_type
= dir
- directives
;
446 tokens
[tix
++].token_type
= TOKEN_TYPE_NAME
;
452 /* Find the end of the number */
454 while (q
< nl
&& (isdigit(*q
)))
456 tokens
[tix
].size
= q
- p
;
458 tokens
[tix
++].token_type
= TOKEN_NUMBER
;
463 if (memcmp(p
, "::=", 3) == 0) {
465 tokens
[tix
].size
= 3;
466 tokens
[tix
++].token_type
= TOKEN_ASSIGNMENT
;
472 if (memcmp(p
, "({", 2) == 0) {
474 tokens
[tix
].size
= 2;
475 tokens
[tix
++].token_type
= TOKEN_OPEN_ACTION
;
478 if (memcmp(p
, "})", 2) == 0) {
480 tokens
[tix
].size
= 2;
481 tokens
[tix
++].token_type
= TOKEN_CLOSE_ACTION
;
487 tokens
[tix
].size
= 1;
491 tokens
[tix
++].token_type
= TOKEN_OPEN_CURLY
;
495 tokens
[tix
++].token_type
= TOKEN_CLOSE_CURLY
;
499 tokens
[tix
++].token_type
= TOKEN_OPEN_SQUARE
;
503 tokens
[tix
++].token_type
= TOKEN_CLOSE_SQUARE
;
507 tokens
[tix
++].token_type
= TOKEN_COMMA
;
514 fprintf(stderr
, "%s:%u: Unknown character in grammar: '%c'\n",
515 filename
, lineno
, *p
);
521 debug("Extracted %u tokens\n", nr_tokens
);
526 for (n
= 0; n
< nr_tokens
; n
++)
527 debug("Token %3u: '%*.*s'\n",
529 (int)token_list
[n
].size
, (int)token_list
[n
].size
,
530 token_list
[n
].value
);
535 static void build_type_list(void);
536 static void parse(void);
537 static void render(FILE *out
, FILE *hdr
);
542 int main(int argc
, char **argv
)
548 char *kbuild_verbose
;
552 fprintf(stderr
, "Format: %s <grammar-file> <c-file> <hdr-file>\n",
557 kbuild_verbose
= getenv("KBUILD_VERBOSE");
559 verbose
= atoi(kbuild_verbose
);
562 outputname
= argv
[2];
563 headername
= argv
[3];
565 fd
= open(filename
, O_RDONLY
);
571 if (fstat(fd
, &st
) < 0) {
576 if (!(buffer
= malloc(st
.st_size
+ 1))) {
581 if ((readlen
= read(fd
, buffer
, st
.st_size
)) < 0) {
591 if (readlen
!= st
.st_size
) {
592 fprintf(stderr
, "%s: Short read\n", filename
);
596 p
= strrchr(argv
[1], '/');
597 p
= p
? p
+ 1 : argv
[1];
598 grammar_name
= strdup(p
);
603 p
= strchr(grammar_name
, '.');
608 tokenise(buffer
, buffer
+ readlen
);
612 out
= fopen(outputname
, "w");
618 hdr
= fopen(headername
, "w");
626 if (fclose(out
) < 0) {
631 if (fclose(hdr
) < 0) {
652 struct type
*type_def
;
655 struct action
*action
;
656 struct element
*children
;
657 struct element
*next
;
658 struct element
*render_next
;
659 struct element
*list_next
;
661 enum compound compound
: 8;
662 enum asn1_class
class : 8;
663 enum asn1_method method
: 8;
665 unsigned entry_index
;
667 #define ELEMENT_IMPLICIT 0x0001
668 #define ELEMENT_EXPLICIT 0x0002
669 #define ELEMENT_MARKED 0x0004
670 #define ELEMENT_RENDERED 0x0008
671 #define ELEMENT_SKIPPABLE 0x0010
672 #define ELEMENT_CONDITIONAL 0x0020
678 struct element
*element
;
681 #define TYPE_STOP_MARKER 0x0001
682 #define TYPE_BEGIN 0x0002
685 static struct type
*type_list
;
686 static struct type
**type_index
;
687 static unsigned nr_types
;
689 static int type_index_compare(const void *_a
, const void *_b
)
691 const struct type
*const *a
= _a
, *const *b
= _b
;
693 if ((*a
)->name
->size
!= (*b
)->name
->size
)
694 return (*a
)->name
->size
- (*b
)->name
->size
;
696 return memcmp((*a
)->name
->value
, (*b
)->name
->value
,
700 static int type_finder(const void *_key
, const void *_ti
)
702 const struct token
*token
= _key
;
703 const struct type
*const *ti
= _ti
;
704 const struct type
*type
= *ti
;
706 if (token
->size
!= type
->name
->size
)
707 return token
->size
- type
->name
->size
;
709 return memcmp(token
->value
, type
->name
->value
,
714 * Build up a list of types and a sorted index to that list.
716 static void build_type_list(void)
722 for (n
= 0; n
< nr_tokens
- 1; n
++)
723 if (token_list
[n
+ 0].token_type
== TOKEN_TYPE_NAME
&&
724 token_list
[n
+ 1].token_type
== TOKEN_ASSIGNMENT
)
728 fprintf(stderr
, "%s: No defined types\n", filename
);
733 types
= type_list
= calloc(nr
+ 1, sizeof(type_list
[0]));
738 type_index
= calloc(nr
, sizeof(type_index
[0]));
745 types
[t
].flags
|= TYPE_BEGIN
;
746 for (n
= 0; n
< nr_tokens
- 1; n
++) {
747 if (token_list
[n
+ 0].token_type
== TOKEN_TYPE_NAME
&&
748 token_list
[n
+ 1].token_type
== TOKEN_ASSIGNMENT
) {
749 types
[t
].name
= &token_list
[n
];
750 type_index
[t
] = &types
[t
];
754 types
[t
].name
= &token_list
[n
+ 1];
755 types
[t
].flags
|= TYPE_STOP_MARKER
;
757 qsort(type_index
, nr
, sizeof(type_index
[0]), type_index_compare
);
759 debug("Extracted %u types\n", nr_types
);
761 for (n
= 0; n
< nr_types
; n
++) {
762 struct type
*type
= type_index
[n
];
764 (int)type
->name
->size
,
765 (int)type
->name
->size
,
771 static struct element
*parse_type(struct token
**_cursor
, struct token
*stop
,
775 * Parse the token stream
777 static void parse(void)
779 struct token
*cursor
;
782 /* Parse one type definition statement at a time */
787 if (cursor
[0].token_type
!= TOKEN_TYPE_NAME
||
788 cursor
[1].token_type
!= TOKEN_ASSIGNMENT
)
792 type
->element
= parse_type(&cursor
, type
[1].name
, NULL
);
793 type
->element
->type_def
= type
;
795 if (cursor
!= type
[1].name
) {
796 fprintf(stderr
, "%s:%d: Parse error at token '%*.*s'\n",
797 filename
, cursor
->line
,
798 (int)cursor
->size
, (int)cursor
->size
, cursor
->value
);
802 } while (type
++, !(type
->flags
& TYPE_STOP_MARKER
));
804 debug("Extracted %u actions\n", nr_actions
);
807 static struct element
*element_list
;
809 static struct element
*alloc_elem(struct token
*type
)
811 struct element
*e
= calloc(1, sizeof(*e
));
816 e
->list_next
= element_list
;
821 static struct element
*parse_compound(struct token
**_cursor
, struct token
*end
,
825 * Parse one type definition statement
827 static struct element
*parse_type(struct token
**_cursor
, struct token
*end
,
830 struct element
*top
, *element
;
831 struct action
*action
, **ppaction
;
832 struct token
*cursor
= *_cursor
;
835 int labelled
= 0, implicit
= 0;
837 top
= element
= alloc_elem(cursor
);
838 element
->class = ASN1_UNIV
;
839 element
->method
= ASN1_PRIM
;
840 element
->tag
= token_to_tag
[cursor
->token_type
];
841 element
->name
= name
;
843 /* Extract the tag value if one given */
844 if (cursor
->token_type
== TOKEN_OPEN_SQUARE
) {
848 switch (cursor
->token_type
) {
849 case DIRECTIVE_UNIVERSAL
:
850 element
->class = ASN1_UNIV
;
853 case DIRECTIVE_APPLICATION
:
854 element
->class = ASN1_APPL
;
858 element
->class = ASN1_CONT
;
860 case DIRECTIVE_PRIVATE
:
861 element
->class = ASN1_PRIV
;
865 fprintf(stderr
, "%s:%d: Unrecognised tag class token '%*.*s'\n",
866 filename
, cursor
->line
,
867 (int)cursor
->size
, (int)cursor
->size
, cursor
->value
);
873 if (cursor
->token_type
!= TOKEN_NUMBER
) {
874 fprintf(stderr
, "%s:%d: Missing tag number '%*.*s'\n",
875 filename
, cursor
->line
,
876 (int)cursor
->size
, (int)cursor
->size
, cursor
->value
);
880 element
->tag
&= ~0x1f;
881 element
->tag
|= strtoul(cursor
->value
, &p
, 10);
882 if (p
- cursor
->value
!= cursor
->size
)
888 if (cursor
->token_type
!= TOKEN_CLOSE_SQUARE
) {
889 fprintf(stderr
, "%s:%d: Missing closing square bracket '%*.*s'\n",
890 filename
, cursor
->line
,
891 (int)cursor
->size
, (int)cursor
->size
, cursor
->value
);
900 /* Handle implicit and explicit markers */
901 if (cursor
->token_type
== DIRECTIVE_IMPLICIT
) {
902 element
->flags
|= ELEMENT_IMPLICIT
;
907 } else if (cursor
->token_type
== DIRECTIVE_EXPLICIT
) {
908 element
->flags
|= ELEMENT_EXPLICIT
;
916 element
->method
|= ASN1_CONS
;
917 element
->compound
= implicit
? TAG_OVERRIDE
: SEQUENCE
;
918 element
->children
= alloc_elem(cursor
);
919 element
= element
->children
;
920 element
->class = ASN1_UNIV
;
921 element
->method
= ASN1_PRIM
;
922 element
->tag
= token_to_tag
[cursor
->token_type
];
923 element
->name
= name
;
926 /* Extract the type we're expecting here */
927 element
->type
= cursor
;
928 switch (cursor
->token_type
) {
930 element
->compound
= ANY
;
935 case DIRECTIVE_BOOLEAN
:
936 case DIRECTIVE_ENUMERATED
:
937 case DIRECTIVE_INTEGER
:
938 element
->compound
= NOT_COMPOUND
;
942 case DIRECTIVE_EXTERNAL
:
943 element
->method
= ASN1_CONS
;
945 case DIRECTIVE_BMPString
:
946 case DIRECTIVE_GeneralString
:
947 case DIRECTIVE_GraphicString
:
948 case DIRECTIVE_IA5String
:
949 case DIRECTIVE_ISO646String
:
950 case DIRECTIVE_NumericString
:
951 case DIRECTIVE_PrintableString
:
952 case DIRECTIVE_T61String
:
953 case DIRECTIVE_TeletexString
:
954 case DIRECTIVE_UniversalString
:
955 case DIRECTIVE_UTF8String
:
956 case DIRECTIVE_VideotexString
:
957 case DIRECTIVE_VisibleString
:
958 case DIRECTIVE_ObjectDescriptor
:
959 case DIRECTIVE_GeneralizedTime
:
960 case DIRECTIVE_UTCTime
:
961 element
->compound
= NOT_COMPOUND
;
966 case DIRECTIVE_OCTET
:
967 element
->compound
= NOT_COMPOUND
;
971 if (cursor
->token_type
!= DIRECTIVE_STRING
)
976 case DIRECTIVE_OBJECT
:
977 element
->compound
= NOT_COMPOUND
;
981 if (cursor
->token_type
!= DIRECTIVE_IDENTIFIER
)
986 case TOKEN_TYPE_NAME
:
987 element
->compound
= TYPE_REF
;
988 ref
= bsearch(cursor
, type_index
, nr_types
, sizeof(type_index
[0]),
991 fprintf(stderr
, "%s:%d: Type '%*.*s' undefined\n",
992 filename
, cursor
->line
,
993 (int)cursor
->size
, (int)cursor
->size
, cursor
->value
);
1001 case DIRECTIVE_CHOICE
:
1002 element
->compound
= CHOICE
;
1004 element
->children
= parse_compound(&cursor
, end
, 1);
1007 case DIRECTIVE_SEQUENCE
:
1008 element
->compound
= SEQUENCE
;
1009 element
->method
= ASN1_CONS
;
1013 if (cursor
->token_type
== DIRECTIVE_OF
) {
1014 element
->compound
= SEQUENCE_OF
;
1018 element
->children
= parse_type(&cursor
, end
, NULL
);
1020 element
->children
= parse_compound(&cursor
, end
, 0);
1025 element
->compound
= SET
;
1026 element
->method
= ASN1_CONS
;
1030 if (cursor
->token_type
== DIRECTIVE_OF
) {
1031 element
->compound
= SET_OF
;
1035 element
->children
= parse_type(&cursor
, end
, NULL
);
1037 element
->children
= parse_compound(&cursor
, end
, 1);
1042 fprintf(stderr
, "%s:%d: Token '%*.*s' does not introduce a type\n",
1043 filename
, cursor
->line
,
1044 (int)cursor
->size
, (int)cursor
->size
, cursor
->value
);
1048 /* Handle elements that are optional */
1049 if (cursor
< end
&& (cursor
->token_type
== DIRECTIVE_OPTIONAL
||
1050 cursor
->token_type
== DIRECTIVE_DEFAULT
)
1053 top
->flags
|= ELEMENT_SKIPPABLE
;
1056 if (cursor
< end
&& cursor
->token_type
== TOKEN_OPEN_ACTION
) {
1060 if (cursor
->token_type
!= TOKEN_ELEMENT_NAME
) {
1061 fprintf(stderr
, "%s:%d: Token '%*.*s' is not an action function name\n",
1062 filename
, cursor
->line
,
1063 (int)cursor
->size
, (int)cursor
->size
, cursor
->value
);
1067 action
= malloc(sizeof(struct action
) + cursor
->size
+ 1);
1073 memcpy(action
->name
, cursor
->value
, cursor
->size
);
1074 action
->name
[cursor
->size
] = 0;
1076 for (ppaction
= &action_list
;
1078 ppaction
= &(*ppaction
)->next
1080 int cmp
= strcmp(action
->name
, (*ppaction
)->name
);
1087 action
->next
= *ppaction
;
1093 action
->next
= NULL
;
1098 element
->action
= action
;
1099 cursor
->action
= action
;
1103 if (cursor
->token_type
!= TOKEN_CLOSE_ACTION
) {
1104 fprintf(stderr
, "%s:%d: Missing close action, got '%*.*s'\n",
1105 filename
, cursor
->line
,
1106 (int)cursor
->size
, (int)cursor
->size
, cursor
->value
);
1116 fprintf(stderr
, "%s:%d: Unexpected token '%*.*s'\n",
1117 filename
, cursor
->line
,
1118 (int)cursor
->size
, (int)cursor
->size
, cursor
->value
);
1122 fprintf(stderr
, "%s: Unexpectedly hit EOF\n", filename
);
1127 * Parse a compound type list
1129 static struct element
*parse_compound(struct token
**_cursor
, struct token
*end
,
1132 struct element
*children
, **child_p
= &children
, *element
;
1133 struct token
*cursor
= *_cursor
, *name
;
1135 if (cursor
->token_type
!= TOKEN_OPEN_CURLY
) {
1136 fprintf(stderr
, "%s:%d: Expected compound to start with brace not '%*.*s'\n",
1137 filename
, cursor
->line
,
1138 (int)cursor
->size
, (int)cursor
->size
, cursor
->value
);
1145 if (cursor
->token_type
== TOKEN_OPEN_CURLY
) {
1146 fprintf(stderr
, "%s:%d: Empty compound\n",
1147 filename
, cursor
->line
);
1153 if (cursor
->token_type
== TOKEN_ELEMENT_NAME
) {
1160 element
= parse_type(&cursor
, end
, name
);
1162 element
->flags
|= ELEMENT_SKIPPABLE
| ELEMENT_CONDITIONAL
;
1165 child_p
= &element
->next
;
1169 if (cursor
->token_type
!= TOKEN_COMMA
)
1176 children
->flags
&= ~ELEMENT_CONDITIONAL
;
1178 if (cursor
->token_type
!= TOKEN_CLOSE_CURLY
) {
1179 fprintf(stderr
, "%s:%d: Expected compound closure, got '%*.*s'\n",
1180 filename
, cursor
->line
,
1181 (int)cursor
->size
, (int)cursor
->size
, cursor
->value
);
1190 fprintf(stderr
, "%s: Unexpectedly hit EOF\n", filename
);
1194 static void render_element(FILE *out
, struct element
*e
, struct element
*tag
);
1195 static void render_out_of_line_list(FILE *out
);
1197 static int nr_entries
;
1198 static int render_depth
= 1;
1199 static struct element
*render_list
, **render_list_p
= &render_list
;
1201 __attribute__((format(printf
, 2, 3)))
1202 static void render_opcode(FILE *out
, const char *fmt
, ...)
1207 fprintf(out
, "\t[%4d] =%*s", nr_entries
, render_depth
, "");
1209 vfprintf(out
, fmt
, va
);
1215 __attribute__((format(printf
, 2, 3)))
1216 static void render_more(FILE *out
, const char *fmt
, ...)
1222 vfprintf(out
, fmt
, va
);
1228 * Render the grammar into a state machine definition.
1230 static void render(FILE *out
, FILE *hdr
)
1233 struct action
*action
;
1237 fprintf(hdr
, "/*\n");
1238 fprintf(hdr
, " * Automatically generated by asn1_compiler. Do not edit\n");
1239 fprintf(hdr
, " *\n");
1240 fprintf(hdr
, " * ASN.1 parser for %s\n", grammar_name
);
1241 fprintf(hdr
, " */\n");
1242 fprintf(hdr
, "#include <linux/asn1_decoder.h>\n");
1244 fprintf(hdr
, "extern const struct asn1_decoder %s_decoder;\n", grammar_name
);
1250 fprintf(out
, "/*\n");
1251 fprintf(out
, " * Automatically generated by asn1_compiler. Do not edit\n");
1252 fprintf(out
, " *\n");
1253 fprintf(out
, " * ASN.1 parser for %s\n", grammar_name
);
1254 fprintf(out
, " */\n");
1255 fprintf(out
, "#include <linux/asn1_ber_bytecode.h>\n");
1256 fprintf(out
, "#include \"%s-asn1.h\"\n", grammar_name
);
1263 /* Tabulate the action functions we might have to call */
1266 for (action
= action_list
; action
; action
= action
->next
) {
1267 action
->index
= index
++;
1269 "extern int %s(void *, size_t, unsigned char,"
1270 " const void *, size_t);\n",
1275 fprintf(out
, "enum %s_actions {\n", grammar_name
);
1276 for (action
= action_list
; action
; action
= action
->next
)
1277 fprintf(out
, "\tACT_%s = %u,\n",
1278 action
->name
, action
->index
);
1279 fprintf(out
, "\tNR__%s_actions = %u\n", grammar_name
, nr_actions
);
1280 fprintf(out
, "};\n");
1283 fprintf(out
, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n",
1284 grammar_name
, grammar_name
);
1285 for (action
= action_list
; action
; action
= action
->next
)
1286 fprintf(out
, "\t[%4u] = %s,\n", action
->index
, action
->name
);
1287 fprintf(out
, "};\n");
1294 /* We do two passes - the first one calculates all the offsets */
1297 root
= &type_list
[0];
1298 render_element(NULL
, root
->element
, NULL
);
1299 render_opcode(NULL
, "ASN1_OP_COMPLETE,\n");
1300 render_out_of_line_list(NULL
);
1302 for (e
= element_list
; e
; e
= e
->list_next
)
1303 e
->flags
&= ~ELEMENT_RENDERED
;
1305 /* And then we actually render */
1308 fprintf(out
, "static const unsigned char %s_machine[] = {\n",
1312 root
= &type_list
[0];
1313 render_element(out
, root
->element
, NULL
);
1314 render_opcode(out
, "ASN1_OP_COMPLETE,\n");
1315 render_out_of_line_list(out
);
1317 fprintf(out
, "};\n");
1320 fprintf(out
, "const struct asn1_decoder %s_decoder = {\n", grammar_name
);
1321 fprintf(out
, "\t.machine = %s_machine,\n", grammar_name
);
1322 fprintf(out
, "\t.machlen = sizeof(%s_machine),\n", grammar_name
);
1323 fprintf(out
, "\t.actions = %s_action_table,\n", grammar_name
);
1324 fprintf(out
, "};\n");
1328 * Render the out-of-line elements
1330 static void render_out_of_line_list(FILE *out
)
1332 struct element
*e
, *ce
;
1336 while ((e
= render_list
)) {
1337 render_list
= e
->render_next
;
1339 render_list_p
= &render_list
;
1341 render_more(out
, "\n");
1342 e
->entry_index
= entry
= nr_entries
;
1344 for (ce
= e
->children
; ce
; ce
= ce
->next
)
1345 render_element(out
, ce
, NULL
);
1348 act
= e
->action
? "_ACT" : "";
1349 switch (e
->compound
) {
1351 render_opcode(out
, "ASN1_OP_END_SEQ%s,\n", act
);
1354 render_opcode(out
, "ASN1_OP_END_SEQ_OF%s,\n", act
);
1355 render_opcode(out
, "_jump_target(%u),\n", entry
);
1358 render_opcode(out
, "ASN1_OP_END_SET%s,\n", act
);
1361 render_opcode(out
, "ASN1_OP_END_SET_OF%s,\n", act
);
1362 render_opcode(out
, "_jump_target(%u),\n", entry
);
1368 render_opcode(out
, "_action(ACT_%s),\n",
1370 render_opcode(out
, "ASN1_OP_RETURN,\n");
1375 * Render an element.
1377 static void render_element(FILE *out
, struct element
*e
, struct element
*tag
)
1380 const char *cond
, *act
;
1381 int entry
, skippable
= 0, outofline
= 0;
1383 if (e
->flags
& ELEMENT_SKIPPABLE
||
1384 (tag
&& tag
->flags
& ELEMENT_SKIPPABLE
))
1387 if ((e
->type_def
&& e
->type_def
->ref_count
> 1) ||
1391 if (e
->type_def
&& out
) {
1392 render_more(out
, "\t// %*.*s\n",
1393 (int)e
->type_def
->name
->size
, (int)e
->type_def
->name
->size
,
1394 e
->type_def
->name
->value
);
1397 /* Render the operation */
1398 cond
= (e
->flags
& ELEMENT_CONDITIONAL
||
1399 (tag
&& tag
->flags
& ELEMENT_CONDITIONAL
)) ? "COND_" : "";
1400 act
= e
->action
? "_ACT" : "";
1401 switch (e
->compound
) {
1403 render_opcode(out
, "ASN1_OP_%sMATCH_ANY%s,", cond
, act
);
1405 render_more(out
, "\t\t// %*.*s",
1406 (int)e
->name
->size
, (int)e
->name
->size
,
1408 render_more(out
, "\n");
1409 goto dont_render_tag
;
1412 render_element(out
, e
->children
, e
);
1419 render_opcode(out
, "ASN1_OP_%sMATCH%s%s,",
1421 outofline
? "_JUMP" : "",
1422 skippable
? "_OR_SKIP" : "");
1426 goto dont_render_tag
;
1429 if (e
->class == ASN1_UNIV
&& e
->method
== ASN1_PRIM
&& e
->tag
== 0)
1430 goto dont_render_tag
;
1432 render_opcode(out
, "ASN1_OP_%sMATCH%s%s,",
1434 skippable
? "_OR_SKIP" : "");
1439 render_more(out
, "\t\t// %*.*s",
1440 (int)e
->name
->size
, (int)e
->name
->size
,
1442 render_more(out
, "\n");
1444 /* Render the tag */
1447 if (tag
->class == ASN1_UNIV
&&
1451 render_opcode(out
, "_tag(%s, %s, %s),\n",
1452 asn1_classes
[tag
->class],
1453 asn1_methods
[tag
->method
| e
->method
],
1454 asn1_universal_tags
[tag
->tag
]);
1456 render_opcode(out
, "_tagn(%s, %s, %2u),\n",
1457 asn1_classes
[tag
->class],
1458 asn1_methods
[tag
->method
| e
->method
],
1463 /* Deal with compound types */
1464 switch (e
->compound
) {
1466 render_element(out
, e
->type
->type
->element
, tag
);
1468 render_opcode(out
, "ASN1_OP_ACT,\n");
1473 /* Render out-of-line for multiple use or
1475 render_opcode(out
, "_jump_target(%u),", e
->entry_index
);
1476 if (e
->type_def
&& e
->type_def
->name
)
1477 render_more(out
, "\t\t// --> %*.*s",
1478 (int)e
->type_def
->name
->size
,
1479 (int)e
->type_def
->name
->size
,
1480 e
->type_def
->name
->value
);
1481 render_more(out
, "\n");
1482 if (!(e
->flags
& ELEMENT_RENDERED
)) {
1483 e
->flags
|= ELEMENT_RENDERED
;
1485 render_list_p
= &e
->render_next
;
1489 /* Render inline for single use */
1491 for (ec
= e
->children
; ec
; ec
= ec
->next
)
1492 render_element(out
, ec
, NULL
);
1494 render_opcode(out
, "ASN1_OP_END_SEQ%s,\n", act
);
1501 /* Render out-of-line for multiple use or
1503 render_opcode(out
, "_jump_target(%u),", e
->entry_index
);
1504 if (e
->type_def
&& e
->type_def
->name
)
1505 render_more(out
, "\t\t// --> %*.*s",
1506 (int)e
->type_def
->name
->size
,
1507 (int)e
->type_def
->name
->size
,
1508 e
->type_def
->name
->value
);
1509 render_more(out
, "\n");
1510 if (!(e
->flags
& ELEMENT_RENDERED
)) {
1511 e
->flags
|= ELEMENT_RENDERED
;
1513 render_list_p
= &e
->render_next
;
1517 /* Render inline for single use */
1520 render_element(out
, e
->children
, NULL
);
1522 if (e
->compound
== SEQUENCE_OF
)
1523 render_opcode(out
, "ASN1_OP_END_SEQ_OF%s,\n", act
);
1525 render_opcode(out
, "ASN1_OP_END_SET_OF%s,\n", act
);
1526 render_opcode(out
, "_jump_target(%u),\n", entry
);
1531 /* I can't think of a nice way to do SET support without having
1532 * a stack of bitmasks to make sure no element is repeated.
1533 * The bitmask has also to be checked that no non-optional
1534 * elements are left out whilst not preventing optional
1535 * elements from being left out.
1537 fprintf(stderr
, "The ASN.1 SET type is not currently supported.\n");
1541 for (ec
= e
->children
; ec
; ec
= ec
->next
)
1542 render_element(out
, ec
, NULL
);
1544 render_opcode(out
, "ASN1_OP_COND_FAIL,\n");
1546 render_opcode(out
, "ASN1_OP_ACT,\n");
1554 render_opcode(out
, "_action(ACT_%s),\n", e
->action
->name
);