Loading...
1/* Simplified ASN.1 notation parser
2 *
3 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
4 * Written by David Howells (dhowells@redhat.com)
5 *
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.
10 */
11
12#include <stdarg.h>
13#include <stdio.h>
14#include <stdlib.h>
15#include <stdint.h>
16#include <stdbool.h>
17#include <string.h>
18#include <ctype.h>
19#include <unistd.h>
20#include <fcntl.h>
21#include <sys/stat.h>
22#include <linux/asn1_ber_bytecode.h>
23
24enum token_type {
25 DIRECTIVE_ABSENT,
26 DIRECTIVE_ALL,
27 DIRECTIVE_ANY,
28 DIRECTIVE_APPLICATION,
29 DIRECTIVE_AUTOMATIC,
30 DIRECTIVE_BEGIN,
31 DIRECTIVE_BIT,
32 DIRECTIVE_BMPString,
33 DIRECTIVE_BOOLEAN,
34 DIRECTIVE_BY,
35 DIRECTIVE_CHARACTER,
36 DIRECTIVE_CHOICE,
37 DIRECTIVE_CLASS,
38 DIRECTIVE_COMPONENT,
39 DIRECTIVE_COMPONENTS,
40 DIRECTIVE_CONSTRAINED,
41 DIRECTIVE_CONTAINING,
42 DIRECTIVE_DEFAULT,
43 DIRECTIVE_DEFINED,
44 DIRECTIVE_DEFINITIONS,
45 DIRECTIVE_EMBEDDED,
46 DIRECTIVE_ENCODED,
47 DIRECTIVE_ENCODING_CONTROL,
48 DIRECTIVE_END,
49 DIRECTIVE_ENUMERATED,
50 DIRECTIVE_EXCEPT,
51 DIRECTIVE_EXPLICIT,
52 DIRECTIVE_EXPORTS,
53 DIRECTIVE_EXTENSIBILITY,
54 DIRECTIVE_EXTERNAL,
55 DIRECTIVE_FALSE,
56 DIRECTIVE_FROM,
57 DIRECTIVE_GeneralString,
58 DIRECTIVE_GeneralizedTime,
59 DIRECTIVE_GraphicString,
60 DIRECTIVE_IA5String,
61 DIRECTIVE_IDENTIFIER,
62 DIRECTIVE_IMPLICIT,
63 DIRECTIVE_IMPLIED,
64 DIRECTIVE_IMPORTS,
65 DIRECTIVE_INCLUDES,
66 DIRECTIVE_INSTANCE,
67 DIRECTIVE_INSTRUCTIONS,
68 DIRECTIVE_INTEGER,
69 DIRECTIVE_INTERSECTION,
70 DIRECTIVE_ISO646String,
71 DIRECTIVE_MAX,
72 DIRECTIVE_MIN,
73 DIRECTIVE_MINUS_INFINITY,
74 DIRECTIVE_NULL,
75 DIRECTIVE_NumericString,
76 DIRECTIVE_OBJECT,
77 DIRECTIVE_OCTET,
78 DIRECTIVE_OF,
79 DIRECTIVE_OPTIONAL,
80 DIRECTIVE_ObjectDescriptor,
81 DIRECTIVE_PATTERN,
82 DIRECTIVE_PDV,
83 DIRECTIVE_PLUS_INFINITY,
84 DIRECTIVE_PRESENT,
85 DIRECTIVE_PRIVATE,
86 DIRECTIVE_PrintableString,
87 DIRECTIVE_REAL,
88 DIRECTIVE_RELATIVE_OID,
89 DIRECTIVE_SEQUENCE,
90 DIRECTIVE_SET,
91 DIRECTIVE_SIZE,
92 DIRECTIVE_STRING,
93 DIRECTIVE_SYNTAX,
94 DIRECTIVE_T61String,
95 DIRECTIVE_TAGS,
96 DIRECTIVE_TRUE,
97 DIRECTIVE_TeletexString,
98 DIRECTIVE_UNION,
99 DIRECTIVE_UNIQUE,
100 DIRECTIVE_UNIVERSAL,
101 DIRECTIVE_UTCTime,
102 DIRECTIVE_UTF8String,
103 DIRECTIVE_UniversalString,
104 DIRECTIVE_VideotexString,
105 DIRECTIVE_VisibleString,
106 DIRECTIVE_WITH,
107 NR__DIRECTIVES,
108 TOKEN_ASSIGNMENT = NR__DIRECTIVES,
109 TOKEN_OPEN_CURLY,
110 TOKEN_CLOSE_CURLY,
111 TOKEN_OPEN_SQUARE,
112 TOKEN_CLOSE_SQUARE,
113 TOKEN_OPEN_ACTION,
114 TOKEN_CLOSE_ACTION,
115 TOKEN_COMMA,
116 TOKEN_NUMBER,
117 TOKEN_TYPE_NAME,
118 TOKEN_ELEMENT_NAME,
119 NR__TOKENS
120};
121
122static const unsigned char token_to_tag[NR__TOKENS] = {
123 /* EOC goes first */
124 [DIRECTIVE_BOOLEAN] = ASN1_BOOL,
125 [DIRECTIVE_INTEGER] = ASN1_INT,
126 [DIRECTIVE_BIT] = ASN1_BTS,
127 [DIRECTIVE_OCTET] = ASN1_OTS,
128 [DIRECTIVE_NULL] = ASN1_NULL,
129 [DIRECTIVE_OBJECT] = ASN1_OID,
130 [DIRECTIVE_ObjectDescriptor] = ASN1_ODE,
131 [DIRECTIVE_EXTERNAL] = ASN1_EXT,
132 [DIRECTIVE_REAL] = ASN1_REAL,
133 [DIRECTIVE_ENUMERATED] = ASN1_ENUM,
134 [DIRECTIVE_EMBEDDED] = 0,
135 [DIRECTIVE_UTF8String] = ASN1_UTF8STR,
136 [DIRECTIVE_RELATIVE_OID] = ASN1_RELOID,
137 /* 14 */
138 /* 15 */
139 [DIRECTIVE_SEQUENCE] = ASN1_SEQ,
140 [DIRECTIVE_SET] = ASN1_SET,
141 [DIRECTIVE_NumericString] = ASN1_NUMSTR,
142 [DIRECTIVE_PrintableString] = ASN1_PRNSTR,
143 [DIRECTIVE_T61String] = ASN1_TEXSTR,
144 [DIRECTIVE_TeletexString] = ASN1_TEXSTR,
145 [DIRECTIVE_VideotexString] = ASN1_VIDSTR,
146 [DIRECTIVE_IA5String] = ASN1_IA5STR,
147 [DIRECTIVE_UTCTime] = ASN1_UNITIM,
148 [DIRECTIVE_GeneralizedTime] = ASN1_GENTIM,
149 [DIRECTIVE_GraphicString] = ASN1_GRASTR,
150 [DIRECTIVE_VisibleString] = ASN1_VISSTR,
151 [DIRECTIVE_GeneralString] = ASN1_GENSTR,
152 [DIRECTIVE_UniversalString] = ASN1_UNITIM,
153 [DIRECTIVE_CHARACTER] = ASN1_CHRSTR,
154 [DIRECTIVE_BMPString] = ASN1_BMPSTR,
155};
156
157static const char asn1_classes[4][5] = {
158 [ASN1_UNIV] = "UNIV",
159 [ASN1_APPL] = "APPL",
160 [ASN1_CONT] = "CONT",
161 [ASN1_PRIV] = "PRIV"
162};
163
164static const char asn1_methods[2][5] = {
165 [ASN1_UNIV] = "PRIM",
166 [ASN1_APPL] = "CONS"
167};
168
169static const char *const asn1_universal_tags[32] = {
170 "EOC",
171 "BOOL",
172 "INT",
173 "BTS",
174 "OTS",
175 "NULL",
176 "OID",
177 "ODE",
178 "EXT",
179 "REAL",
180 "ENUM",
181 "EPDV",
182 "UTF8STR",
183 "RELOID",
184 NULL, /* 14 */
185 NULL, /* 15 */
186 "SEQ",
187 "SET",
188 "NUMSTR",
189 "PRNSTR",
190 "TEXSTR",
191 "VIDSTR",
192 "IA5STR",
193 "UNITIM",
194 "GENTIM",
195 "GRASTR",
196 "VISSTR",
197 "GENSTR",
198 "UNISTR",
199 "CHRSTR",
200 "BMPSTR",
201 NULL /* 31 */
202};
203
204static const char *filename;
205static const char *grammar_name;
206static const char *outputname;
207static const char *headername;
208
209static const char *const directives[NR__DIRECTIVES] = {
210#define _(X) [DIRECTIVE_##X] = #X
211 _(ABSENT),
212 _(ALL),
213 _(ANY),
214 _(APPLICATION),
215 _(AUTOMATIC),
216 _(BEGIN),
217 _(BIT),
218 _(BMPString),
219 _(BOOLEAN),
220 _(BY),
221 _(CHARACTER),
222 _(CHOICE),
223 _(CLASS),
224 _(COMPONENT),
225 _(COMPONENTS),
226 _(CONSTRAINED),
227 _(CONTAINING),
228 _(DEFAULT),
229 _(DEFINED),
230 _(DEFINITIONS),
231 _(EMBEDDED),
232 _(ENCODED),
233 [DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL",
234 _(END),
235 _(ENUMERATED),
236 _(EXCEPT),
237 _(EXPLICIT),
238 _(EXPORTS),
239 _(EXTENSIBILITY),
240 _(EXTERNAL),
241 _(FALSE),
242 _(FROM),
243 _(GeneralString),
244 _(GeneralizedTime),
245 _(GraphicString),
246 _(IA5String),
247 _(IDENTIFIER),
248 _(IMPLICIT),
249 _(IMPLIED),
250 _(IMPORTS),
251 _(INCLUDES),
252 _(INSTANCE),
253 _(INSTRUCTIONS),
254 _(INTEGER),
255 _(INTERSECTION),
256 _(ISO646String),
257 _(MAX),
258 _(MIN),
259 [DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY",
260 [DIRECTIVE_NULL] = "NULL",
261 _(NumericString),
262 _(OBJECT),
263 _(OCTET),
264 _(OF),
265 _(OPTIONAL),
266 _(ObjectDescriptor),
267 _(PATTERN),
268 _(PDV),
269 [DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY",
270 _(PRESENT),
271 _(PRIVATE),
272 _(PrintableString),
273 _(REAL),
274 [DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID",
275 _(SEQUENCE),
276 _(SET),
277 _(SIZE),
278 _(STRING),
279 _(SYNTAX),
280 _(T61String),
281 _(TAGS),
282 _(TRUE),
283 _(TeletexString),
284 _(UNION),
285 _(UNIQUE),
286 _(UNIVERSAL),
287 _(UTCTime),
288 _(UTF8String),
289 _(UniversalString),
290 _(VideotexString),
291 _(VisibleString),
292 _(WITH)
293};
294
295struct action {
296 struct action *next;
297 char *name;
298 unsigned char index;
299};
300
301static struct action *action_list;
302static unsigned nr_actions;
303
304struct token {
305 unsigned short line;
306 enum token_type token_type : 8;
307 unsigned char size;
308 struct action *action;
309 char *content;
310 struct type *type;
311};
312
313static struct token *token_list;
314static unsigned nr_tokens;
315static bool verbose_opt;
316static bool debug_opt;
317
318#define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0)
319#define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0)
320
321static int directive_compare(const void *_key, const void *_pdir)
322{
323 const struct token *token = _key;
324 const char *const *pdir = _pdir, *dir = *pdir;
325 size_t dlen, clen;
326 int val;
327
328 dlen = strlen(dir);
329 clen = (dlen < token->size) ? dlen : token->size;
330
331 //debug("cmp(%s,%s) = ", token->content, dir);
332
333 val = memcmp(token->content, dir, clen);
334 if (val != 0) {
335 //debug("%d [cmp]\n", val);
336 return val;
337 }
338
339 if (dlen == token->size) {
340 //debug("0\n");
341 return 0;
342 }
343 //debug("%d\n", (int)dlen - (int)token->size);
344 return dlen - token->size; /* shorter -> negative */
345}
346
347/*
348 * Tokenise an ASN.1 grammar
349 */
350static void tokenise(char *buffer, char *end)
351{
352 struct token *tokens;
353 char *line, *nl, *start, *p, *q;
354 unsigned tix, lineno;
355
356 /* Assume we're going to have half as many tokens as we have
357 * characters
358 */
359 token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token));
360 if (!tokens) {
361 perror(NULL);
362 exit(1);
363 }
364 tix = 0;
365
366 lineno = 0;
367 while (buffer < end) {
368 /* First of all, break out a line */
369 lineno++;
370 line = buffer;
371 nl = memchr(line, '\n', end - buffer);
372 if (!nl) {
373 buffer = nl = end;
374 } else {
375 buffer = nl + 1;
376 *nl = '\0';
377 }
378
379 /* Remove "--" comments */
380 p = line;
381 next_comment:
382 while ((p = memchr(p, '-', nl - p))) {
383 if (p[1] == '-') {
384 /* Found a comment; see if there's a terminator */
385 q = p + 2;
386 while ((q = memchr(q, '-', nl - q))) {
387 if (q[1] == '-') {
388 /* There is - excise the comment */
389 q += 2;
390 memmove(p, q, nl - q);
391 goto next_comment;
392 }
393 q++;
394 }
395 *p = '\0';
396 nl = p;
397 break;
398 } else {
399 p++;
400 }
401 }
402
403 p = line;
404 while (p < nl) {
405 /* Skip white space */
406 while (p < nl && isspace(*p))
407 *(p++) = 0;
408 if (p >= nl)
409 break;
410
411 tokens[tix].line = lineno;
412 start = p;
413
414 /* Handle string tokens */
415 if (isalpha(*p)) {
416 const char **dir, *start = p;
417
418 /* Can be a directive, type name or element
419 * name. Find the end of the name.
420 */
421 q = p + 1;
422 while (q < nl && (isalnum(*q) || *q == '-' || *q == '_'))
423 q++;
424 tokens[tix].size = q - p;
425 p = q;
426
427 tokens[tix].content = malloc(tokens[tix].size + 1);
428 if (!tokens[tix].content) {
429 perror(NULL);
430 exit(1);
431 }
432 memcpy(tokens[tix].content, start, tokens[tix].size);
433 tokens[tix].content[tokens[tix].size] = 0;
434
435 /* If it begins with a lowercase letter then
436 * it's an element name
437 */
438 if (islower(tokens[tix].content[0])) {
439 tokens[tix++].token_type = TOKEN_ELEMENT_NAME;
440 continue;
441 }
442
443 /* Otherwise we need to search the directive
444 * table
445 */
446 dir = bsearch(&tokens[tix], directives,
447 sizeof(directives) / sizeof(directives[1]),
448 sizeof(directives[1]),
449 directive_compare);
450 if (dir) {
451 tokens[tix++].token_type = dir - directives;
452 continue;
453 }
454
455 tokens[tix++].token_type = TOKEN_TYPE_NAME;
456 continue;
457 }
458
459 /* Handle numbers */
460 if (isdigit(*p)) {
461 /* Find the end of the number */
462 q = p + 1;
463 while (q < nl && (isdigit(*q)))
464 q++;
465 tokens[tix].size = q - p;
466 p = q;
467 tokens[tix].content = malloc(tokens[tix].size + 1);
468 if (!tokens[tix].content) {
469 perror(NULL);
470 exit(1);
471 }
472 memcpy(tokens[tix].content, start, tokens[tix].size);
473 tokens[tix].content[tokens[tix].size] = 0;
474 tokens[tix++].token_type = TOKEN_NUMBER;
475 continue;
476 }
477
478 if (nl - p >= 3) {
479 if (memcmp(p, "::=", 3) == 0) {
480 p += 3;
481 tokens[tix].size = 3;
482 tokens[tix].content = "::=";
483 tokens[tix++].token_type = TOKEN_ASSIGNMENT;
484 continue;
485 }
486 }
487
488 if (nl - p >= 2) {
489 if (memcmp(p, "({", 2) == 0) {
490 p += 2;
491 tokens[tix].size = 2;
492 tokens[tix].content = "({";
493 tokens[tix++].token_type = TOKEN_OPEN_ACTION;
494 continue;
495 }
496 if (memcmp(p, "})", 2) == 0) {
497 p += 2;
498 tokens[tix].size = 2;
499 tokens[tix].content = "})";
500 tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
501 continue;
502 }
503 }
504
505 if (nl - p >= 1) {
506 tokens[tix].size = 1;
507 switch (*p) {
508 case '{':
509 p += 1;
510 tokens[tix].content = "{";
511 tokens[tix++].token_type = TOKEN_OPEN_CURLY;
512 continue;
513 case '}':
514 p += 1;
515 tokens[tix].content = "}";
516 tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
517 continue;
518 case '[':
519 p += 1;
520 tokens[tix].content = "[";
521 tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
522 continue;
523 case ']':
524 p += 1;
525 tokens[tix].content = "]";
526 tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
527 continue;
528 case ',':
529 p += 1;
530 tokens[tix].content = ",";
531 tokens[tix++].token_type = TOKEN_COMMA;
532 continue;
533 default:
534 break;
535 }
536 }
537
538 fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n",
539 filename, lineno, *p);
540 exit(1);
541 }
542 }
543
544 nr_tokens = tix;
545 verbose("Extracted %u tokens\n", nr_tokens);
546
547#if 0
548 {
549 int n;
550 for (n = 0; n < nr_tokens; n++)
551 debug("Token %3u: '%s'\n", n, token_list[n].content);
552 }
553#endif
554}
555
556static void build_type_list(void);
557static void parse(void);
558static void dump_elements(void);
559static void render(FILE *out, FILE *hdr);
560
561/*
562 *
563 */
564int main(int argc, char **argv)
565{
566 struct stat st;
567 ssize_t readlen;
568 FILE *out, *hdr;
569 char *buffer, *p;
570 char *kbuild_verbose;
571 int fd;
572
573 kbuild_verbose = getenv("KBUILD_VERBOSE");
574 if (kbuild_verbose)
575 verbose_opt = atoi(kbuild_verbose);
576
577 while (argc > 4) {
578 if (strcmp(argv[1], "-v") == 0)
579 verbose_opt = true;
580 else if (strcmp(argv[1], "-d") == 0)
581 debug_opt = true;
582 else
583 break;
584 memmove(&argv[1], &argv[2], (argc - 2) * sizeof(char *));
585 argc--;
586 }
587
588 if (argc != 4) {
589 fprintf(stderr, "Format: %s [-v] [-d] <grammar-file> <c-file> <hdr-file>\n",
590 argv[0]);
591 exit(2);
592 }
593
594 filename = argv[1];
595 outputname = argv[2];
596 headername = argv[3];
597
598 fd = open(filename, O_RDONLY);
599 if (fd < 0) {
600 perror(filename);
601 exit(1);
602 }
603
604 if (fstat(fd, &st) < 0) {
605 perror(filename);
606 exit(1);
607 }
608
609 if (!(buffer = malloc(st.st_size + 1))) {
610 perror(NULL);
611 exit(1);
612 }
613
614 if ((readlen = read(fd, buffer, st.st_size)) < 0) {
615 perror(filename);
616 exit(1);
617 }
618
619 if (close(fd) < 0) {
620 perror(filename);
621 exit(1);
622 }
623
624 if (readlen != st.st_size) {
625 fprintf(stderr, "%s: Short read\n", filename);
626 exit(1);
627 }
628
629 p = strrchr(argv[1], '/');
630 p = p ? p + 1 : argv[1];
631 grammar_name = strdup(p);
632 if (!p) {
633 perror(NULL);
634 exit(1);
635 }
636 p = strchr(grammar_name, '.');
637 if (p)
638 *p = '\0';
639
640 buffer[readlen] = 0;
641 tokenise(buffer, buffer + readlen);
642 build_type_list();
643 parse();
644 dump_elements();
645
646 out = fopen(outputname, "w");
647 if (!out) {
648 perror(outputname);
649 exit(1);
650 }
651
652 hdr = fopen(headername, "w");
653 if (!hdr) {
654 perror(headername);
655 exit(1);
656 }
657
658 render(out, hdr);
659
660 if (fclose(out) < 0) {
661 perror(outputname);
662 exit(1);
663 }
664
665 if (fclose(hdr) < 0) {
666 perror(headername);
667 exit(1);
668 }
669
670 return 0;
671}
672
673enum compound {
674 NOT_COMPOUND,
675 SET,
676 SET_OF,
677 SEQUENCE,
678 SEQUENCE_OF,
679 CHOICE,
680 ANY,
681 TYPE_REF,
682 TAG_OVERRIDE
683};
684
685struct element {
686 struct type *type_def;
687 struct token *name;
688 struct token *type;
689 struct action *action;
690 struct element *children;
691 struct element *next;
692 struct element *render_next;
693 struct element *list_next;
694 uint8_t n_elements;
695 enum compound compound : 8;
696 enum asn1_class class : 8;
697 enum asn1_method method : 8;
698 uint8_t tag;
699 unsigned entry_index;
700 unsigned flags;
701#define ELEMENT_IMPLICIT 0x0001
702#define ELEMENT_EXPLICIT 0x0002
703#define ELEMENT_TAG_SPECIFIED 0x0004
704#define ELEMENT_RENDERED 0x0008
705#define ELEMENT_SKIPPABLE 0x0010
706#define ELEMENT_CONDITIONAL 0x0020
707};
708
709struct type {
710 struct token *name;
711 struct token *def;
712 struct element *element;
713 unsigned ref_count;
714 unsigned flags;
715#define TYPE_STOP_MARKER 0x0001
716#define TYPE_BEGIN 0x0002
717};
718
719static struct type *type_list;
720static struct type **type_index;
721static unsigned nr_types;
722
723static int type_index_compare(const void *_a, const void *_b)
724{
725 const struct type *const *a = _a, *const *b = _b;
726
727 if ((*a)->name->size != (*b)->name->size)
728 return (*a)->name->size - (*b)->name->size;
729 else
730 return memcmp((*a)->name->content, (*b)->name->content,
731 (*a)->name->size);
732}
733
734static int type_finder(const void *_key, const void *_ti)
735{
736 const struct token *token = _key;
737 const struct type *const *ti = _ti;
738 const struct type *type = *ti;
739
740 if (token->size != type->name->size)
741 return token->size - type->name->size;
742 else
743 return memcmp(token->content, type->name->content,
744 token->size);
745}
746
747/*
748 * Build up a list of types and a sorted index to that list.
749 */
750static void build_type_list(void)
751{
752 struct type *types;
753 unsigned nr, t, n;
754
755 nr = 0;
756 for (n = 0; n < nr_tokens - 1; n++)
757 if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
758 token_list[n + 1].token_type == TOKEN_ASSIGNMENT)
759 nr++;
760
761 if (nr == 0) {
762 fprintf(stderr, "%s: No defined types\n", filename);
763 exit(1);
764 }
765
766 nr_types = nr;
767 types = type_list = calloc(nr + 1, sizeof(type_list[0]));
768 if (!type_list) {
769 perror(NULL);
770 exit(1);
771 }
772 type_index = calloc(nr, sizeof(type_index[0]));
773 if (!type_index) {
774 perror(NULL);
775 exit(1);
776 }
777
778 t = 0;
779 types[t].flags |= TYPE_BEGIN;
780 for (n = 0; n < nr_tokens - 1; n++) {
781 if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
782 token_list[n + 1].token_type == TOKEN_ASSIGNMENT) {
783 types[t].name = &token_list[n];
784 type_index[t] = &types[t];
785 t++;
786 }
787 }
788 types[t].name = &token_list[n + 1];
789 types[t].flags |= TYPE_STOP_MARKER;
790
791 qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
792
793 verbose("Extracted %u types\n", nr_types);
794#if 0
795 for (n = 0; n < nr_types; n++) {
796 struct type *type = type_index[n];
797 debug("- %*.*s\n", type->name->content);
798 }
799#endif
800}
801
802static struct element *parse_type(struct token **_cursor, struct token *stop,
803 struct token *name);
804
805/*
806 * Parse the token stream
807 */
808static void parse(void)
809{
810 struct token *cursor;
811 struct type *type;
812
813 /* Parse one type definition statement at a time */
814 type = type_list;
815 do {
816 cursor = type->name;
817
818 if (cursor[0].token_type != TOKEN_TYPE_NAME ||
819 cursor[1].token_type != TOKEN_ASSIGNMENT)
820 abort();
821 cursor += 2;
822
823 type->element = parse_type(&cursor, type[1].name, NULL);
824 type->element->type_def = type;
825
826 if (cursor != type[1].name) {
827 fprintf(stderr, "%s:%d: Parse error at token '%s'\n",
828 filename, cursor->line, cursor->content);
829 exit(1);
830 }
831
832 } while (type++, !(type->flags & TYPE_STOP_MARKER));
833
834 verbose("Extracted %u actions\n", nr_actions);
835}
836
837static struct element *element_list;
838
839static struct element *alloc_elem(struct token *type)
840{
841 struct element *e = calloc(1, sizeof(*e));
842 if (!e) {
843 perror(NULL);
844 exit(1);
845 }
846 e->list_next = element_list;
847 element_list = e;
848 return e;
849}
850
851static struct element *parse_compound(struct token **_cursor, struct token *end,
852 int alternates);
853
854/*
855 * Parse one type definition statement
856 */
857static struct element *parse_type(struct token **_cursor, struct token *end,
858 struct token *name)
859{
860 struct element *top, *element;
861 struct action *action, **ppaction;
862 struct token *cursor = *_cursor;
863 struct type **ref;
864 char *p;
865 int labelled = 0, implicit = 0;
866
867 top = element = alloc_elem(cursor);
868 element->class = ASN1_UNIV;
869 element->method = ASN1_PRIM;
870 element->tag = token_to_tag[cursor->token_type];
871 element->name = name;
872
873 /* Extract the tag value if one given */
874 if (cursor->token_type == TOKEN_OPEN_SQUARE) {
875 cursor++;
876 if (cursor >= end)
877 goto overrun_error;
878 switch (cursor->token_type) {
879 case DIRECTIVE_UNIVERSAL:
880 element->class = ASN1_UNIV;
881 cursor++;
882 break;
883 case DIRECTIVE_APPLICATION:
884 element->class = ASN1_APPL;
885 cursor++;
886 break;
887 case TOKEN_NUMBER:
888 element->class = ASN1_CONT;
889 break;
890 case DIRECTIVE_PRIVATE:
891 element->class = ASN1_PRIV;
892 cursor++;
893 break;
894 default:
895 fprintf(stderr, "%s:%d: Unrecognised tag class token '%s'\n",
896 filename, cursor->line, cursor->content);
897 exit(1);
898 }
899
900 if (cursor >= end)
901 goto overrun_error;
902 if (cursor->token_type != TOKEN_NUMBER) {
903 fprintf(stderr, "%s:%d: Missing tag number '%s'\n",
904 filename, cursor->line, cursor->content);
905 exit(1);
906 }
907
908 element->tag &= ~0x1f;
909 element->tag |= strtoul(cursor->content, &p, 10);
910 element->flags |= ELEMENT_TAG_SPECIFIED;
911 if (p - cursor->content != cursor->size)
912 abort();
913 cursor++;
914
915 if (cursor >= end)
916 goto overrun_error;
917 if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
918 fprintf(stderr, "%s:%d: Missing closing square bracket '%s'\n",
919 filename, cursor->line, cursor->content);
920 exit(1);
921 }
922 cursor++;
923 if (cursor >= end)
924 goto overrun_error;
925 labelled = 1;
926 }
927
928 /* Handle implicit and explicit markers */
929 if (cursor->token_type == DIRECTIVE_IMPLICIT) {
930 element->flags |= ELEMENT_IMPLICIT;
931 implicit = 1;
932 cursor++;
933 if (cursor >= end)
934 goto overrun_error;
935 } else if (cursor->token_type == DIRECTIVE_EXPLICIT) {
936 element->flags |= ELEMENT_EXPLICIT;
937 cursor++;
938 if (cursor >= end)
939 goto overrun_error;
940 }
941
942 if (labelled) {
943 if (!implicit)
944 element->method |= ASN1_CONS;
945 element->compound = implicit ? TAG_OVERRIDE : SEQUENCE;
946 element->children = alloc_elem(cursor);
947 element = element->children;
948 element->class = ASN1_UNIV;
949 element->method = ASN1_PRIM;
950 element->tag = token_to_tag[cursor->token_type];
951 element->name = name;
952 }
953
954 /* Extract the type we're expecting here */
955 element->type = cursor;
956 switch (cursor->token_type) {
957 case DIRECTIVE_ANY:
958 element->compound = ANY;
959 cursor++;
960 break;
961
962 case DIRECTIVE_NULL:
963 case DIRECTIVE_BOOLEAN:
964 case DIRECTIVE_ENUMERATED:
965 case DIRECTIVE_INTEGER:
966 element->compound = NOT_COMPOUND;
967 cursor++;
968 break;
969
970 case DIRECTIVE_EXTERNAL:
971 element->method = ASN1_CONS;
972
973 case DIRECTIVE_BMPString:
974 case DIRECTIVE_GeneralString:
975 case DIRECTIVE_GraphicString:
976 case DIRECTIVE_IA5String:
977 case DIRECTIVE_ISO646String:
978 case DIRECTIVE_NumericString:
979 case DIRECTIVE_PrintableString:
980 case DIRECTIVE_T61String:
981 case DIRECTIVE_TeletexString:
982 case DIRECTIVE_UniversalString:
983 case DIRECTIVE_UTF8String:
984 case DIRECTIVE_VideotexString:
985 case DIRECTIVE_VisibleString:
986 case DIRECTIVE_ObjectDescriptor:
987 case DIRECTIVE_GeneralizedTime:
988 case DIRECTIVE_UTCTime:
989 element->compound = NOT_COMPOUND;
990 cursor++;
991 break;
992
993 case DIRECTIVE_BIT:
994 case DIRECTIVE_OCTET:
995 element->compound = NOT_COMPOUND;
996 cursor++;
997 if (cursor >= end)
998 goto overrun_error;
999 if (cursor->token_type != DIRECTIVE_STRING)
1000 goto parse_error;
1001 cursor++;
1002 break;
1003
1004 case DIRECTIVE_OBJECT:
1005 element->compound = NOT_COMPOUND;
1006 cursor++;
1007 if (cursor >= end)
1008 goto overrun_error;
1009 if (cursor->token_type != DIRECTIVE_IDENTIFIER)
1010 goto parse_error;
1011 cursor++;
1012 break;
1013
1014 case TOKEN_TYPE_NAME:
1015 element->compound = TYPE_REF;
1016 ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
1017 type_finder);
1018 if (!ref) {
1019 fprintf(stderr, "%s:%d: Type '%s' undefined\n",
1020 filename, cursor->line, cursor->content);
1021 exit(1);
1022 }
1023 cursor->type = *ref;
1024 (*ref)->ref_count++;
1025 cursor++;
1026 break;
1027
1028 case DIRECTIVE_CHOICE:
1029 element->compound = CHOICE;
1030 cursor++;
1031 element->children = parse_compound(&cursor, end, 1);
1032 break;
1033
1034 case DIRECTIVE_SEQUENCE:
1035 element->compound = SEQUENCE;
1036 element->method = ASN1_CONS;
1037 cursor++;
1038 if (cursor >= end)
1039 goto overrun_error;
1040 if (cursor->token_type == DIRECTIVE_OF) {
1041 element->compound = SEQUENCE_OF;
1042 cursor++;
1043 if (cursor >= end)
1044 goto overrun_error;
1045 element->children = parse_type(&cursor, end, NULL);
1046 } else {
1047 element->children = parse_compound(&cursor, end, 0);
1048 }
1049 break;
1050
1051 case DIRECTIVE_SET:
1052 element->compound = SET;
1053 element->method = ASN1_CONS;
1054 cursor++;
1055 if (cursor >= end)
1056 goto overrun_error;
1057 if (cursor->token_type == DIRECTIVE_OF) {
1058 element->compound = SET_OF;
1059 cursor++;
1060 if (cursor >= end)
1061 goto parse_error;
1062 element->children = parse_type(&cursor, end, NULL);
1063 } else {
1064 element->children = parse_compound(&cursor, end, 1);
1065 }
1066 break;
1067
1068 default:
1069 fprintf(stderr, "%s:%d: Token '%s' does not introduce a type\n",
1070 filename, cursor->line, cursor->content);
1071 exit(1);
1072 }
1073
1074 /* Handle elements that are optional */
1075 if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL ||
1076 cursor->token_type == DIRECTIVE_DEFAULT)
1077 ) {
1078 cursor++;
1079 top->flags |= ELEMENT_SKIPPABLE;
1080 }
1081
1082 if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) {
1083 cursor++;
1084 if (cursor >= end)
1085 goto overrun_error;
1086 if (cursor->token_type != TOKEN_ELEMENT_NAME) {
1087 fprintf(stderr, "%s:%d: Token '%s' is not an action function name\n",
1088 filename, cursor->line, cursor->content);
1089 exit(1);
1090 }
1091
1092 action = malloc(sizeof(struct action));
1093 if (!action) {
1094 perror(NULL);
1095 exit(1);
1096 }
1097 action->index = 0;
1098 action->name = cursor->content;
1099
1100 for (ppaction = &action_list;
1101 *ppaction;
1102 ppaction = &(*ppaction)->next
1103 ) {
1104 int cmp = strcmp(action->name, (*ppaction)->name);
1105 if (cmp == 0) {
1106 free(action);
1107 action = *ppaction;
1108 goto found;
1109 }
1110 if (cmp < 0) {
1111 action->next = *ppaction;
1112 *ppaction = action;
1113 nr_actions++;
1114 goto found;
1115 }
1116 }
1117 action->next = NULL;
1118 *ppaction = action;
1119 nr_actions++;
1120 found:
1121
1122 element->action = action;
1123 cursor->action = action;
1124 cursor++;
1125 if (cursor >= end)
1126 goto overrun_error;
1127 if (cursor->token_type != TOKEN_CLOSE_ACTION) {
1128 fprintf(stderr, "%s:%d: Missing close action, got '%s'\n",
1129 filename, cursor->line, cursor->content);
1130 exit(1);
1131 }
1132 cursor++;
1133 }
1134
1135 *_cursor = cursor;
1136 return top;
1137
1138parse_error:
1139 fprintf(stderr, "%s:%d: Unexpected token '%s'\n",
1140 filename, cursor->line, cursor->content);
1141 exit(1);
1142
1143overrun_error:
1144 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1145 exit(1);
1146}
1147
1148/*
1149 * Parse a compound type list
1150 */
1151static struct element *parse_compound(struct token **_cursor, struct token *end,
1152 int alternates)
1153{
1154 struct element *children, **child_p = &children, *element;
1155 struct token *cursor = *_cursor, *name;
1156
1157 if (cursor->token_type != TOKEN_OPEN_CURLY) {
1158 fprintf(stderr, "%s:%d: Expected compound to start with brace not '%s'\n",
1159 filename, cursor->line, cursor->content);
1160 exit(1);
1161 }
1162 cursor++;
1163 if (cursor >= end)
1164 goto overrun_error;
1165
1166 if (cursor->token_type == TOKEN_OPEN_CURLY) {
1167 fprintf(stderr, "%s:%d: Empty compound\n",
1168 filename, cursor->line);
1169 exit(1);
1170 }
1171
1172 for (;;) {
1173 name = NULL;
1174 if (cursor->token_type == TOKEN_ELEMENT_NAME) {
1175 name = cursor;
1176 cursor++;
1177 if (cursor >= end)
1178 goto overrun_error;
1179 }
1180
1181 element = parse_type(&cursor, end, name);
1182 if (alternates)
1183 element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL;
1184
1185 *child_p = element;
1186 child_p = &element->next;
1187
1188 if (cursor >= end)
1189 goto overrun_error;
1190 if (cursor->token_type != TOKEN_COMMA)
1191 break;
1192 cursor++;
1193 if (cursor >= end)
1194 goto overrun_error;
1195 }
1196
1197 children->flags &= ~ELEMENT_CONDITIONAL;
1198
1199 if (cursor->token_type != TOKEN_CLOSE_CURLY) {
1200 fprintf(stderr, "%s:%d: Expected compound closure, got '%s'\n",
1201 filename, cursor->line, cursor->content);
1202 exit(1);
1203 }
1204 cursor++;
1205
1206 *_cursor = cursor;
1207 return children;
1208
1209overrun_error:
1210 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1211 exit(1);
1212}
1213
1214static void dump_element(const struct element *e, int level)
1215{
1216 const struct element *c;
1217 const struct type *t = e->type_def;
1218 const char *name = e->name ? e->name->content : ".";
1219 const char *tname = t && t->name ? t->name->content : ".";
1220 char tag[32];
1221
1222 if (e->class == 0 && e->method == 0 && e->tag == 0)
1223 strcpy(tag, "<...>");
1224 else if (e->class == ASN1_UNIV)
1225 sprintf(tag, "%s %s %s",
1226 asn1_classes[e->class],
1227 asn1_methods[e->method],
1228 asn1_universal_tags[e->tag]);
1229 else
1230 sprintf(tag, "%s %s %u",
1231 asn1_classes[e->class],
1232 asn1_methods[e->method],
1233 e->tag);
1234
1235 printf("%c%c%c%c%c %c %*s[*] \e[33m%s\e[m %s %s \e[35m%s\e[m\n",
1236 e->flags & ELEMENT_IMPLICIT ? 'I' : '-',
1237 e->flags & ELEMENT_EXPLICIT ? 'E' : '-',
1238 e->flags & ELEMENT_TAG_SPECIFIED ? 'T' : '-',
1239 e->flags & ELEMENT_SKIPPABLE ? 'S' : '-',
1240 e->flags & ELEMENT_CONDITIONAL ? 'C' : '-',
1241 "-tTqQcaro"[e->compound],
1242 level, "",
1243 tag,
1244 tname,
1245 name,
1246 e->action ? e->action->name : "");
1247 if (e->compound == TYPE_REF)
1248 dump_element(e->type->type->element, level + 3);
1249 else
1250 for (c = e->children; c; c = c->next)
1251 dump_element(c, level + 3);
1252}
1253
1254static void dump_elements(void)
1255{
1256 if (debug_opt)
1257 dump_element(type_list[0].element, 0);
1258}
1259
1260static void render_element(FILE *out, struct element *e, struct element *tag);
1261static void render_out_of_line_list(FILE *out);
1262
1263static int nr_entries;
1264static int render_depth = 1;
1265static struct element *render_list, **render_list_p = &render_list;
1266
1267__attribute__((format(printf, 2, 3)))
1268static void render_opcode(FILE *out, const char *fmt, ...)
1269{
1270 va_list va;
1271
1272 if (out) {
1273 fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, "");
1274 va_start(va, fmt);
1275 vfprintf(out, fmt, va);
1276 va_end(va);
1277 }
1278 nr_entries++;
1279}
1280
1281__attribute__((format(printf, 2, 3)))
1282static void render_more(FILE *out, const char *fmt, ...)
1283{
1284 va_list va;
1285
1286 if (out) {
1287 va_start(va, fmt);
1288 vfprintf(out, fmt, va);
1289 va_end(va);
1290 }
1291}
1292
1293/*
1294 * Render the grammar into a state machine definition.
1295 */
1296static void render(FILE *out, FILE *hdr)
1297{
1298 struct element *e;
1299 struct action *action;
1300 struct type *root;
1301 int index;
1302
1303 fprintf(hdr, "/*\n");
1304 fprintf(hdr, " * Automatically generated by asn1_compiler. Do not edit\n");
1305 fprintf(hdr, " *\n");
1306 fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name);
1307 fprintf(hdr, " */\n");
1308 fprintf(hdr, "#include <linux/asn1_decoder.h>\n");
1309 fprintf(hdr, "\n");
1310 fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name);
1311 if (ferror(hdr)) {
1312 perror(headername);
1313 exit(1);
1314 }
1315
1316 fprintf(out, "/*\n");
1317 fprintf(out, " * Automatically generated by asn1_compiler. Do not edit\n");
1318 fprintf(out, " *\n");
1319 fprintf(out, " * ASN.1 parser for %s\n", grammar_name);
1320 fprintf(out, " */\n");
1321 fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n");
1322 fprintf(out, "#include \"%s.asn1.h\"\n", grammar_name);
1323 fprintf(out, "\n");
1324 if (ferror(out)) {
1325 perror(outputname);
1326 exit(1);
1327 }
1328
1329 /* Tabulate the action functions we might have to call */
1330 fprintf(hdr, "\n");
1331 index = 0;
1332 for (action = action_list; action; action = action->next) {
1333 action->index = index++;
1334 fprintf(hdr,
1335 "extern int %s(void *, size_t, unsigned char,"
1336 " const void *, size_t);\n",
1337 action->name);
1338 }
1339 fprintf(hdr, "\n");
1340
1341 fprintf(out, "enum %s_actions {\n", grammar_name);
1342 for (action = action_list; action; action = action->next)
1343 fprintf(out, "\tACT_%s = %u,\n",
1344 action->name, action->index);
1345 fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions);
1346 fprintf(out, "};\n");
1347
1348 fprintf(out, "\n");
1349 fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n",
1350 grammar_name, grammar_name);
1351 for (action = action_list; action; action = action->next)
1352 fprintf(out, "\t[%4u] = %s,\n", action->index, action->name);
1353 fprintf(out, "};\n");
1354
1355 if (ferror(out)) {
1356 perror(outputname);
1357 exit(1);
1358 }
1359
1360 /* We do two passes - the first one calculates all the offsets */
1361 verbose("Pass 1\n");
1362 nr_entries = 0;
1363 root = &type_list[0];
1364 render_element(NULL, root->element, NULL);
1365 render_opcode(NULL, "ASN1_OP_COMPLETE,\n");
1366 render_out_of_line_list(NULL);
1367
1368 for (e = element_list; e; e = e->list_next)
1369 e->flags &= ~ELEMENT_RENDERED;
1370
1371 /* And then we actually render */
1372 verbose("Pass 2\n");
1373 fprintf(out, "\n");
1374 fprintf(out, "static const unsigned char %s_machine[] = {\n",
1375 grammar_name);
1376
1377 nr_entries = 0;
1378 root = &type_list[0];
1379 render_element(out, root->element, NULL);
1380 render_opcode(out, "ASN1_OP_COMPLETE,\n");
1381 render_out_of_line_list(out);
1382
1383 fprintf(out, "};\n");
1384
1385 fprintf(out, "\n");
1386 fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name);
1387 fprintf(out, "\t.machine = %s_machine,\n", grammar_name);
1388 fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name);
1389 fprintf(out, "\t.actions = %s_action_table,\n", grammar_name);
1390 fprintf(out, "};\n");
1391}
1392
1393/*
1394 * Render the out-of-line elements
1395 */
1396static void render_out_of_line_list(FILE *out)
1397{
1398 struct element *e, *ce;
1399 const char *act;
1400 int entry;
1401
1402 while ((e = render_list)) {
1403 render_list = e->render_next;
1404 if (!render_list)
1405 render_list_p = &render_list;
1406
1407 render_more(out, "\n");
1408 e->entry_index = entry = nr_entries;
1409 render_depth++;
1410 for (ce = e->children; ce; ce = ce->next)
1411 render_element(out, ce, NULL);
1412 render_depth--;
1413
1414 act = e->action ? "_ACT" : "";
1415 switch (e->compound) {
1416 case SEQUENCE:
1417 render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1418 break;
1419 case SEQUENCE_OF:
1420 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1421 render_opcode(out, "_jump_target(%u),\n", entry);
1422 break;
1423 case SET:
1424 render_opcode(out, "ASN1_OP_END_SET%s,\n", act);
1425 break;
1426 case SET_OF:
1427 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1428 render_opcode(out, "_jump_target(%u),\n", entry);
1429 break;
1430 default:
1431 break;
1432 }
1433 if (e->action)
1434 render_opcode(out, "_action(ACT_%s),\n",
1435 e->action->name);
1436 render_opcode(out, "ASN1_OP_RETURN,\n");
1437 }
1438}
1439
1440/*
1441 * Render an element.
1442 */
1443static void render_element(FILE *out, struct element *e, struct element *tag)
1444{
1445 struct element *ec, *x;
1446 const char *cond, *act;
1447 int entry, skippable = 0, outofline = 0;
1448
1449 if (e->flags & ELEMENT_SKIPPABLE ||
1450 (tag && tag->flags & ELEMENT_SKIPPABLE))
1451 skippable = 1;
1452
1453 if ((e->type_def && e->type_def->ref_count > 1) ||
1454 skippable)
1455 outofline = 1;
1456
1457 if (e->type_def && out) {
1458 render_more(out, "\t// %s\n", e->type_def->name->content);
1459 }
1460
1461 /* Render the operation */
1462 cond = (e->flags & ELEMENT_CONDITIONAL ||
1463 (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : "";
1464 act = e->action ? "_ACT" : "";
1465 switch (e->compound) {
1466 case ANY:
1467 render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,",
1468 cond, act, skippable ? "_OR_SKIP" : "");
1469 if (e->name)
1470 render_more(out, "\t\t// %s", e->name->content);
1471 render_more(out, "\n");
1472 goto dont_render_tag;
1473
1474 case TAG_OVERRIDE:
1475 render_element(out, e->children, e);
1476 return;
1477
1478 case SEQUENCE:
1479 case SEQUENCE_OF:
1480 case SET:
1481 case SET_OF:
1482 render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1483 cond,
1484 outofline ? "_JUMP" : "",
1485 skippable ? "_OR_SKIP" : "");
1486 break;
1487
1488 case CHOICE:
1489 goto dont_render_tag;
1490
1491 case TYPE_REF:
1492 if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0)
1493 goto dont_render_tag;
1494 default:
1495 render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1496 cond, act,
1497 skippable ? "_OR_SKIP" : "");
1498 break;
1499 }
1500
1501 x = tag ?: e;
1502 if (x->name)
1503 render_more(out, "\t\t// %s", x->name->content);
1504 render_more(out, "\n");
1505
1506 /* Render the tag */
1507 if (!tag || !(tag->flags & ELEMENT_TAG_SPECIFIED))
1508 tag = e;
1509
1510 if (tag->class == ASN1_UNIV &&
1511 tag->tag != 14 &&
1512 tag->tag != 15 &&
1513 tag->tag != 31)
1514 render_opcode(out, "_tag(%s, %s, %s),\n",
1515 asn1_classes[tag->class],
1516 asn1_methods[tag->method | e->method],
1517 asn1_universal_tags[tag->tag]);
1518 else
1519 render_opcode(out, "_tagn(%s, %s, %2u),\n",
1520 asn1_classes[tag->class],
1521 asn1_methods[tag->method | e->method],
1522 tag->tag);
1523 tag = NULL;
1524dont_render_tag:
1525
1526 /* Deal with compound types */
1527 switch (e->compound) {
1528 case TYPE_REF:
1529 render_element(out, e->type->type->element, tag);
1530 if (e->action)
1531 render_opcode(out, "ASN1_OP_%sACT,\n",
1532 skippable ? "MAYBE_" : "");
1533 break;
1534
1535 case SEQUENCE:
1536 if (outofline) {
1537 /* Render out-of-line for multiple use or
1538 * skipability */
1539 render_opcode(out, "_jump_target(%u),", e->entry_index);
1540 if (e->type_def && e->type_def->name)
1541 render_more(out, "\t\t// --> %s",
1542 e->type_def->name->content);
1543 render_more(out, "\n");
1544 if (!(e->flags & ELEMENT_RENDERED)) {
1545 e->flags |= ELEMENT_RENDERED;
1546 *render_list_p = e;
1547 render_list_p = &e->render_next;
1548 }
1549 return;
1550 } else {
1551 /* Render inline for single use */
1552 render_depth++;
1553 for (ec = e->children; ec; ec = ec->next)
1554 render_element(out, ec, NULL);
1555 render_depth--;
1556 render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1557 }
1558 break;
1559
1560 case SEQUENCE_OF:
1561 case SET_OF:
1562 if (outofline) {
1563 /* Render out-of-line for multiple use or
1564 * skipability */
1565 render_opcode(out, "_jump_target(%u),", e->entry_index);
1566 if (e->type_def && e->type_def->name)
1567 render_more(out, "\t\t// --> %s",
1568 e->type_def->name->content);
1569 render_more(out, "\n");
1570 if (!(e->flags & ELEMENT_RENDERED)) {
1571 e->flags |= ELEMENT_RENDERED;
1572 *render_list_p = e;
1573 render_list_p = &e->render_next;
1574 }
1575 return;
1576 } else {
1577 /* Render inline for single use */
1578 entry = nr_entries;
1579 render_depth++;
1580 render_element(out, e->children, NULL);
1581 render_depth--;
1582 if (e->compound == SEQUENCE_OF)
1583 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1584 else
1585 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1586 render_opcode(out, "_jump_target(%u),\n", entry);
1587 }
1588 break;
1589
1590 case SET:
1591 /* I can't think of a nice way to do SET support without having
1592 * a stack of bitmasks to make sure no element is repeated.
1593 * The bitmask has also to be checked that no non-optional
1594 * elements are left out whilst not preventing optional
1595 * elements from being left out.
1596 */
1597 fprintf(stderr, "The ASN.1 SET type is not currently supported.\n");
1598 exit(1);
1599
1600 case CHOICE:
1601 for (ec = e->children; ec; ec = ec->next)
1602 render_element(out, ec, ec);
1603 if (!skippable)
1604 render_opcode(out, "ASN1_OP_COND_FAIL,\n");
1605 if (e->action)
1606 render_opcode(out, "ASN1_OP_ACT,\n");
1607 break;
1608
1609 default:
1610 break;
1611 }
1612
1613 if (e->action)
1614 render_opcode(out, "_action(ACT_%s),\n", e->action->name);
1615}
1// SPDX-License-Identifier: GPL-2.0-or-later
2/* Simplified ASN.1 notation parser
3 *
4 * Copyright (C) 2012 Red Hat, Inc. All Rights Reserved.
5 * Written by David Howells (dhowells@redhat.com)
6 */
7
8#include <stdarg.h>
9#include <stdio.h>
10#include <stdlib.h>
11#include <stdint.h>
12#include <stdbool.h>
13#include <string.h>
14#include <ctype.h>
15#include <unistd.h>
16#include <fcntl.h>
17#include <sys/stat.h>
18#include <linux/asn1_ber_bytecode.h>
19
20enum token_type {
21 DIRECTIVE_ABSENT,
22 DIRECTIVE_ALL,
23 DIRECTIVE_ANY,
24 DIRECTIVE_APPLICATION,
25 DIRECTIVE_AUTOMATIC,
26 DIRECTIVE_BEGIN,
27 DIRECTIVE_BIT,
28 DIRECTIVE_BMPString,
29 DIRECTIVE_BOOLEAN,
30 DIRECTIVE_BY,
31 DIRECTIVE_CHARACTER,
32 DIRECTIVE_CHOICE,
33 DIRECTIVE_CLASS,
34 DIRECTIVE_COMPONENT,
35 DIRECTIVE_COMPONENTS,
36 DIRECTIVE_CONSTRAINED,
37 DIRECTIVE_CONTAINING,
38 DIRECTIVE_DEFAULT,
39 DIRECTIVE_DEFINED,
40 DIRECTIVE_DEFINITIONS,
41 DIRECTIVE_EMBEDDED,
42 DIRECTIVE_ENCODED,
43 DIRECTIVE_ENCODING_CONTROL,
44 DIRECTIVE_END,
45 DIRECTIVE_ENUMERATED,
46 DIRECTIVE_EXCEPT,
47 DIRECTIVE_EXPLICIT,
48 DIRECTIVE_EXPORTS,
49 DIRECTIVE_EXTENSIBILITY,
50 DIRECTIVE_EXTERNAL,
51 DIRECTIVE_FALSE,
52 DIRECTIVE_FROM,
53 DIRECTIVE_GeneralString,
54 DIRECTIVE_GeneralizedTime,
55 DIRECTIVE_GraphicString,
56 DIRECTIVE_IA5String,
57 DIRECTIVE_IDENTIFIER,
58 DIRECTIVE_IMPLICIT,
59 DIRECTIVE_IMPLIED,
60 DIRECTIVE_IMPORTS,
61 DIRECTIVE_INCLUDES,
62 DIRECTIVE_INSTANCE,
63 DIRECTIVE_INSTRUCTIONS,
64 DIRECTIVE_INTEGER,
65 DIRECTIVE_INTERSECTION,
66 DIRECTIVE_ISO646String,
67 DIRECTIVE_MAX,
68 DIRECTIVE_MIN,
69 DIRECTIVE_MINUS_INFINITY,
70 DIRECTIVE_NULL,
71 DIRECTIVE_NumericString,
72 DIRECTIVE_OBJECT,
73 DIRECTIVE_OCTET,
74 DIRECTIVE_OF,
75 DIRECTIVE_OPTIONAL,
76 DIRECTIVE_ObjectDescriptor,
77 DIRECTIVE_PATTERN,
78 DIRECTIVE_PDV,
79 DIRECTIVE_PLUS_INFINITY,
80 DIRECTIVE_PRESENT,
81 DIRECTIVE_PRIVATE,
82 DIRECTIVE_PrintableString,
83 DIRECTIVE_REAL,
84 DIRECTIVE_RELATIVE_OID,
85 DIRECTIVE_SEQUENCE,
86 DIRECTIVE_SET,
87 DIRECTIVE_SIZE,
88 DIRECTIVE_STRING,
89 DIRECTIVE_SYNTAX,
90 DIRECTIVE_T61String,
91 DIRECTIVE_TAGS,
92 DIRECTIVE_TRUE,
93 DIRECTIVE_TeletexString,
94 DIRECTIVE_UNION,
95 DIRECTIVE_UNIQUE,
96 DIRECTIVE_UNIVERSAL,
97 DIRECTIVE_UTCTime,
98 DIRECTIVE_UTF8String,
99 DIRECTIVE_UniversalString,
100 DIRECTIVE_VideotexString,
101 DIRECTIVE_VisibleString,
102 DIRECTIVE_WITH,
103 NR__DIRECTIVES,
104 TOKEN_ASSIGNMENT = NR__DIRECTIVES,
105 TOKEN_OPEN_CURLY,
106 TOKEN_CLOSE_CURLY,
107 TOKEN_OPEN_SQUARE,
108 TOKEN_CLOSE_SQUARE,
109 TOKEN_OPEN_ACTION,
110 TOKEN_CLOSE_ACTION,
111 TOKEN_COMMA,
112 TOKEN_NUMBER,
113 TOKEN_TYPE_NAME,
114 TOKEN_ELEMENT_NAME,
115 NR__TOKENS
116};
117
118static const unsigned char token_to_tag[NR__TOKENS] = {
119 /* EOC goes first */
120 [DIRECTIVE_BOOLEAN] = ASN1_BOOL,
121 [DIRECTIVE_INTEGER] = ASN1_INT,
122 [DIRECTIVE_BIT] = ASN1_BTS,
123 [DIRECTIVE_OCTET] = ASN1_OTS,
124 [DIRECTIVE_NULL] = ASN1_NULL,
125 [DIRECTIVE_OBJECT] = ASN1_OID,
126 [DIRECTIVE_ObjectDescriptor] = ASN1_ODE,
127 [DIRECTIVE_EXTERNAL] = ASN1_EXT,
128 [DIRECTIVE_REAL] = ASN1_REAL,
129 [DIRECTIVE_ENUMERATED] = ASN1_ENUM,
130 [DIRECTIVE_EMBEDDED] = 0,
131 [DIRECTIVE_UTF8String] = ASN1_UTF8STR,
132 [DIRECTIVE_RELATIVE_OID] = ASN1_RELOID,
133 /* 14 */
134 /* 15 */
135 [DIRECTIVE_SEQUENCE] = ASN1_SEQ,
136 [DIRECTIVE_SET] = ASN1_SET,
137 [DIRECTIVE_NumericString] = ASN1_NUMSTR,
138 [DIRECTIVE_PrintableString] = ASN1_PRNSTR,
139 [DIRECTIVE_T61String] = ASN1_TEXSTR,
140 [DIRECTIVE_TeletexString] = ASN1_TEXSTR,
141 [DIRECTIVE_VideotexString] = ASN1_VIDSTR,
142 [DIRECTIVE_IA5String] = ASN1_IA5STR,
143 [DIRECTIVE_UTCTime] = ASN1_UNITIM,
144 [DIRECTIVE_GeneralizedTime] = ASN1_GENTIM,
145 [DIRECTIVE_GraphicString] = ASN1_GRASTR,
146 [DIRECTIVE_VisibleString] = ASN1_VISSTR,
147 [DIRECTIVE_GeneralString] = ASN1_GENSTR,
148 [DIRECTIVE_UniversalString] = ASN1_UNITIM,
149 [DIRECTIVE_CHARACTER] = ASN1_CHRSTR,
150 [DIRECTIVE_BMPString] = ASN1_BMPSTR,
151};
152
153static const char asn1_classes[4][5] = {
154 [ASN1_UNIV] = "UNIV",
155 [ASN1_APPL] = "APPL",
156 [ASN1_CONT] = "CONT",
157 [ASN1_PRIV] = "PRIV"
158};
159
160static const char asn1_methods[2][5] = {
161 [ASN1_UNIV] = "PRIM",
162 [ASN1_APPL] = "CONS"
163};
164
165static const char *const asn1_universal_tags[32] = {
166 "EOC",
167 "BOOL",
168 "INT",
169 "BTS",
170 "OTS",
171 "NULL",
172 "OID",
173 "ODE",
174 "EXT",
175 "REAL",
176 "ENUM",
177 "EPDV",
178 "UTF8STR",
179 "RELOID",
180 NULL, /* 14 */
181 NULL, /* 15 */
182 "SEQ",
183 "SET",
184 "NUMSTR",
185 "PRNSTR",
186 "TEXSTR",
187 "VIDSTR",
188 "IA5STR",
189 "UNITIM",
190 "GENTIM",
191 "GRASTR",
192 "VISSTR",
193 "GENSTR",
194 "UNISTR",
195 "CHRSTR",
196 "BMPSTR",
197 NULL /* 31 */
198};
199
200static const char *filename;
201static const char *grammar_name;
202static const char *outputname;
203static const char *headername;
204
205static const char *const directives[NR__DIRECTIVES] = {
206#define _(X) [DIRECTIVE_##X] = #X
207 _(ABSENT),
208 _(ALL),
209 _(ANY),
210 _(APPLICATION),
211 _(AUTOMATIC),
212 _(BEGIN),
213 _(BIT),
214 _(BMPString),
215 _(BOOLEAN),
216 _(BY),
217 _(CHARACTER),
218 _(CHOICE),
219 _(CLASS),
220 _(COMPONENT),
221 _(COMPONENTS),
222 _(CONSTRAINED),
223 _(CONTAINING),
224 _(DEFAULT),
225 _(DEFINED),
226 _(DEFINITIONS),
227 _(EMBEDDED),
228 _(ENCODED),
229 [DIRECTIVE_ENCODING_CONTROL] = "ENCODING-CONTROL",
230 _(END),
231 _(ENUMERATED),
232 _(EXCEPT),
233 _(EXPLICIT),
234 _(EXPORTS),
235 _(EXTENSIBILITY),
236 _(EXTERNAL),
237 _(FALSE),
238 _(FROM),
239 _(GeneralString),
240 _(GeneralizedTime),
241 _(GraphicString),
242 _(IA5String),
243 _(IDENTIFIER),
244 _(IMPLICIT),
245 _(IMPLIED),
246 _(IMPORTS),
247 _(INCLUDES),
248 _(INSTANCE),
249 _(INSTRUCTIONS),
250 _(INTEGER),
251 _(INTERSECTION),
252 _(ISO646String),
253 _(MAX),
254 _(MIN),
255 [DIRECTIVE_MINUS_INFINITY] = "MINUS-INFINITY",
256 [DIRECTIVE_NULL] = "NULL",
257 _(NumericString),
258 _(OBJECT),
259 _(OCTET),
260 _(OF),
261 _(OPTIONAL),
262 _(ObjectDescriptor),
263 _(PATTERN),
264 _(PDV),
265 [DIRECTIVE_PLUS_INFINITY] = "PLUS-INFINITY",
266 _(PRESENT),
267 _(PRIVATE),
268 _(PrintableString),
269 _(REAL),
270 [DIRECTIVE_RELATIVE_OID] = "RELATIVE-OID",
271 _(SEQUENCE),
272 _(SET),
273 _(SIZE),
274 _(STRING),
275 _(SYNTAX),
276 _(T61String),
277 _(TAGS),
278 _(TRUE),
279 _(TeletexString),
280 _(UNION),
281 _(UNIQUE),
282 _(UNIVERSAL),
283 _(UTCTime),
284 _(UTF8String),
285 _(UniversalString),
286 _(VideotexString),
287 _(VisibleString),
288 _(WITH)
289};
290
291struct action {
292 struct action *next;
293 char *name;
294 unsigned char index;
295};
296
297static struct action *action_list;
298static unsigned nr_actions;
299
300struct token {
301 unsigned short line;
302 enum token_type token_type : 8;
303 unsigned char size;
304 struct action *action;
305 char *content;
306 struct type *type;
307};
308
309static struct token *token_list;
310static unsigned nr_tokens;
311static bool verbose_opt;
312static bool debug_opt;
313
314#define verbose(fmt, ...) do { if (verbose_opt) printf(fmt, ## __VA_ARGS__); } while (0)
315#define debug(fmt, ...) do { if (debug_opt) printf(fmt, ## __VA_ARGS__); } while (0)
316
317static int directive_compare(const void *_key, const void *_pdir)
318{
319 const struct token *token = _key;
320 const char *const *pdir = _pdir, *dir = *pdir;
321 size_t dlen, clen;
322 int val;
323
324 dlen = strlen(dir);
325 clen = (dlen < token->size) ? dlen : token->size;
326
327 //debug("cmp(%s,%s) = ", token->content, dir);
328
329 val = memcmp(token->content, dir, clen);
330 if (val != 0) {
331 //debug("%d [cmp]\n", val);
332 return val;
333 }
334
335 if (dlen == token->size) {
336 //debug("0\n");
337 return 0;
338 }
339 //debug("%d\n", (int)dlen - (int)token->size);
340 return dlen - token->size; /* shorter -> negative */
341}
342
343/*
344 * Tokenise an ASN.1 grammar
345 */
346static void tokenise(char *buffer, char *end)
347{
348 struct token *tokens;
349 char *line, *nl, *start, *p, *q;
350 unsigned tix, lineno;
351
352 /* Assume we're going to have half as many tokens as we have
353 * characters
354 */
355 token_list = tokens = calloc((end - buffer) / 2, sizeof(struct token));
356 if (!tokens) {
357 perror(NULL);
358 exit(1);
359 }
360 tix = 0;
361
362 lineno = 0;
363 while (buffer < end) {
364 /* First of all, break out a line */
365 lineno++;
366 line = buffer;
367 nl = memchr(line, '\n', end - buffer);
368 if (!nl) {
369 buffer = nl = end;
370 } else {
371 buffer = nl + 1;
372 *nl = '\0';
373 }
374
375 /* Remove "--" comments */
376 p = line;
377 next_comment:
378 while ((p = memchr(p, '-', nl - p))) {
379 if (p[1] == '-') {
380 /* Found a comment; see if there's a terminator */
381 q = p + 2;
382 while ((q = memchr(q, '-', nl - q))) {
383 if (q[1] == '-') {
384 /* There is - excise the comment */
385 q += 2;
386 memmove(p, q, nl - q);
387 goto next_comment;
388 }
389 q++;
390 }
391 *p = '\0';
392 nl = p;
393 break;
394 } else {
395 p++;
396 }
397 }
398
399 p = line;
400 while (p < nl) {
401 /* Skip white space */
402 while (p < nl && isspace(*p))
403 *(p++) = 0;
404 if (p >= nl)
405 break;
406
407 tokens[tix].line = lineno;
408 start = p;
409
410 /* Handle string tokens */
411 if (isalpha(*p)) {
412 const char **dir;
413
414 /* Can be a directive, type name or element
415 * name. Find the end of the name.
416 */
417 q = p + 1;
418 while (q < nl && (isalnum(*q) || *q == '-' || *q == '_'))
419 q++;
420 tokens[tix].size = q - p;
421 p = q;
422
423 tokens[tix].content = malloc(tokens[tix].size + 1);
424 if (!tokens[tix].content) {
425 perror(NULL);
426 exit(1);
427 }
428 memcpy(tokens[tix].content, start, tokens[tix].size);
429 tokens[tix].content[tokens[tix].size] = 0;
430
431 /* If it begins with a lowercase letter then
432 * it's an element name
433 */
434 if (islower(tokens[tix].content[0])) {
435 tokens[tix++].token_type = TOKEN_ELEMENT_NAME;
436 continue;
437 }
438
439 /* Otherwise we need to search the directive
440 * table
441 */
442 dir = bsearch(&tokens[tix], directives,
443 sizeof(directives) / sizeof(directives[1]),
444 sizeof(directives[1]),
445 directive_compare);
446 if (dir) {
447 tokens[tix++].token_type = dir - directives;
448 continue;
449 }
450
451 tokens[tix++].token_type = TOKEN_TYPE_NAME;
452 continue;
453 }
454
455 /* Handle numbers */
456 if (isdigit(*p)) {
457 /* Find the end of the number */
458 q = p + 1;
459 while (q < nl && (isdigit(*q)))
460 q++;
461 tokens[tix].size = q - p;
462 p = q;
463 tokens[tix].content = malloc(tokens[tix].size + 1);
464 if (!tokens[tix].content) {
465 perror(NULL);
466 exit(1);
467 }
468 memcpy(tokens[tix].content, start, tokens[tix].size);
469 tokens[tix].content[tokens[tix].size] = 0;
470 tokens[tix++].token_type = TOKEN_NUMBER;
471 continue;
472 }
473
474 if (nl - p >= 3) {
475 if (memcmp(p, "::=", 3) == 0) {
476 p += 3;
477 tokens[tix].size = 3;
478 tokens[tix].content = "::=";
479 tokens[tix++].token_type = TOKEN_ASSIGNMENT;
480 continue;
481 }
482 }
483
484 if (nl - p >= 2) {
485 if (memcmp(p, "({", 2) == 0) {
486 p += 2;
487 tokens[tix].size = 2;
488 tokens[tix].content = "({";
489 tokens[tix++].token_type = TOKEN_OPEN_ACTION;
490 continue;
491 }
492 if (memcmp(p, "})", 2) == 0) {
493 p += 2;
494 tokens[tix].size = 2;
495 tokens[tix].content = "})";
496 tokens[tix++].token_type = TOKEN_CLOSE_ACTION;
497 continue;
498 }
499 }
500
501 if (nl - p >= 1) {
502 tokens[tix].size = 1;
503 switch (*p) {
504 case '{':
505 p += 1;
506 tokens[tix].content = "{";
507 tokens[tix++].token_type = TOKEN_OPEN_CURLY;
508 continue;
509 case '}':
510 p += 1;
511 tokens[tix].content = "}";
512 tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
513 continue;
514 case '[':
515 p += 1;
516 tokens[tix].content = "[";
517 tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
518 continue;
519 case ']':
520 p += 1;
521 tokens[tix].content = "]";
522 tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
523 continue;
524 case ',':
525 p += 1;
526 tokens[tix].content = ",";
527 tokens[tix++].token_type = TOKEN_COMMA;
528 continue;
529 default:
530 break;
531 }
532 }
533
534 fprintf(stderr, "%s:%u: Unknown character in grammar: '%c'\n",
535 filename, lineno, *p);
536 exit(1);
537 }
538 }
539
540 nr_tokens = tix;
541 verbose("Extracted %u tokens\n", nr_tokens);
542
543#if 0
544 {
545 int n;
546 for (n = 0; n < nr_tokens; n++)
547 debug("Token %3u: '%s'\n", n, token_list[n].content);
548 }
549#endif
550}
551
552static void build_type_list(void);
553static void parse(void);
554static void dump_elements(void);
555static void render(FILE *out, FILE *hdr);
556
557/*
558 *
559 */
560int main(int argc, char **argv)
561{
562 struct stat st;
563 ssize_t readlen;
564 FILE *out, *hdr;
565 char *buffer, *p;
566 char *kbuild_verbose;
567 int fd;
568
569 kbuild_verbose = getenv("KBUILD_VERBOSE");
570 if (kbuild_verbose)
571 verbose_opt = atoi(kbuild_verbose);
572
573 while (argc > 4) {
574 if (strcmp(argv[1], "-v") == 0)
575 verbose_opt = true;
576 else if (strcmp(argv[1], "-d") == 0)
577 debug_opt = true;
578 else
579 break;
580 memmove(&argv[1], &argv[2], (argc - 2) * sizeof(char *));
581 argc--;
582 }
583
584 if (argc != 4) {
585 fprintf(stderr, "Format: %s [-v] [-d] <grammar-file> <c-file> <hdr-file>\n",
586 argv[0]);
587 exit(2);
588 }
589
590 filename = argv[1];
591 outputname = argv[2];
592 headername = argv[3];
593
594 fd = open(filename, O_RDONLY);
595 if (fd < 0) {
596 perror(filename);
597 exit(1);
598 }
599
600 if (fstat(fd, &st) < 0) {
601 perror(filename);
602 exit(1);
603 }
604
605 if (!(buffer = malloc(st.st_size + 1))) {
606 perror(NULL);
607 exit(1);
608 }
609
610 if ((readlen = read(fd, buffer, st.st_size)) < 0) {
611 perror(filename);
612 exit(1);
613 }
614
615 if (close(fd) < 0) {
616 perror(filename);
617 exit(1);
618 }
619
620 if (readlen != st.st_size) {
621 fprintf(stderr, "%s: Short read\n", filename);
622 exit(1);
623 }
624
625 p = strrchr(argv[1], '/');
626 p = p ? p + 1 : argv[1];
627 grammar_name = strdup(p);
628 if (!p) {
629 perror(NULL);
630 exit(1);
631 }
632 p = strchr(grammar_name, '.');
633 if (p)
634 *p = '\0';
635
636 buffer[readlen] = 0;
637 tokenise(buffer, buffer + readlen);
638 build_type_list();
639 parse();
640 dump_elements();
641
642 out = fopen(outputname, "w");
643 if (!out) {
644 perror(outputname);
645 exit(1);
646 }
647
648 hdr = fopen(headername, "w");
649 if (!hdr) {
650 perror(headername);
651 exit(1);
652 }
653
654 render(out, hdr);
655
656 if (fclose(out) < 0) {
657 perror(outputname);
658 exit(1);
659 }
660
661 if (fclose(hdr) < 0) {
662 perror(headername);
663 exit(1);
664 }
665
666 return 0;
667}
668
669enum compound {
670 NOT_COMPOUND,
671 SET,
672 SET_OF,
673 SEQUENCE,
674 SEQUENCE_OF,
675 CHOICE,
676 ANY,
677 TYPE_REF,
678 TAG_OVERRIDE
679};
680
681struct element {
682 struct type *type_def;
683 struct token *name;
684 struct token *type;
685 struct action *action;
686 struct element *children;
687 struct element *next;
688 struct element *render_next;
689 struct element *list_next;
690 uint8_t n_elements;
691 enum compound compound : 8;
692 enum asn1_class class : 8;
693 enum asn1_method method : 8;
694 uint8_t tag;
695 unsigned entry_index;
696 unsigned flags;
697#define ELEMENT_IMPLICIT 0x0001
698#define ELEMENT_EXPLICIT 0x0002
699#define ELEMENT_TAG_SPECIFIED 0x0004
700#define ELEMENT_RENDERED 0x0008
701#define ELEMENT_SKIPPABLE 0x0010
702#define ELEMENT_CONDITIONAL 0x0020
703};
704
705struct type {
706 struct token *name;
707 struct token *def;
708 struct element *element;
709 unsigned ref_count;
710 unsigned flags;
711#define TYPE_STOP_MARKER 0x0001
712#define TYPE_BEGIN 0x0002
713};
714
715static struct type *type_list;
716static struct type **type_index;
717static unsigned nr_types;
718
719static int type_index_compare(const void *_a, const void *_b)
720{
721 const struct type *const *a = _a, *const *b = _b;
722
723 if ((*a)->name->size != (*b)->name->size)
724 return (*a)->name->size - (*b)->name->size;
725 else
726 return memcmp((*a)->name->content, (*b)->name->content,
727 (*a)->name->size);
728}
729
730static int type_finder(const void *_key, const void *_ti)
731{
732 const struct token *token = _key;
733 const struct type *const *ti = _ti;
734 const struct type *type = *ti;
735
736 if (token->size != type->name->size)
737 return token->size - type->name->size;
738 else
739 return memcmp(token->content, type->name->content,
740 token->size);
741}
742
743/*
744 * Build up a list of types and a sorted index to that list.
745 */
746static void build_type_list(void)
747{
748 struct type *types;
749 unsigned nr, t, n;
750
751 nr = 0;
752 for (n = 0; n < nr_tokens - 1; n++)
753 if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
754 token_list[n + 1].token_type == TOKEN_ASSIGNMENT)
755 nr++;
756
757 if (nr == 0) {
758 fprintf(stderr, "%s: No defined types\n", filename);
759 exit(1);
760 }
761
762 nr_types = nr;
763 types = type_list = calloc(nr + 1, sizeof(type_list[0]));
764 if (!type_list) {
765 perror(NULL);
766 exit(1);
767 }
768 type_index = calloc(nr, sizeof(type_index[0]));
769 if (!type_index) {
770 perror(NULL);
771 exit(1);
772 }
773
774 t = 0;
775 types[t].flags |= TYPE_BEGIN;
776 for (n = 0; n < nr_tokens - 1; n++) {
777 if (token_list[n + 0].token_type == TOKEN_TYPE_NAME &&
778 token_list[n + 1].token_type == TOKEN_ASSIGNMENT) {
779 types[t].name = &token_list[n];
780 type_index[t] = &types[t];
781 t++;
782 }
783 }
784 types[t].name = &token_list[n + 1];
785 types[t].flags |= TYPE_STOP_MARKER;
786
787 qsort(type_index, nr, sizeof(type_index[0]), type_index_compare);
788
789 verbose("Extracted %u types\n", nr_types);
790#if 0
791 for (n = 0; n < nr_types; n++) {
792 struct type *type = type_index[n];
793 debug("- %*.*s\n", type->name->content);
794 }
795#endif
796}
797
798static struct element *parse_type(struct token **_cursor, struct token *stop,
799 struct token *name);
800
801/*
802 * Parse the token stream
803 */
804static void parse(void)
805{
806 struct token *cursor;
807 struct type *type;
808
809 /* Parse one type definition statement at a time */
810 type = type_list;
811 do {
812 cursor = type->name;
813
814 if (cursor[0].token_type != TOKEN_TYPE_NAME ||
815 cursor[1].token_type != TOKEN_ASSIGNMENT)
816 abort();
817 cursor += 2;
818
819 type->element = parse_type(&cursor, type[1].name, NULL);
820 type->element->type_def = type;
821
822 if (cursor != type[1].name) {
823 fprintf(stderr, "%s:%d: Parse error at token '%s'\n",
824 filename, cursor->line, cursor->content);
825 exit(1);
826 }
827
828 } while (type++, !(type->flags & TYPE_STOP_MARKER));
829
830 verbose("Extracted %u actions\n", nr_actions);
831}
832
833static struct element *element_list;
834
835static struct element *alloc_elem(void)
836{
837 struct element *e = calloc(1, sizeof(*e));
838 if (!e) {
839 perror(NULL);
840 exit(1);
841 }
842 e->list_next = element_list;
843 element_list = e;
844 return e;
845}
846
847static struct element *parse_compound(struct token **_cursor, struct token *end,
848 int alternates);
849
850/*
851 * Parse one type definition statement
852 */
853static struct element *parse_type(struct token **_cursor, struct token *end,
854 struct token *name)
855{
856 struct element *top, *element;
857 struct action *action, **ppaction;
858 struct token *cursor = *_cursor;
859 struct type **ref;
860 char *p;
861 int labelled = 0, implicit = 0;
862
863 top = element = alloc_elem();
864 element->class = ASN1_UNIV;
865 element->method = ASN1_PRIM;
866 element->tag = token_to_tag[cursor->token_type];
867 element->name = name;
868
869 /* Extract the tag value if one given */
870 if (cursor->token_type == TOKEN_OPEN_SQUARE) {
871 cursor++;
872 if (cursor >= end)
873 goto overrun_error;
874 switch (cursor->token_type) {
875 case DIRECTIVE_UNIVERSAL:
876 element->class = ASN1_UNIV;
877 cursor++;
878 break;
879 case DIRECTIVE_APPLICATION:
880 element->class = ASN1_APPL;
881 cursor++;
882 break;
883 case TOKEN_NUMBER:
884 element->class = ASN1_CONT;
885 break;
886 case DIRECTIVE_PRIVATE:
887 element->class = ASN1_PRIV;
888 cursor++;
889 break;
890 default:
891 fprintf(stderr, "%s:%d: Unrecognised tag class token '%s'\n",
892 filename, cursor->line, cursor->content);
893 exit(1);
894 }
895
896 if (cursor >= end)
897 goto overrun_error;
898 if (cursor->token_type != TOKEN_NUMBER) {
899 fprintf(stderr, "%s:%d: Missing tag number '%s'\n",
900 filename, cursor->line, cursor->content);
901 exit(1);
902 }
903
904 element->tag &= ~0x1f;
905 element->tag |= strtoul(cursor->content, &p, 10);
906 element->flags |= ELEMENT_TAG_SPECIFIED;
907 if (p - cursor->content != cursor->size)
908 abort();
909 cursor++;
910
911 if (cursor >= end)
912 goto overrun_error;
913 if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
914 fprintf(stderr, "%s:%d: Missing closing square bracket '%s'\n",
915 filename, cursor->line, cursor->content);
916 exit(1);
917 }
918 cursor++;
919 if (cursor >= end)
920 goto overrun_error;
921 labelled = 1;
922 }
923
924 /* Handle implicit and explicit markers */
925 if (cursor->token_type == DIRECTIVE_IMPLICIT) {
926 element->flags |= ELEMENT_IMPLICIT;
927 implicit = 1;
928 cursor++;
929 if (cursor >= end)
930 goto overrun_error;
931 } else if (cursor->token_type == DIRECTIVE_EXPLICIT) {
932 element->flags |= ELEMENT_EXPLICIT;
933 cursor++;
934 if (cursor >= end)
935 goto overrun_error;
936 }
937
938 if (labelled) {
939 if (!implicit)
940 element->method |= ASN1_CONS;
941 element->compound = implicit ? TAG_OVERRIDE : SEQUENCE;
942 element->children = alloc_elem();
943 element = element->children;
944 element->class = ASN1_UNIV;
945 element->method = ASN1_PRIM;
946 element->tag = token_to_tag[cursor->token_type];
947 element->name = name;
948 }
949
950 /* Extract the type we're expecting here */
951 element->type = cursor;
952 switch (cursor->token_type) {
953 case DIRECTIVE_ANY:
954 element->compound = ANY;
955 cursor++;
956 break;
957
958 case DIRECTIVE_NULL:
959 case DIRECTIVE_BOOLEAN:
960 case DIRECTIVE_ENUMERATED:
961 case DIRECTIVE_INTEGER:
962 element->compound = NOT_COMPOUND;
963 cursor++;
964 break;
965
966 case DIRECTIVE_EXTERNAL:
967 element->method = ASN1_CONS;
968
969 case DIRECTIVE_BMPString:
970 case DIRECTIVE_GeneralString:
971 case DIRECTIVE_GraphicString:
972 case DIRECTIVE_IA5String:
973 case DIRECTIVE_ISO646String:
974 case DIRECTIVE_NumericString:
975 case DIRECTIVE_PrintableString:
976 case DIRECTIVE_T61String:
977 case DIRECTIVE_TeletexString:
978 case DIRECTIVE_UniversalString:
979 case DIRECTIVE_UTF8String:
980 case DIRECTIVE_VideotexString:
981 case DIRECTIVE_VisibleString:
982 case DIRECTIVE_ObjectDescriptor:
983 case DIRECTIVE_GeneralizedTime:
984 case DIRECTIVE_UTCTime:
985 element->compound = NOT_COMPOUND;
986 cursor++;
987 break;
988
989 case DIRECTIVE_BIT:
990 case DIRECTIVE_OCTET:
991 element->compound = NOT_COMPOUND;
992 cursor++;
993 if (cursor >= end)
994 goto overrun_error;
995 if (cursor->token_type != DIRECTIVE_STRING)
996 goto parse_error;
997 cursor++;
998 break;
999
1000 case DIRECTIVE_OBJECT:
1001 element->compound = NOT_COMPOUND;
1002 cursor++;
1003 if (cursor >= end)
1004 goto overrun_error;
1005 if (cursor->token_type != DIRECTIVE_IDENTIFIER)
1006 goto parse_error;
1007 cursor++;
1008 break;
1009
1010 case TOKEN_TYPE_NAME:
1011 element->compound = TYPE_REF;
1012 ref = bsearch(cursor, type_index, nr_types, sizeof(type_index[0]),
1013 type_finder);
1014 if (!ref) {
1015 fprintf(stderr, "%s:%d: Type '%s' undefined\n",
1016 filename, cursor->line, cursor->content);
1017 exit(1);
1018 }
1019 cursor->type = *ref;
1020 (*ref)->ref_count++;
1021 cursor++;
1022 break;
1023
1024 case DIRECTIVE_CHOICE:
1025 element->compound = CHOICE;
1026 cursor++;
1027 element->children = parse_compound(&cursor, end, 1);
1028 break;
1029
1030 case DIRECTIVE_SEQUENCE:
1031 element->compound = SEQUENCE;
1032 element->method = ASN1_CONS;
1033 cursor++;
1034 if (cursor >= end)
1035 goto overrun_error;
1036 if (cursor->token_type == DIRECTIVE_OF) {
1037 element->compound = SEQUENCE_OF;
1038 cursor++;
1039 if (cursor >= end)
1040 goto overrun_error;
1041 element->children = parse_type(&cursor, end, NULL);
1042 } else {
1043 element->children = parse_compound(&cursor, end, 0);
1044 }
1045 break;
1046
1047 case DIRECTIVE_SET:
1048 element->compound = SET;
1049 element->method = ASN1_CONS;
1050 cursor++;
1051 if (cursor >= end)
1052 goto overrun_error;
1053 if (cursor->token_type == DIRECTIVE_OF) {
1054 element->compound = SET_OF;
1055 cursor++;
1056 if (cursor >= end)
1057 goto parse_error;
1058 element->children = parse_type(&cursor, end, NULL);
1059 } else {
1060 element->children = parse_compound(&cursor, end, 1);
1061 }
1062 break;
1063
1064 default:
1065 fprintf(stderr, "%s:%d: Token '%s' does not introduce a type\n",
1066 filename, cursor->line, cursor->content);
1067 exit(1);
1068 }
1069
1070 /* Handle elements that are optional */
1071 if (cursor < end && (cursor->token_type == DIRECTIVE_OPTIONAL ||
1072 cursor->token_type == DIRECTIVE_DEFAULT)
1073 ) {
1074 cursor++;
1075 top->flags |= ELEMENT_SKIPPABLE;
1076 }
1077
1078 if (cursor < end && cursor->token_type == TOKEN_OPEN_ACTION) {
1079 cursor++;
1080 if (cursor >= end)
1081 goto overrun_error;
1082 if (cursor->token_type != TOKEN_ELEMENT_NAME) {
1083 fprintf(stderr, "%s:%d: Token '%s' is not an action function name\n",
1084 filename, cursor->line, cursor->content);
1085 exit(1);
1086 }
1087
1088 action = malloc(sizeof(struct action));
1089 if (!action) {
1090 perror(NULL);
1091 exit(1);
1092 }
1093 action->index = 0;
1094 action->name = cursor->content;
1095
1096 for (ppaction = &action_list;
1097 *ppaction;
1098 ppaction = &(*ppaction)->next
1099 ) {
1100 int cmp = strcmp(action->name, (*ppaction)->name);
1101 if (cmp == 0) {
1102 free(action);
1103 action = *ppaction;
1104 goto found;
1105 }
1106 if (cmp < 0) {
1107 action->next = *ppaction;
1108 *ppaction = action;
1109 nr_actions++;
1110 goto found;
1111 }
1112 }
1113 action->next = NULL;
1114 *ppaction = action;
1115 nr_actions++;
1116 found:
1117
1118 element->action = action;
1119 cursor->action = action;
1120 cursor++;
1121 if (cursor >= end)
1122 goto overrun_error;
1123 if (cursor->token_type != TOKEN_CLOSE_ACTION) {
1124 fprintf(stderr, "%s:%d: Missing close action, got '%s'\n",
1125 filename, cursor->line, cursor->content);
1126 exit(1);
1127 }
1128 cursor++;
1129 }
1130
1131 *_cursor = cursor;
1132 return top;
1133
1134parse_error:
1135 fprintf(stderr, "%s:%d: Unexpected token '%s'\n",
1136 filename, cursor->line, cursor->content);
1137 exit(1);
1138
1139overrun_error:
1140 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1141 exit(1);
1142}
1143
1144/*
1145 * Parse a compound type list
1146 */
1147static struct element *parse_compound(struct token **_cursor, struct token *end,
1148 int alternates)
1149{
1150 struct element *children, **child_p = &children, *element;
1151 struct token *cursor = *_cursor, *name;
1152
1153 if (cursor->token_type != TOKEN_OPEN_CURLY) {
1154 fprintf(stderr, "%s:%d: Expected compound to start with brace not '%s'\n",
1155 filename, cursor->line, cursor->content);
1156 exit(1);
1157 }
1158 cursor++;
1159 if (cursor >= end)
1160 goto overrun_error;
1161
1162 if (cursor->token_type == TOKEN_OPEN_CURLY) {
1163 fprintf(stderr, "%s:%d: Empty compound\n",
1164 filename, cursor->line);
1165 exit(1);
1166 }
1167
1168 for (;;) {
1169 name = NULL;
1170 if (cursor->token_type == TOKEN_ELEMENT_NAME) {
1171 name = cursor;
1172 cursor++;
1173 if (cursor >= end)
1174 goto overrun_error;
1175 }
1176
1177 element = parse_type(&cursor, end, name);
1178 if (alternates)
1179 element->flags |= ELEMENT_SKIPPABLE | ELEMENT_CONDITIONAL;
1180
1181 *child_p = element;
1182 child_p = &element->next;
1183
1184 if (cursor >= end)
1185 goto overrun_error;
1186 if (cursor->token_type != TOKEN_COMMA)
1187 break;
1188 cursor++;
1189 if (cursor >= end)
1190 goto overrun_error;
1191 }
1192
1193 children->flags &= ~ELEMENT_CONDITIONAL;
1194
1195 if (cursor->token_type != TOKEN_CLOSE_CURLY) {
1196 fprintf(stderr, "%s:%d: Expected compound closure, got '%s'\n",
1197 filename, cursor->line, cursor->content);
1198 exit(1);
1199 }
1200 cursor++;
1201
1202 *_cursor = cursor;
1203 return children;
1204
1205overrun_error:
1206 fprintf(stderr, "%s: Unexpectedly hit EOF\n", filename);
1207 exit(1);
1208}
1209
1210static void dump_element(const struct element *e, int level)
1211{
1212 const struct element *c;
1213 const struct type *t = e->type_def;
1214 const char *name = e->name ? e->name->content : ".";
1215 const char *tname = t && t->name ? t->name->content : ".";
1216 char tag[32];
1217
1218 if (e->class == 0 && e->method == 0 && e->tag == 0)
1219 strcpy(tag, "<...>");
1220 else if (e->class == ASN1_UNIV)
1221 sprintf(tag, "%s %s %s",
1222 asn1_classes[e->class],
1223 asn1_methods[e->method],
1224 asn1_universal_tags[e->tag]);
1225 else
1226 sprintf(tag, "%s %s %u",
1227 asn1_classes[e->class],
1228 asn1_methods[e->method],
1229 e->tag);
1230
1231 printf("%c%c%c%c%c %c %*s[*] \e[33m%s\e[m %s %s \e[35m%s\e[m\n",
1232 e->flags & ELEMENT_IMPLICIT ? 'I' : '-',
1233 e->flags & ELEMENT_EXPLICIT ? 'E' : '-',
1234 e->flags & ELEMENT_TAG_SPECIFIED ? 'T' : '-',
1235 e->flags & ELEMENT_SKIPPABLE ? 'S' : '-',
1236 e->flags & ELEMENT_CONDITIONAL ? 'C' : '-',
1237 "-tTqQcaro"[e->compound],
1238 level, "",
1239 tag,
1240 tname,
1241 name,
1242 e->action ? e->action->name : "");
1243 if (e->compound == TYPE_REF)
1244 dump_element(e->type->type->element, level + 3);
1245 else
1246 for (c = e->children; c; c = c->next)
1247 dump_element(c, level + 3);
1248}
1249
1250static void dump_elements(void)
1251{
1252 if (debug_opt)
1253 dump_element(type_list[0].element, 0);
1254}
1255
1256static void render_element(FILE *out, struct element *e, struct element *tag);
1257static void render_out_of_line_list(FILE *out);
1258
1259static int nr_entries;
1260static int render_depth = 1;
1261static struct element *render_list, **render_list_p = &render_list;
1262
1263__attribute__((format(printf, 2, 3)))
1264static void render_opcode(FILE *out, const char *fmt, ...)
1265{
1266 va_list va;
1267
1268 if (out) {
1269 fprintf(out, "\t[%4d] =%*s", nr_entries, render_depth, "");
1270 va_start(va, fmt);
1271 vfprintf(out, fmt, va);
1272 va_end(va);
1273 }
1274 nr_entries++;
1275}
1276
1277__attribute__((format(printf, 2, 3)))
1278static void render_more(FILE *out, const char *fmt, ...)
1279{
1280 va_list va;
1281
1282 if (out) {
1283 va_start(va, fmt);
1284 vfprintf(out, fmt, va);
1285 va_end(va);
1286 }
1287}
1288
1289/*
1290 * Render the grammar into a state machine definition.
1291 */
1292static void render(FILE *out, FILE *hdr)
1293{
1294 struct element *e;
1295 struct action *action;
1296 struct type *root;
1297 int index;
1298
1299 fprintf(hdr, "/*\n");
1300 fprintf(hdr, " * Automatically generated by asn1_compiler. Do not edit\n");
1301 fprintf(hdr, " *\n");
1302 fprintf(hdr, " * ASN.1 parser for %s\n", grammar_name);
1303 fprintf(hdr, " */\n");
1304 fprintf(hdr, "#include <linux/asn1_decoder.h>\n");
1305 fprintf(hdr, "\n");
1306 fprintf(hdr, "extern const struct asn1_decoder %s_decoder;\n", grammar_name);
1307 if (ferror(hdr)) {
1308 perror(headername);
1309 exit(1);
1310 }
1311
1312 fprintf(out, "/*\n");
1313 fprintf(out, " * Automatically generated by asn1_compiler. Do not edit\n");
1314 fprintf(out, " *\n");
1315 fprintf(out, " * ASN.1 parser for %s\n", grammar_name);
1316 fprintf(out, " */\n");
1317 fprintf(out, "#include <linux/asn1_ber_bytecode.h>\n");
1318 fprintf(out, "#include \"%s.asn1.h\"\n", grammar_name);
1319 fprintf(out, "\n");
1320 if (ferror(out)) {
1321 perror(outputname);
1322 exit(1);
1323 }
1324
1325 /* Tabulate the action functions we might have to call */
1326 fprintf(hdr, "\n");
1327 index = 0;
1328 for (action = action_list; action; action = action->next) {
1329 action->index = index++;
1330 fprintf(hdr,
1331 "extern int %s(void *, size_t, unsigned char,"
1332 " const void *, size_t);\n",
1333 action->name);
1334 }
1335 fprintf(hdr, "\n");
1336
1337 fprintf(out, "enum %s_actions {\n", grammar_name);
1338 for (action = action_list; action; action = action->next)
1339 fprintf(out, "\tACT_%s = %u,\n",
1340 action->name, action->index);
1341 fprintf(out, "\tNR__%s_actions = %u\n", grammar_name, nr_actions);
1342 fprintf(out, "};\n");
1343
1344 fprintf(out, "\n");
1345 fprintf(out, "static const asn1_action_t %s_action_table[NR__%s_actions] = {\n",
1346 grammar_name, grammar_name);
1347 for (action = action_list; action; action = action->next)
1348 fprintf(out, "\t[%4u] = %s,\n", action->index, action->name);
1349 fprintf(out, "};\n");
1350
1351 if (ferror(out)) {
1352 perror(outputname);
1353 exit(1);
1354 }
1355
1356 /* We do two passes - the first one calculates all the offsets */
1357 verbose("Pass 1\n");
1358 nr_entries = 0;
1359 root = &type_list[0];
1360 render_element(NULL, root->element, NULL);
1361 render_opcode(NULL, "ASN1_OP_COMPLETE,\n");
1362 render_out_of_line_list(NULL);
1363
1364 for (e = element_list; e; e = e->list_next)
1365 e->flags &= ~ELEMENT_RENDERED;
1366
1367 /* And then we actually render */
1368 verbose("Pass 2\n");
1369 fprintf(out, "\n");
1370 fprintf(out, "static const unsigned char %s_machine[] = {\n",
1371 grammar_name);
1372
1373 nr_entries = 0;
1374 root = &type_list[0];
1375 render_element(out, root->element, NULL);
1376 render_opcode(out, "ASN1_OP_COMPLETE,\n");
1377 render_out_of_line_list(out);
1378
1379 fprintf(out, "};\n");
1380
1381 fprintf(out, "\n");
1382 fprintf(out, "const struct asn1_decoder %s_decoder = {\n", grammar_name);
1383 fprintf(out, "\t.machine = %s_machine,\n", grammar_name);
1384 fprintf(out, "\t.machlen = sizeof(%s_machine),\n", grammar_name);
1385 fprintf(out, "\t.actions = %s_action_table,\n", grammar_name);
1386 fprintf(out, "};\n");
1387}
1388
1389/*
1390 * Render the out-of-line elements
1391 */
1392static void render_out_of_line_list(FILE *out)
1393{
1394 struct element *e, *ce;
1395 const char *act;
1396 int entry;
1397
1398 while ((e = render_list)) {
1399 render_list = e->render_next;
1400 if (!render_list)
1401 render_list_p = &render_list;
1402
1403 render_more(out, "\n");
1404 e->entry_index = entry = nr_entries;
1405 render_depth++;
1406 for (ce = e->children; ce; ce = ce->next)
1407 render_element(out, ce, NULL);
1408 render_depth--;
1409
1410 act = e->action ? "_ACT" : "";
1411 switch (e->compound) {
1412 case SEQUENCE:
1413 render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1414 break;
1415 case SEQUENCE_OF:
1416 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1417 render_opcode(out, "_jump_target(%u),\n", entry);
1418 break;
1419 case SET:
1420 render_opcode(out, "ASN1_OP_END_SET%s,\n", act);
1421 break;
1422 case SET_OF:
1423 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1424 render_opcode(out, "_jump_target(%u),\n", entry);
1425 break;
1426 default:
1427 break;
1428 }
1429 if (e->action)
1430 render_opcode(out, "_action(ACT_%s),\n",
1431 e->action->name);
1432 render_opcode(out, "ASN1_OP_RETURN,\n");
1433 }
1434}
1435
1436/*
1437 * Render an element.
1438 */
1439static void render_element(FILE *out, struct element *e, struct element *tag)
1440{
1441 struct element *ec, *x;
1442 const char *cond, *act;
1443 int entry, skippable = 0, outofline = 0;
1444
1445 if (e->flags & ELEMENT_SKIPPABLE ||
1446 (tag && tag->flags & ELEMENT_SKIPPABLE))
1447 skippable = 1;
1448
1449 if ((e->type_def && e->type_def->ref_count > 1) ||
1450 skippable)
1451 outofline = 1;
1452
1453 if (e->type_def && out) {
1454 render_more(out, "\t// %s\n", e->type_def->name->content);
1455 }
1456
1457 /* Render the operation */
1458 cond = (e->flags & ELEMENT_CONDITIONAL ||
1459 (tag && tag->flags & ELEMENT_CONDITIONAL)) ? "COND_" : "";
1460 act = e->action ? "_ACT" : "";
1461 switch (e->compound) {
1462 case ANY:
1463 render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,",
1464 cond, act, skippable ? "_OR_SKIP" : "");
1465 if (e->name)
1466 render_more(out, "\t\t// %s", e->name->content);
1467 render_more(out, "\n");
1468 goto dont_render_tag;
1469
1470 case TAG_OVERRIDE:
1471 render_element(out, e->children, e);
1472 return;
1473
1474 case SEQUENCE:
1475 case SEQUENCE_OF:
1476 case SET:
1477 case SET_OF:
1478 render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1479 cond,
1480 outofline ? "_JUMP" : "",
1481 skippable ? "_OR_SKIP" : "");
1482 break;
1483
1484 case CHOICE:
1485 goto dont_render_tag;
1486
1487 case TYPE_REF:
1488 if (e->class == ASN1_UNIV && e->method == ASN1_PRIM && e->tag == 0)
1489 goto dont_render_tag;
1490 default:
1491 render_opcode(out, "ASN1_OP_%sMATCH%s%s,",
1492 cond, act,
1493 skippable ? "_OR_SKIP" : "");
1494 break;
1495 }
1496
1497 x = tag ?: e;
1498 if (x->name)
1499 render_more(out, "\t\t// %s", x->name->content);
1500 render_more(out, "\n");
1501
1502 /* Render the tag */
1503 if (!tag || !(tag->flags & ELEMENT_TAG_SPECIFIED))
1504 tag = e;
1505
1506 if (tag->class == ASN1_UNIV &&
1507 tag->tag != 14 &&
1508 tag->tag != 15 &&
1509 tag->tag != 31)
1510 render_opcode(out, "_tag(%s, %s, %s),\n",
1511 asn1_classes[tag->class],
1512 asn1_methods[tag->method | e->method],
1513 asn1_universal_tags[tag->tag]);
1514 else
1515 render_opcode(out, "_tagn(%s, %s, %2u),\n",
1516 asn1_classes[tag->class],
1517 asn1_methods[tag->method | e->method],
1518 tag->tag);
1519 tag = NULL;
1520dont_render_tag:
1521
1522 /* Deal with compound types */
1523 switch (e->compound) {
1524 case TYPE_REF:
1525 render_element(out, e->type->type->element, tag);
1526 if (e->action)
1527 render_opcode(out, "ASN1_OP_%sACT,\n",
1528 skippable ? "MAYBE_" : "");
1529 break;
1530
1531 case SEQUENCE:
1532 if (outofline) {
1533 /* Render out-of-line for multiple use or
1534 * skipability */
1535 render_opcode(out, "_jump_target(%u),", e->entry_index);
1536 if (e->type_def && e->type_def->name)
1537 render_more(out, "\t\t// --> %s",
1538 e->type_def->name->content);
1539 render_more(out, "\n");
1540 if (!(e->flags & ELEMENT_RENDERED)) {
1541 e->flags |= ELEMENT_RENDERED;
1542 *render_list_p = e;
1543 render_list_p = &e->render_next;
1544 }
1545 return;
1546 } else {
1547 /* Render inline for single use */
1548 render_depth++;
1549 for (ec = e->children; ec; ec = ec->next)
1550 render_element(out, ec, NULL);
1551 render_depth--;
1552 render_opcode(out, "ASN1_OP_END_SEQ%s,\n", act);
1553 }
1554 break;
1555
1556 case SEQUENCE_OF:
1557 case SET_OF:
1558 if (outofline) {
1559 /* Render out-of-line for multiple use or
1560 * skipability */
1561 render_opcode(out, "_jump_target(%u),", e->entry_index);
1562 if (e->type_def && e->type_def->name)
1563 render_more(out, "\t\t// --> %s",
1564 e->type_def->name->content);
1565 render_more(out, "\n");
1566 if (!(e->flags & ELEMENT_RENDERED)) {
1567 e->flags |= ELEMENT_RENDERED;
1568 *render_list_p = e;
1569 render_list_p = &e->render_next;
1570 }
1571 return;
1572 } else {
1573 /* Render inline for single use */
1574 entry = nr_entries;
1575 render_depth++;
1576 render_element(out, e->children, NULL);
1577 render_depth--;
1578 if (e->compound == SEQUENCE_OF)
1579 render_opcode(out, "ASN1_OP_END_SEQ_OF%s,\n", act);
1580 else
1581 render_opcode(out, "ASN1_OP_END_SET_OF%s,\n", act);
1582 render_opcode(out, "_jump_target(%u),\n", entry);
1583 }
1584 break;
1585
1586 case SET:
1587 /* I can't think of a nice way to do SET support without having
1588 * a stack of bitmasks to make sure no element is repeated.
1589 * The bitmask has also to be checked that no non-optional
1590 * elements are left out whilst not preventing optional
1591 * elements from being left out.
1592 */
1593 fprintf(stderr, "The ASN.1 SET type is not currently supported.\n");
1594 exit(1);
1595
1596 case CHOICE:
1597 for (ec = e->children; ec; ec = ec->next)
1598 render_element(out, ec, ec);
1599 if (!skippable)
1600 render_opcode(out, "ASN1_OP_COND_FAIL,\n");
1601 if (e->action)
1602 render_opcode(out, "ASN1_OP_ACT,\n");
1603 break;
1604
1605 default:
1606 break;
1607 }
1608
1609 if (e->action)
1610 render_opcode(out, "_action(ACT_%s),\n", e->action->name);
1611}