blob: c1b7ef3e24c1c055cc90d1e986b11308ff7d2e02 [file] [log] [blame]
David Howells4520c6a2012-09-21 23:31:13 +01001/* 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>
David Howellsae44a2f2015-08-05 14:07:01 +010016#include <stdbool.h>
David Howells4520c6a2012-09-21 23:31:13 +010017#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;
David Howellsc05cae92015-07-29 21:14:00 +0100297 char *name;
David Howells4520c6a2012-09-21 23:31:13 +0100298 unsigned char index;
David Howells4520c6a2012-09-21 23:31:13 +0100299};
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;
David Howellsc05cae92015-07-29 21:14:00 +0100309 char *content;
David Howells4520c6a2012-09-21 23:31:13 +0100310 struct type *type;
311};
312
313static struct token *token_list;
314static unsigned nr_tokens;
David Howellsae44a2f2015-08-05 14:07:01 +0100315static bool verbose_opt;
316static bool debug_opt;
Arnd Bergmanne9943932015-01-13 22:24:31 +0100317
David Howellsae44a2f2015-08-05 14:07:01 +0100318#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)
David Howells4520c6a2012-09-21 23:31:13 +0100320
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
David Howellsc05cae92015-07-29 21:14:00 +0100331 //debug("cmp(%s,%s) = ", token->content, dir);
David Howells4520c6a2012-09-21 23:31:13 +0100332
David Howellsc05cae92015-07-29 21:14:00 +0100333 val = memcmp(token->content, dir, clen);
David Howells4520c6a2012-09-21 23:31:13 +0100334 if (val != 0) {
Arnd Bergmanne9943932015-01-13 22:24:31 +0100335 //debug("%d [cmp]\n", val);
David Howells4520c6a2012-09-21 23:31:13 +0100336 return val;
337 }
338
339 if (dlen == token->size) {
Arnd Bergmanne9943932015-01-13 22:24:31 +0100340 //debug("0\n");
David Howells4520c6a2012-09-21 23:31:13 +0100341 return 0;
342 }
Arnd Bergmanne9943932015-01-13 22:24:31 +0100343 //debug("%d\n", (int)dlen - (int)token->size);
David Howells4520c6a2012-09-21 23:31:13 +0100344 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;
David Howellsc05cae92015-07-29 21:14:00 +0100353 char *line, *nl, *start, *p, *q;
David Howells4520c6a2012-09-21 23:31:13 +0100354 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;
David Howellsc05cae92015-07-29 21:14:00 +0100412 start = p;
David Howells4520c6a2012-09-21 23:31:13 +0100413
414 /* Handle string tokens */
415 if (isalpha(*p)) {
David Howellsc05cae92015-07-29 21:14:00 +0100416 const char **dir, *start = p;
David Howells4520c6a2012-09-21 23:31:13 +0100417
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
David Howellsc05cae92015-07-29 21:14:00 +0100427 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
David Howells4520c6a2012-09-21 23:31:13 +0100435 /* If it begins with a lowercase letter then
436 * it's an element name
437 */
David Howellsc05cae92015-07-29 21:14:00 +0100438 if (islower(tokens[tix].content[0])) {
David Howells4520c6a2012-09-21 23:31:13 +0100439 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;
David Howellsc05cae92015-07-29 21:14:00 +0100467 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;
David Howells4520c6a2012-09-21 23:31:13 +0100474 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;
David Howellsc05cae92015-07-29 21:14:00 +0100482 tokens[tix].content = "::=";
David Howells4520c6a2012-09-21 23:31:13 +0100483 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;
David Howellsc05cae92015-07-29 21:14:00 +0100492 tokens[tix].content = "({";
David Howells4520c6a2012-09-21 23:31:13 +0100493 tokens[tix++].token_type = TOKEN_OPEN_ACTION;
494 continue;
495 }
496 if (memcmp(p, "})", 2) == 0) {
497 p += 2;
498 tokens[tix].size = 2;
David Howellsc05cae92015-07-29 21:14:00 +0100499 tokens[tix].content = "})";
David Howells4520c6a2012-09-21 23:31:13 +0100500 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;
David Howellsc05cae92015-07-29 21:14:00 +0100510 tokens[tix].content = "{";
David Howells4520c6a2012-09-21 23:31:13 +0100511 tokens[tix++].token_type = TOKEN_OPEN_CURLY;
512 continue;
513 case '}':
514 p += 1;
David Howellsc05cae92015-07-29 21:14:00 +0100515 tokens[tix].content = "}";
David Howells4520c6a2012-09-21 23:31:13 +0100516 tokens[tix++].token_type = TOKEN_CLOSE_CURLY;
517 continue;
518 case '[':
519 p += 1;
David Howellsc05cae92015-07-29 21:14:00 +0100520 tokens[tix].content = "[";
David Howells4520c6a2012-09-21 23:31:13 +0100521 tokens[tix++].token_type = TOKEN_OPEN_SQUARE;
522 continue;
523 case ']':
524 p += 1;
David Howellsc05cae92015-07-29 21:14:00 +0100525 tokens[tix].content = "]";
David Howells4520c6a2012-09-21 23:31:13 +0100526 tokens[tix++].token_type = TOKEN_CLOSE_SQUARE;
527 continue;
528 case ',':
529 p += 1;
David Howellsc05cae92015-07-29 21:14:00 +0100530 tokens[tix].content = ",";
David Howells4520c6a2012-09-21 23:31:13 +0100531 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;
David Howellsae44a2f2015-08-05 14:07:01 +0100545 verbose("Extracted %u tokens\n", nr_tokens);
David Howells4520c6a2012-09-21 23:31:13 +0100546
547#if 0
548 {
549 int n;
550 for (n = 0; n < nr_tokens; n++)
David Howellsc05cae92015-07-29 21:14:00 +0100551 debug("Token %3u: '%s'\n", n, token_list[n].content);
David Howells4520c6a2012-09-21 23:31:13 +0100552 }
553#endif
554}
555
556static void build_type_list(void);
557static void parse(void);
David Howellsae44a2f2015-08-05 14:07:01 +0100558static void dump_elements(void);
David Howells4520c6a2012-09-21 23:31:13 +0100559static 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;
Arnd Bergmanne9943932015-01-13 22:24:31 +0100570 char *kbuild_verbose;
David Howells4520c6a2012-09-21 23:31:13 +0100571 int fd;
572
David Howellsae44a2f2015-08-05 14:07:01 +0100573 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
David Howells4520c6a2012-09-21 23:31:13 +0100588 if (argc != 4) {
David Howellsae44a2f2015-08-05 14:07:01 +0100589 fprintf(stderr, "Format: %s [-v] [-d] <grammar-file> <c-file> <hdr-file>\n",
David Howells4520c6a2012-09-21 23:31:13 +0100590 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();
David Howellsae44a2f2015-08-05 14:07:01 +0100644 dump_elements();
David Howells4520c6a2012-09-21 23:31:13 +0100645
646 out = fopen(outputname, "w");
647 if (!out) {
648 perror(outputname);
649 exit(1);
650 }
651
652 hdr = fopen(headername, "w");
Colin Ian King952cca62016-04-06 14:06:48 +0100653 if (!hdr) {
David Howells4520c6a2012-09-21 23:31:13 +0100654 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
David Howells8d9b21d2015-08-05 12:54:45 +0100703#define ELEMENT_TAG_SPECIFIED 0x0004
David Howells4520c6a2012-09-21 23:31:13 +0100704#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
David Howellsc05cae92015-07-29 21:14:00 +0100730 return memcmp((*a)->name->content, (*b)->name->content,
David Howells4520c6a2012-09-21 23:31:13 +0100731 (*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
David Howellsc05cae92015-07-29 21:14:00 +0100743 return memcmp(token->content, type->name->content,
David Howells4520c6a2012-09-21 23:31:13 +0100744 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
David Howellsae44a2f2015-08-05 14:07:01 +0100793 verbose("Extracted %u types\n", nr_types);
David Howells4520c6a2012-09-21 23:31:13 +0100794#if 0
795 for (n = 0; n < nr_types; n++) {
796 struct type *type = type_index[n];
David Howellsc05cae92015-07-29 21:14:00 +0100797 debug("- %*.*s\n", type->name->content);
David Howells4520c6a2012-09-21 23:31:13 +0100798 }
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) {
David Howellsc05cae92015-07-29 21:14:00 +0100827 fprintf(stderr, "%s:%d: Parse error at token '%s'\n",
828 filename, cursor->line, cursor->content);
David Howells4520c6a2012-09-21 23:31:13 +0100829 exit(1);
830 }
831
832 } while (type++, !(type->flags & TYPE_STOP_MARKER));
833
David Howellsae44a2f2015-08-05 14:07:01 +0100834 verbose("Extracted %u actions\n", nr_actions);
David Howells4520c6a2012-09-21 23:31:13 +0100835}
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:
David Howellsc05cae92015-07-29 21:14:00 +0100895 fprintf(stderr, "%s:%d: Unrecognised tag class token '%s'\n",
896 filename, cursor->line, cursor->content);
David Howells4520c6a2012-09-21 23:31:13 +0100897 exit(1);
898 }
899
900 if (cursor >= end)
901 goto overrun_error;
902 if (cursor->token_type != TOKEN_NUMBER) {
David Howellsc05cae92015-07-29 21:14:00 +0100903 fprintf(stderr, "%s:%d: Missing tag number '%s'\n",
904 filename, cursor->line, cursor->content);
David Howells4520c6a2012-09-21 23:31:13 +0100905 exit(1);
906 }
907
908 element->tag &= ~0x1f;
David Howellsc05cae92015-07-29 21:14:00 +0100909 element->tag |= strtoul(cursor->content, &p, 10);
David Howells8d9b21d2015-08-05 12:54:45 +0100910 element->flags |= ELEMENT_TAG_SPECIFIED;
David Howellsc05cae92015-07-29 21:14:00 +0100911 if (p - cursor->content != cursor->size)
David Howells4520c6a2012-09-21 23:31:13 +0100912 abort();
913 cursor++;
914
915 if (cursor >= end)
916 goto overrun_error;
917 if (cursor->token_type != TOKEN_CLOSE_SQUARE) {
David Howellsc05cae92015-07-29 21:14:00 +0100918 fprintf(stderr, "%s:%d: Missing closing square bracket '%s'\n",
919 filename, cursor->line, cursor->content);
David Howells4520c6a2012-09-21 23:31:13 +0100920 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) {
David Howellsc05cae92015-07-29 21:14:00 +01001019 fprintf(stderr, "%s:%d: Type '%s' undefined\n",
1020 filename, cursor->line, cursor->content);
David Howells4520c6a2012-09-21 23:31:13 +01001021 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:
David Howellsc05cae92015-07-29 21:14:00 +01001069 fprintf(stderr, "%s:%d: Token '%s' does not introduce a type\n",
1070 filename, cursor->line, cursor->content);
David Howells4520c6a2012-09-21 23:31:13 +01001071 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) {
David Howellsc05cae92015-07-29 21:14:00 +01001087 fprintf(stderr, "%s:%d: Token '%s' is not an action function name\n",
1088 filename, cursor->line, cursor->content);
David Howells4520c6a2012-09-21 23:31:13 +01001089 exit(1);
1090 }
1091
David Howellsc05cae92015-07-29 21:14:00 +01001092 action = malloc(sizeof(struct action));
David Howells4520c6a2012-09-21 23:31:13 +01001093 if (!action) {
1094 perror(NULL);
1095 exit(1);
1096 }
1097 action->index = 0;
David Howellsc05cae92015-07-29 21:14:00 +01001098 action->name = cursor->content;
David Howells4520c6a2012-09-21 23:31:13 +01001099
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) {
David Howellsc05cae92015-07-29 21:14:00 +01001128 fprintf(stderr, "%s:%d: Missing close action, got '%s'\n",
1129 filename, cursor->line, cursor->content);
David Howells4520c6a2012-09-21 23:31:13 +01001130 exit(1);
1131 }
1132 cursor++;
1133 }
1134
1135 *_cursor = cursor;
1136 return top;
1137
1138parse_error:
David Howellsc05cae92015-07-29 21:14:00 +01001139 fprintf(stderr, "%s:%d: Unexpected token '%s'\n",
1140 filename, cursor->line, cursor->content);
David Howells4520c6a2012-09-21 23:31:13 +01001141 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) {
David Howellsc05cae92015-07-29 21:14:00 +01001158 fprintf(stderr, "%s:%d: Expected compound to start with brace not '%s'\n",
1159 filename, cursor->line, cursor->content);
David Howells4520c6a2012-09-21 23:31:13 +01001160 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) {
David Howellsc05cae92015-07-29 21:14:00 +01001200 fprintf(stderr, "%s:%d: Expected compound closure, got '%s'\n",
1201 filename, cursor->line, cursor->content);
David Howells4520c6a2012-09-21 23:31:13 +01001202 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
David Howellsae44a2f2015-08-05 14:07:01 +01001214static void dump_element(const struct element *e, int level)
1215{
1216 const struct element *c;
1217 const struct type *t = e->type_def;
David Howellsc05cae92015-07-29 21:14:00 +01001218 const char *name = e->name ? e->name->content : ".";
1219 const char *tname = t && t->name ? t->name->content : ".";
David Howellsae44a2f2015-08-05 14:07:01 +01001220 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
David Howellsc05cae92015-07-29 21:14:00 +01001235 printf("%c%c%c%c%c %c %*s[*] \e[33m%s\e[m %s %s \e[35m%s\e[m\n",
David Howellsae44a2f2015-08-05 14:07:01 +01001236 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,
David Howellsc05cae92015-07-29 21:14:00 +01001244 tname,
1245 name,
David Howellsae44a2f2015-08-05 14:07:01 +01001246 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
David Howells4520c6a2012-09-21 23:31:13 +01001260static 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 */
David Howellsae44a2f2015-08-05 14:07:01 +01001361 verbose("Pass 1\n");
David Howells4520c6a2012-09-21 23:31:13 +01001362 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 */
David Howellsae44a2f2015-08-05 14:07:01 +01001372 verbose("Pass 2\n");
David Howells4520c6a2012-09-21 23:31:13 +01001373 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;
Antonio Alecrim Jreb8948a2013-09-16 11:04:54 -03001430 default:
1431 break;
David Howells4520c6a2012-09-21 23:31:13 +01001432 }
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{
David Howells8d9b21d2015-08-05 12:54:45 +01001445 struct element *ec, *x;
David Howells4520c6a2012-09-21 23:31:13 +01001446 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) {
David Howellsc05cae92015-07-29 21:14:00 +01001458 render_more(out, "\t// %s\n", e->type_def->name->content);
David Howells4520c6a2012-09-21 23:31:13 +01001459 }
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:
David Howells233ce792015-08-05 12:54:46 +01001467 render_opcode(out, "ASN1_OP_%sMATCH_ANY%s%s,",
1468 cond, act, skippable ? "_OR_SKIP" : "");
David Howells4520c6a2012-09-21 23:31:13 +01001469 if (e->name)
David Howellsc05cae92015-07-29 21:14:00 +01001470 render_more(out, "\t\t// %s", e->name->content);
David Howells4520c6a2012-09-21 23:31:13 +01001471 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
David Howells8d9b21d2015-08-05 12:54:45 +01001501 x = tag ?: e;
1502 if (x->name)
David Howellsc05cae92015-07-29 21:14:00 +01001503 render_more(out, "\t\t// %s", x->name->content);
David Howells4520c6a2012-09-21 23:31:13 +01001504 render_more(out, "\n");
1505
1506 /* Render the tag */
David Howells8d9b21d2015-08-05 12:54:45 +01001507 if (!tag || !(tag->flags & ELEMENT_TAG_SPECIFIED))
David Howells4520c6a2012-09-21 23:31:13 +01001508 tag = e;
David Howells8d9b21d2015-08-05 12:54:45 +01001509
David Howells4520c6a2012-09-21 23:31:13 +01001510 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)
David Howells3f3af972015-08-05 12:54:46 +01001531 render_opcode(out, "ASN1_OP_%sACT,\n",
1532 skippable ? "MAYBE_" : "");
David Howells4520c6a2012-09-21 23:31:13 +01001533 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)
David Howellsc05cae92015-07-29 21:14:00 +01001541 render_more(out, "\t\t// --> %s",
1542 e->type_def->name->content);
David Howells4520c6a2012-09-21 23:31:13 +01001543 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)
David Howellsc05cae92015-07-29 21:14:00 +01001567 render_more(out, "\t\t// --> %s",
1568 e->type_def->name->content);
David Howells4520c6a2012-09-21 23:31:13 +01001569 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)
David Howells8d9b21d2015-08-05 12:54:45 +01001602 render_element(out, ec, ec);
David Howells4520c6a2012-09-21 23:31:13 +01001603 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}