1 /*        $NetBSD: gen_template.c,v 1.3 2019/12/15 22:50:47 christos Exp $      */
2 
3 /*
4  * Copyright (c) 1997 - 2005 Kungliga Tekniska H�gskolan
5  * (Royal Institute of Technology, Stockholm, Sweden).
6  * All rights reserved.
7  *
8  * Portions Copyright (c) 2009 - 2010 Apple Inc. All rights reserved.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  *
14  * 1. Redistributions of source code must retain the above copyright
15  *    notice, this list of conditions and the following disclaimer.
16  *
17  * 2. Redistributions in binary form must reproduce the above copyright
18  *    notice, this list of conditions and the following disclaimer in the
19  *    documentation and/or other materials provided with the distribution.
20  *
21  * 3. Neither the name of the Institute nor the names of its contributors
22  *    may be used to endorse or promote products derived from this software
23  *    without specific prior written permission.
24  *
25  * THIS SOFTWARE IS PROVIDED BY THE INSTITUTE AND CONTRIBUTORS ``AS IS'' AND
26  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
27  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
28  * ARE DISCLAIMED.  IN NO EVENT SHALL THE INSTITUTE OR CONTRIBUTORS BE LIABLE
29  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
30  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
31  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
32  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
33  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
34  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
35  * SUCH DAMAGE.
36  */
37 
38 #include "gen_locl.h"
39 
40 static const char *symbol_name(const char *, const Type *);
41 static void generate_template_type(const char *, const char **, const char *, const char *, const char *,
42                                            Type *, int, int, int);
43 
44 static const char *
ttype_symbol(const char * basename,const Type * t)45 ttype_symbol(const char *basename, const Type *t)
46 {
47     return t->symbol->gen_name;
48 }
49 
50 static const char *
integer_symbol(const char * basename,const Type * t)51 integer_symbol(const char *basename, const Type *t)
52 {
53     if (t->members)
54           return "int"; /* XXX enum foo */
55     else if (t->range == NULL)
56           return "heim_integer";
57     else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX)
58           return "int64_t";
59     else if (t->range->min >= 0 && t->range->max > UINT_MAX)
60           return "uint64_t";
61     else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX)
62           return "int";
63     else if (t->range->min >= 0 && t->range->max <= UINT_MAX)
64           return "unsigned";
65     else {
66           abort();
67         UNREACHABLE(return NULL);
68     }
69 }
70 
71 static const char *
boolean_symbol(const char * basename,const Type * t)72 boolean_symbol(const char *basename, const Type *t)
73 {
74     return "int";
75 }
76 
77 
78 static const char *
octetstring_symbol(const char * basename,const Type * t)79 octetstring_symbol(const char *basename, const Type *t)
80 {
81     return "heim_octet_string";
82 }
83 
84 static const char *
sequence_symbol(const char * basename,const Type * t)85 sequence_symbol(const char *basename, const Type *t)
86 {
87     return basename;
88 }
89 
90 static const char *
time_symbol(const char * basename,const Type * t)91 time_symbol(const char *basename, const Type *t)
92 {
93     return "time_t";
94 }
95 
96 static const char *
tag_symbol(const char * basename,const Type * t)97 tag_symbol(const char *basename, const Type *t)
98 {
99     return symbol_name(basename, t->subtype);
100 }
101 
102 static const char *
generalstring_symbol(const char * basename,const Type * t)103 generalstring_symbol(const char *basename, const Type *t)
104 {
105     return "heim_general_string";
106 }
107 
108 static const char *
printablestring_symbol(const char * basename,const Type * t)109 printablestring_symbol(const char *basename, const Type *t)
110 {
111     return "heim_printable_string";
112 }
113 
114 static const char *
ia5string_symbol(const char * basename,const Type * t)115 ia5string_symbol(const char *basename, const Type *t)
116 {
117     return "heim_ia5_string";
118 }
119 
120 static const char *
teletexstring_symbol(const char * basename,const Type * t)121 teletexstring_symbol(const char *basename, const Type *t)
122 {
123     return "heim_teletex_string";
124 }
125 
126 static const char *
visiblestring_symbol(const char * basename,const Type * t)127 visiblestring_symbol(const char *basename, const Type *t)
128 {
129     return "heim_visible_string";
130 }
131 
132 static const char *
utf8string_symbol(const char * basename,const Type * t)133 utf8string_symbol(const char *basename, const Type *t)
134 {
135     return "heim_utf8_string";
136 }
137 
138 static const char *
bmpstring_symbol(const char * basename,const Type * t)139 bmpstring_symbol(const char *basename, const Type *t)
140 {
141     return "heim_bmp_string";
142 }
143 
144 static const char *
universalstring_symbol(const char * basename,const Type * t)145 universalstring_symbol(const char *basename, const Type *t)
146 {
147     return "heim_universal_string";
148 }
149 
150 static const char *
oid_symbol(const char * basename,const Type * t)151 oid_symbol(const char *basename, const Type *t)
152 {
153     return "heim_oid";
154 }
155 
156 static const char *
bitstring_symbol(const char * basename,const Type * t)157 bitstring_symbol(const char *basename, const Type *t)
158 {
159     if (t->members)
160           return basename;
161     return "heim_bit_string";
162 }
163 
164 
165 
166 struct {
167     enum typetype type;
168     const char *(*symbol_name)(const char *, const Type *);
169     int is_struct;
170 } types[] =  {
171     { TBMPString, bmpstring_symbol, 0 },
172     { TBitString, bitstring_symbol, 0 },
173     { TBoolean, boolean_symbol, 0 },
174     { TGeneralString, generalstring_symbol, 0 },
175     { TGeneralizedTime, time_symbol, 0 },
176     { TIA5String, ia5string_symbol, 0 },
177     { TTeletexString, generalstring_symbol, 0 },
178     { TInteger, integer_symbol, 0 },
179     { TOID, oid_symbol, 0 },
180     { TOctetString, octetstring_symbol, 0 },
181     { TPrintableString, printablestring_symbol, 0 },
182     { TSequence, sequence_symbol, 1 },
183     { TSequenceOf, tag_symbol, 1 },
184     { TSetOf, tag_symbol, 1 },
185     { TTag, tag_symbol, 1 },
186     { TType, ttype_symbol, 1 },
187     { TUTCTime, time_symbol, 0 },
188     { TUniversalString, universalstring_symbol, 0 },
189     { TTeletexString, teletexstring_symbol, 0 },
190     { TVisibleString,  visiblestring_symbol, 0 },
191     { TUTF8String, utf8string_symbol, 0 },
192     { TChoice, sequence_symbol, 1 },
193     { TNull, integer_symbol, 1 }
194 };
195 
196 static FILE *
get_code_file(void)197 get_code_file(void)
198 {
199     if (!one_code_file)
200           return templatefile;
201     return codefile;
202 }
203 
204 
205 static int
is_supported_type_p(const Type * t)206 is_supported_type_p(const Type *t)
207 {
208     size_t i;
209 
210     for (i = 0; i < sizeof(types)/sizeof(types[0]); i++)
211           if (t->type == types[i].type)
212               return 1;
213     return 0;
214 }
215 
216 int
is_template_compat(const Symbol * s)217 is_template_compat (const Symbol *s)
218 {
219     return is_supported_type_p(s->type);
220 }
221 
222 static const char *
symbol_name(const char * basename,const Type * t)223 symbol_name(const char *basename, const Type *t)
224 {
225     size_t i;
226 
227     for (i = 0; i < sizeof(types)/sizeof(types[0]); i++)
228           if (t->type == types[i].type)
229               return (types[i].symbol_name)(basename, t);
230     printf("unknown der type: %d\n", t->type);
231     exit(1);
232 }
233 
234 
235 static char *
partial_offset(const char * basetype,const char * name,int need_offset,int isstruct)236 partial_offset(const char *basetype, const char *name, int need_offset, int isstruct)
237 {
238     char *str;
239     if (name == NULL || need_offset == 0)
240           return strdup("0");
241     if (asprintf(&str, "offsetof(%s%s, %s)", isstruct ? "struct " : "", basetype, name) < 0 || str == NULL)
242           errx(1, "malloc");
243     return str;
244 }
245 
246 struct template {
247     char *line;
248     char *tt;
249     char *offset;
250     char *ptr;
251     ASN1_TAILQ_ENTRY(template) members;
252 };
253 
254 ASN1_TAILQ_HEAD(templatehead, template);
255 
256 struct tlist {
257     char *name;
258     char *header;
259     struct templatehead template;
260     ASN1_TAILQ_ENTRY(tlist) tmembers;
261 };
262 
263 ASN1_TAILQ_HEAD(tlisthead, tlist);
264 
265 static void tlist_header(struct tlist *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
266 static struct template *
267     add_line(struct templatehead *, const char *, ...) __attribute__ ((__format__ (__printf__, 2, 3)));
268 static int tlist_cmp(const struct tlist *, const struct tlist *);
269 
270 static void add_line_pointer(struct templatehead *, const char *, const char *, const char *, ...)
271     __attribute__ ((__format__ (__printf__, 4, 5)));
272 
273 
274 static struct tlisthead tlistmaster = ASN1_TAILQ_HEAD_INITIALIZER(tlistmaster);
275 static unsigned long numdups = 0;
276 
277 static struct tlist *
tlist_new(const char * name)278 tlist_new(const char *name)
279 {
280     struct tlist *tl = calloc(1, sizeof(*tl));
281     tl->name = strdup(name);
282     ASN1_TAILQ_INIT(&tl->template);
283     return tl;
284 }
285 
286 static void
tlist_header(struct tlist * t,const char * fmt,...)287 tlist_header(struct tlist *t, const char *fmt, ...)
288 {
289     va_list ap;
290     va_start(ap, fmt);
291     if (vasprintf(&t->header, fmt, ap) < 0 || t->header == NULL)
292           errx(1, "malloc");
293     va_end(ap);
294 }
295 
296 static unsigned long
tlist_count(struct tlist * tl)297 tlist_count(struct tlist *tl)
298 {
299     unsigned int count = 0;
300     struct template *q;
301 
302     ASN1_TAILQ_FOREACH(q, &tl->template, members) {
303           count++;
304     }
305     return count;
306 }
307 
308 static void
tlist_add(struct tlist * tl)309 tlist_add(struct tlist *tl)
310 {
311     ASN1_TAILQ_INSERT_TAIL(&tlistmaster, tl, tmembers);
312 }
313 
314 static void
tlist_print(struct tlist * tl)315 tlist_print(struct tlist *tl)
316 {
317     struct template *q;
318     unsigned int i = 1;
319     FILE *f = get_code_file();
320 
321     fprintf(f, "const struct asn1_template asn1_%s[] = {\n", tl->name);
322     fprintf(f, "/* 0 */ %s,\n", tl->header);
323     ASN1_TAILQ_FOREACH(q, &tl->template, members) {
324           int last = (ASN1_TAILQ_LAST(&tl->template, templatehead) == q);
325           fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ",");
326     }
327     fprintf(f, "};\n");
328 }
329 
330 static struct tlist *
tlist_find_by_name(const char * name)331 tlist_find_by_name(const char *name)
332 {
333     struct tlist *ql;
334     ASN1_TAILQ_FOREACH(ql, &tlistmaster, tmembers) {
335           if (strcmp(ql->name, name) == 0)
336               return ql;
337     }
338     return NULL;
339 }
340 
341 static int
tlist_cmp_name(const char * tname,const char * qname)342 tlist_cmp_name(const char *tname, const char *qname)
343 {
344     struct tlist *tl = tlist_find_by_name(tname);
345     struct tlist *ql = tlist_find_by_name(qname);
346     if (tl == NULL)
347           return 1;
348     if (ql == NULL)
349           return -1;
350     return tlist_cmp(tl, ql);
351 }
352 
353 static int
tlist_cmp(const struct tlist * tl,const struct tlist * ql)354 tlist_cmp(const struct tlist *tl, const struct tlist *ql)
355 {
356     int ret;
357     struct template *t, *q;
358 
359     ret = strcmp(tl->header, ql->header);
360     if (ret) return ret;
361 
362     q = ASN1_TAILQ_FIRST(&ql->template);
363     ASN1_TAILQ_FOREACH(t, &tl->template, members) {
364           if (q == NULL) return 1;
365 
366           if (t->ptr == NULL || q->ptr == NULL) {
367               ret = strcmp(t->line, q->line);
368               if (ret) return ret;
369           } else {
370               ret = strcmp(t->tt, q->tt);
371               if (ret) return ret;
372 
373               ret = strcmp(t->offset, q->offset);
374               if (ret) return ret;
375 
376               if ((ret = strcmp(t->ptr, q->ptr)) != 0 ||
377                     (ret = tlist_cmp_name(t->ptr, q->ptr)) != 0)
378                     return ret;
379           }
380           q = ASN1_TAILQ_NEXT(q, members);
381     }
382     if (q != NULL) return -1;
383     return 0;
384 }
385 
386 
387 static const char *
tlist_find_dup(const struct tlist * tl)388 tlist_find_dup(const struct tlist *tl)
389 {
390     struct tlist *ql;
391 
392     ASN1_TAILQ_FOREACH(ql, &tlistmaster, tmembers) {
393           if (tlist_cmp(ql, tl) == 0) {
394               numdups++;
395               return ql->name;
396           }
397     }
398     return NULL;
399 }
400 
401 
402 /*
403  *
404  */
405 
406 static struct template *
add_line(struct templatehead * t,const char * fmt,...)407 add_line(struct templatehead *t, const char *fmt, ...)
408 {
409     struct template *q = calloc(1, sizeof(*q));
410     va_list ap;
411     va_start(ap, fmt);
412     if (vasprintf(&q->line, fmt, ap) < 0 || q->line == NULL)
413           errx(1, "malloc");
414     va_end(ap);
415     ASN1_TAILQ_INSERT_TAIL(t, q, members);
416     return q;
417 }
418 
419 static void
add_line_pointer(struct templatehead * t,const char * ptr,const char * offset,const char * ttfmt,...)420 add_line_pointer(struct templatehead *t,
421                      const char *ptr,
422                      const char *offset,
423                      const char *ttfmt,
424                      ...)
425 {
426     struct template *q;
427     va_list ap;
428     char *tt = NULL;
429 
430     va_start(ap, ttfmt);
431     if (vasprintf(&tt, ttfmt, ap) < 0 || tt == NULL)
432           errx(1, "malloc");
433     va_end(ap);
434 
435     q = add_line(t, "{ %s, %s, asn1_%s }", tt, offset, ptr);
436     q->tt = tt;
437     q->offset = strdup(offset);
438     q->ptr = strdup(ptr);
439 }
440 
441 static int
use_extern(const Symbol * s)442 use_extern(const Symbol *s)
443 {
444     if (s->type == NULL)
445           return 1;
446     return 0;
447 }
448 
449 static int
is_struct(const Type * t,int isstruct)450 is_struct(const Type *t, int isstruct)
451 {
452     size_t i;
453 
454     if (t->type == TType)
455           return 0;
456     if (t->type == TSequence || t->type == TSet || t->type == TChoice)
457           return 1;
458     if (t->type == TTag)
459           return is_struct(t->subtype, isstruct);
460 
461     for (i = 0; i < sizeof(types)/sizeof(types[0]); i++) {
462           if (t->type == types[i].type) {
463               if (types[i].is_struct == 0)
464                     return 0;
465               else
466                     break;
467           }
468     }
469 
470     return isstruct;
471 }
472 
473 static const Type *
compact_tag(const Type * t)474 compact_tag(const Type *t)
475 {
476     while (t->type == TTag)
477           t = t->subtype;
478     return t;
479 }
480 
481 static void
template_members(struct templatehead * temp,const char * basetype,const char * name,const Type * t,int optional,int implicit,int isstruct,int need_offset)482 template_members(struct templatehead *temp, const char *basetype, const char *name, const Type *t, int optional, int implicit, int isstruct, int need_offset)
483 {
484     char *poffset = NULL;
485 
486     if (optional && t->type != TTag && t->type != TType)
487           errx(1, "%s...%s is optional and not a (TTag or TType)", basetype, name);
488 
489     poffset = partial_offset(basetype, name, need_offset, isstruct);
490 
491     switch (t->type) {
492     case TType:
493           if (use_extern(t->symbol)) {
494               add_line(temp, "{ A1_OP_TYPE_EXTERN %s%s, %s, &asn1_extern_%s}",
495                          optional ? "|A1_FLAG_OPTIONAL" : "",
496                          implicit ? "|A1_FLAG_IMPLICIT" : "",
497                          poffset, t->symbol->gen_name);
498           } else {
499               add_line_pointer(temp, t->symbol->gen_name, poffset,
500                                    "A1_OP_TYPE %s%s",
501                                    optional ? "|A1_FLAG_OPTIONAL" : "",
502                                    implicit ? "|A1_FLAG_IMPLICIT" : "");
503 
504           }
505           break;
506     case TInteger: {
507           char *itype = NULL;
508 
509           if (t->members)
510               itype = "IMEMBER";
511           else if (t->range == NULL)
512               itype = "HEIM_INTEGER";
513           else if (t->range->min < INT_MIN && t->range->max <= INT64_MAX)
514               itype = "INTEGER64";
515           else if (t->range->min >= 0 && t->range->max > UINT_MAX)
516               itype = "UNSIGNED64";
517           else if (t->range->min >= INT_MIN && t->range->max <= INT_MAX)
518               itype = "INTEGER";
519           else if (t->range->min >= 0 && t->range->max <= UINT_MAX)
520               itype = "UNSIGNED";
521           else
522               errx(1, "%s: unsupported range %lld -> %lld",
523                      name, (long long)t->range->min, (long long)t->range->max);
524 
525           add_line(temp, "{ A1_PARSE_T(A1T_%s), %s, NULL }", itype, poffset);
526           break;
527     }
528     case TGeneralString:
529           add_line(temp, "{ A1_PARSE_T(A1T_GENERAL_STRING), %s, NULL }", poffset);
530           break;
531     case TTeletexString:
532           add_line(temp, "{ A1_PARSE_T(A1T_TELETEX_STRING), %s, NULL }", poffset);
533           break;
534     case TPrintableString:
535           add_line(temp, "{ A1_PARSE_T(A1T_PRINTABLE_STRING), %s, NULL }", poffset);
536           break;
537     case TOctetString:
538           add_line(temp, "{ A1_PARSE_T(A1T_OCTET_STRING), %s, NULL }", poffset);
539           break;
540     case TIA5String:
541           add_line(temp, "{ A1_PARSE_T(A1T_IA5_STRING), %s, NULL }", poffset);
542           break;
543     case TBMPString:
544           add_line(temp, "{ A1_PARSE_T(A1T_BMP_STRING), %s, NULL }", poffset);
545           break;
546     case TUniversalString:
547           add_line(temp, "{ A1_PARSE_T(A1T_UNIVERSAL_STRING), %s, NULL }", poffset);
548           break;
549     case TVisibleString:
550           add_line(temp, "{ A1_PARSE_T(A1T_VISIBLE_STRING), %s, NULL }", poffset);
551           break;
552     case TUTF8String:
553           add_line(temp, "{ A1_PARSE_T(A1T_UTF8_STRING), %s, NULL }", poffset);
554           break;
555     case TGeneralizedTime:
556           add_line(temp, "{ A1_PARSE_T(A1T_GENERALIZED_TIME), %s, NULL }", poffset);
557           break;
558     case TUTCTime:
559           add_line(temp, "{ A1_PARSE_T(A1T_UTC_TIME), %s, NULL }", poffset);
560           break;
561     case TBoolean:
562           add_line(temp, "{ A1_PARSE_T(A1T_BOOLEAN), %s, NULL }", poffset);
563           break;
564     case TOID:
565           add_line(temp, "{ A1_PARSE_T(A1T_OID), %s, NULL }", poffset);
566           break;
567     case TNull:
568           break;
569     case TBitString: {
570           struct templatehead template;
571           struct template *q;
572           Member *m;
573           size_t count = 0, i;
574           char *bname = NULL;
575           FILE *f = get_code_file();
576           static unsigned long bmember_counter = 0;
577 
578           ASN1_TAILQ_INIT(&template);
579 
580           if (ASN1_TAILQ_EMPTY(t->members)) {
581               add_line(temp, "{ A1_PARSE_T(A1T_HEIM_BIT_STRING), %s, NULL }", poffset);
582               break;
583           }
584 
585           if (asprintf(&bname, "bmember_%s_%lu", name ? name : "", bmember_counter++) < 0 || bname == NULL)
586               errx(1, "malloc");
587           output_name(bname);
588 
589           ASN1_TAILQ_FOREACH(m, t->members, members) {
590               add_line(&template, "{ 0, %d, 0 } /* %s */", m->val, m->gen_name);
591           }
592 
593           ASN1_TAILQ_FOREACH(q, &template, members) {
594               count++;
595           }
596 
597           fprintf(f, "static const struct asn1_template asn1_%s_%s[] = {\n", basetype, bname);
598           fprintf(f, "/* 0 */ { 0%s, sizeof(%s), ((void *)%lu) },\n",
599                     rfc1510_bitstring ? "|A1_HBF_RFC1510" : "",
600                     basetype, (unsigned long)count);
601           i = 1;
602           ASN1_TAILQ_FOREACH(q, &template, members) {
603               int last = (ASN1_TAILQ_LAST(&template, templatehead) == q);
604               fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ",");
605           }
606           fprintf(f, "};\n");
607 
608           add_line(temp, "{ A1_OP_BMEMBER, %s, asn1_%s_%s }", poffset, basetype, bname);
609 
610           free(bname);
611 
612           break;
613     }
614     case TSequence: {
615           Member *m;
616 
617           fprintf(get_code_file(), "/* tsequence: members isstruct: %d */\n", isstruct);
618 
619           ASN1_TAILQ_FOREACH(m, t->members, members) {
620               char *newbasename = NULL;
621 
622               if (m->ellipsis)
623                     continue;
624 
625               if (name) {
626                     if (asprintf(&newbasename, "%s_%s", basetype, name) < 0)
627                         errx(1, "malloc");
628               } else
629                     newbasename = strdup(basetype);
630               if (newbasename == NULL)
631                     errx(1, "malloc");
632 
633               template_members(temp, newbasename, m->gen_name, m->type, m->optional, 0, isstruct, 1);
634 
635               free(newbasename);
636           }
637 
638           break;
639     }
640     case TTag: {
641           char *tname = NULL, *elname = NULL;
642           const char *sename, *dupname;
643           int subtype_is_struct = is_struct(t->subtype, isstruct);
644           static unsigned long tag_counter = 0;
645           int tagimplicit = (t->tag.tagenv == TE_IMPLICIT);
646           struct type *subtype;
647 
648           fprintf(get_code_file(), "/* template_members: %s %s %s */\n", basetype, implicit ? "imp" : "exp", tagimplicit ? "imp" : "exp");
649 
650           if (tagimplicit) {
651 
652               struct type *type = t->subtype;
653               int have_tag = 0;
654 
655               while (!have_tag) {
656                     if (type->type == TTag) {
657                         fprintf(get_code_file(), "/* template_members: imp skip tag */\n");
658                         type = type->subtype;
659                         have_tag = 1;
660                     } else if(type->type == TType && type->symbol && type->symbol->type) {
661                         /* XXX really, we should stop here and find a
662                          * pointer to where this is encoded instead of
663                          * generated an new structure and hope that the
664                          * optimizer catch it later.
665                          */
666                         subtype_is_struct = is_struct(type, isstruct);
667                         fprintf(get_code_file(), "/* template_members: imp skip type %s isstruct: %d */\n",
668                                   type->symbol->name, subtype_is_struct);
669                         type = type->symbol->type;
670                     } else {
671                         have_tag = 1;
672                     }
673               }
674               subtype = type;
675           } else {
676               subtype = t->subtype;
677           }
678 
679           if (subtype_is_struct)
680               sename = basetype;
681           else
682               sename = symbol_name(basetype, subtype);
683 
684           if (asprintf(&tname, "tag_%s_%lu", name ? name : "", tag_counter++) < 0 || tname == NULL)
685               errx(1, "malloc");
686           output_name(tname);
687 
688           if (asprintf(&elname, "%s_%s", basetype, tname) < 0 || elname == NULL)
689               errx(1, "malloc");
690 
691           generate_template_type(elname, &dupname, NULL, sename, name,
692                                      subtype, 0, subtype_is_struct, 0);
693 
694           add_line_pointer(temp, dupname, poffset,
695                                "A1_TAG_T(%s,%s,%s)%s%s",
696                                classname(t->tag.tagclass),
697                                is_primitive_type(subtype->type)  ? "PRIM" : "CONS",
698                                valuename(t->tag.tagclass, t->tag.tagvalue),
699                                optional ? "|A1_FLAG_OPTIONAL" : "",
700                                tagimplicit ? "|A1_FLAG_IMPLICIT" : "");
701 
702           free(tname);
703           free(elname);
704 
705           break;
706     }
707     case TSetOf:
708     case TSequenceOf: {
709           const char *type = NULL, *tname, *dupname;
710           char *sename = NULL, *elname = NULL;
711           int subtype_is_struct = is_struct(t->subtype, 0);
712           static unsigned long seof_counter = 0;
713 
714           if (name && subtype_is_struct) {
715               tname = "seofTstruct";
716               if (asprintf(&sename, "%s_%s_val", basetype, name) < 0)
717                     errx(1, "malloc");
718           } else if (subtype_is_struct) {
719               tname = "seofTstruct";
720               if (asprintf(&sename, "%s_val", symbol_name(basetype, t->subtype)) < 0)
721                     errx(1, "malloc");
722           } else {
723               if (name)
724                     tname = name;
725               else
726                     tname = "seofTstruct";
727               sename = strdup(symbol_name(basetype, t->subtype));
728           }
729           if (sename == NULL)
730               errx(1, "malloc");
731 
732           if (t->type == TSetOf) type = "A1_OP_SETOF";
733           else if (t->type == TSequenceOf) type = "A1_OP_SEQOF";
734           else abort();
735 
736           if (asprintf(&elname, "%s_%s_%lu", basetype, tname, seof_counter++) < 0 || elname == NULL)
737               errx(1, "malloc");
738 
739           generate_template_type(elname, &dupname, NULL, sename, NULL, t->subtype,
740                                      0, subtype_is_struct, need_offset);
741 
742           add_line(temp, "{ %s, %s, asn1_%s }", type, poffset, dupname);
743           free(sename);
744           break;
745     }
746     case TChoice: {
747           struct templatehead template;
748           struct template *q;
749           size_t count = 0, i;
750           char *tname = NULL;
751           FILE *f = get_code_file();
752           Member *m;
753           int ellipsis = 0;
754           char *e;
755           static unsigned long choice_counter = 0;
756 
757           ASN1_TAILQ_INIT(&template);
758 
759           if (asprintf(&tname, "asn1_choice_%s_%s%lu",
760                          basetype, name ? name : "", choice_counter++) < 0 || tname == NULL)
761               errx(1, "malloc");
762 
763           ASN1_TAILQ_FOREACH(m, t->members, members) {
764               const char *dupname;
765               char *elname = NULL;
766               char *newbasename = NULL;
767               int subtype_is_struct;
768 
769               if (m->ellipsis) {
770                     ellipsis = 1;
771                     continue;
772               }
773 
774               subtype_is_struct = is_struct(m->type, 0);
775 
776               if (asprintf(&elname, "%s_choice_%s", basetype, m->gen_name) < 0 || elname == NULL)
777                     errx(1, "malloc");
778 
779               if (subtype_is_struct) {
780                     if (asprintf(&newbasename, "%s_%s", basetype, m->gen_name) < 0)
781                         errx(1, "malloc");
782               } else
783                     newbasename = strdup(basetype);
784 
785               if (newbasename == NULL)
786                     errx(1, "malloc");
787 
788 
789               generate_template_type(elname, &dupname, NULL,
790                                            symbol_name(newbasename, m->type),
791                                            NULL, m->type, 0, subtype_is_struct, 1);
792 
793               add_line(&template, "{ %s, offsetof(%s%s, u.%s), asn1_%s }",
794                          m->label, isstruct ? "struct " : "",
795                          basetype, m->gen_name,
796                          dupname);
797 
798               free(elname);
799               free(newbasename);
800           }
801 
802           e = NULL;
803           if (ellipsis) {
804               if (asprintf(&e, "offsetof(%s%s, u.asn1_ellipsis)", isstruct ? "struct " : "", basetype) < 0 || e == NULL)
805                     errx(1, "malloc");
806           }
807 
808           ASN1_TAILQ_FOREACH(q, &template, members) {
809               count++;
810           }
811 
812           fprintf(f, "static const struct asn1_template %s[] = {\n", tname);
813           fprintf(f, "/* 0 */ { %s, offsetof(%s%s, element), ((void *)%lu) },\n",
814                     e ? e : "0", isstruct ? "struct " : "", basetype, (unsigned long)count);
815           i = 1;
816           ASN1_TAILQ_FOREACH(q, &template, members) {
817               int last = (ASN1_TAILQ_LAST(&template, templatehead) == q);
818               fprintf(f, "/* %lu */ %s%s\n", (unsigned long)i++, q->line, last ? "" : ",");
819           }
820           fprintf(f, "};\n");
821 
822           add_line(temp, "{ A1_OP_CHOICE, %s, %s }", poffset, tname);
823 
824           free(e);
825           free(tname);
826           break;
827     }
828     default:
829           abort ();
830     }
831     if (poffset)
832           free(poffset);
833 }
834 
835 static void
gen_extern_stubs(FILE * f,const char * name)836 gen_extern_stubs(FILE *f, const char *name)
837 {
838     fprintf(f,
839               "static const struct asn1_type_func asn1_extern_%s = {\n"
840               "\t(asn1_type_encode)encode_%s,\n"
841               "\t(asn1_type_decode)decode_%s,\n"
842               "\t(asn1_type_length)length_%s,\n"
843               "\t(asn1_type_copy)copy_%s,\n"
844               "\t(asn1_type_release)free_%s,\n"
845               "\tsizeof(%s)\n"
846               "};\n",
847               name, name, name, name,
848               name, name, name);
849 }
850 
851 void
gen_template_import(const Symbol * s)852 gen_template_import(const Symbol *s)
853 {
854     FILE *f = get_code_file();
855 
856     if (template_flag == 0)
857           return;
858 
859     gen_extern_stubs(f, s->gen_name);
860 }
861 
862 static void
generate_template_type(const char * varname,const char ** dupname,const char * symname,const char * basetype,const char * name,Type * type,int optional,int isstruct,int need_offset)863 generate_template_type(const char *varname,
864                            const char **dupname,
865                            const char *symname,
866                            const char *basetype,
867                            const char *name,
868                            Type *type,
869                            int optional, int isstruct, int need_offset)
870 {
871     struct tlist *tl;
872     const char *d;
873     char *szt = NULL;
874     int have_ellipsis = 0;
875     int implicit = 0;
876     int n;
877 
878     tl = tlist_new(varname);
879 
880     if (type->type == TTag)
881           implicit = (type->tag.tagenv == TE_IMPLICIT);
882 
883     fprintf(get_code_file(), "extern const struct asn1_template asn1_%s[];\n", tl->name);
884 
885     template_members(&tl->template, basetype, name, type, optional, implicit, isstruct, need_offset);
886 
887     /* if its a sequence or set type, check if there is a ellipsis */
888     if (type->type == TSequence || type->type == TSet) {
889           Member *m;
890           ASN1_TAILQ_FOREACH(m, type->members, members) {
891               if (m->ellipsis)
892                     have_ellipsis = 1;
893           }
894     }
895 
896     if (isstruct)
897           if (name)
898               n = asprintf(&szt, "struct %s_%s", basetype, name);
899           else
900               n = asprintf(&szt, "struct %s", basetype);
901     else
902           n = asprintf(&szt, "%s", basetype);
903     if (n < 0 || szt == NULL)
904           errx(1, "malloc");
905 
906     if (ASN1_TAILQ_EMPTY(&tl->template) && compact_tag(type)->type != TNull)
907           errx(1, "Tag %s...%s with no content ?", basetype, name ? name : "");
908 
909     fprintf(get_code_file(), "/* generate_template_type: %s */\n", tl->name);
910 
911     tlist_header(tl, "{ 0%s%s, sizeof(%s), ((void *)%lu) }",
912                      (symname && preserve_type(symname)) ? "|A1_HF_PRESERVE" : "",
913                      have_ellipsis ? "|A1_HF_ELLIPSIS" : "", szt, tlist_count(tl));
914 
915     free(szt);
916 
917     d = tlist_find_dup(tl);
918     if (d) {
919 #if 0
920           if (strcmp(d, tl->name) == 0)
921               errx(1, "found dup of ourself: %s", d);
922 #endif
923           *dupname = d;
924     } else {
925           *dupname = tl->name;
926           tlist_print(tl);
927           tlist_add(tl);
928     }
929 }
930 
931 
932 void
generate_template(const Symbol * s)933 generate_template(const Symbol *s)
934 {
935     FILE *f = get_code_file();
936     const char *dupname;
937 
938     if (use_extern(s)) {
939           gen_extern_stubs(f, s->gen_name);
940           return;
941     }
942 
943     generate_template_type(s->gen_name, &dupname, s->name, s->gen_name, NULL, s->type, 0, 0, 1);
944 
945     fprintf(f,
946               "\n"
947               "int\n"
948               "decode_%s(const unsigned char *p, size_t len, %s *data, size_t *size)\n"
949               "{\n"
950               "    return _asn1_decode_top(asn1_%s, 0|%s, p, len, data, size);\n"
951               "}\n"
952               "\n",
953               s->gen_name,
954               s->gen_name,
955               dupname,
956               support_ber ? "A1_PF_ALLOW_BER" : "0");
957 
958     fprintf(f,
959               "\n"
960               "int\n"
961               "encode_%s(unsigned char *p, size_t len, const %s *data, size_t *size)\n"
962               "{\n"
963               "    return _asn1_encode%s(asn1_%s, p, len, data, size);\n"
964               "}\n"
965               "\n",
966               s->gen_name,
967               s->gen_name,
968               fuzzer_string,
969               dupname);
970 
971     fprintf(f,
972               "\n"
973               "size_t\n"
974               "length_%s(const %s *data)\n"
975               "{\n"
976               "    return _asn1_length%s(asn1_%s, data);\n"
977               "}\n"
978               "\n",
979               s->gen_name,
980               s->gen_name,
981               fuzzer_string,
982               dupname);
983 
984 
985     fprintf(f,
986               "\n"
987               "void\n"
988               "free_%s(%s *data)\n"
989               "{\n"
990               "    _asn1_free_top(asn1_%s, data);\n"
991               "}\n"
992               "\n",
993               s->gen_name,
994               s->gen_name,
995               dupname);
996 
997     fprintf(f,
998               "\n"
999               "int\n"
1000               "copy_%s(const %s *from, %s *to)\n"
1001               "{\n"
1002               "    return _asn1_copy_top(asn1_%s, from, to);\n"
1003               "}\n"
1004               "\n",
1005               s->gen_name,
1006               s->gen_name,
1007               s->gen_name,
1008               dupname);
1009 }
1010