1 /* $NetBSD: gen_template.c,v 1.2 2017/01/28 21:31:45 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 * 45 ttype_symbol(const char *basename, const Type *t) 46 { 47 return t->symbol->gen_name; 48 } 49 50 static const char * 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 * 72 boolean_symbol(const char *basename, const Type *t) 73 { 74 return "int"; 75 } 76 77 78 static const char * 79 octetstring_symbol(const char *basename, const Type *t) 80 { 81 return "heim_octet_string"; 82 } 83 84 static const char * 85 sequence_symbol(const char *basename, const Type *t) 86 { 87 return basename; 88 } 89 90 static const char * 91 time_symbol(const char *basename, const Type *t) 92 { 93 return "time_t"; 94 } 95 96 static const char * 97 tag_symbol(const char *basename, const Type *t) 98 { 99 return symbol_name(basename, t->subtype); 100 } 101 102 static const char * 103 generalstring_symbol(const char *basename, const Type *t) 104 { 105 return "heim_general_string"; 106 } 107 108 static const char * 109 printablestring_symbol(const char *basename, const Type *t) 110 { 111 return "heim_printable_string"; 112 } 113 114 static const char * 115 ia5string_symbol(const char *basename, const Type *t) 116 { 117 return "heim_ia5_string"; 118 } 119 120 static const char * 121 teletexstring_symbol(const char *basename, const Type *t) 122 { 123 return "heim_teletex_string"; 124 } 125 126 static const char * 127 visiblestring_symbol(const char *basename, const Type *t) 128 { 129 return "heim_visible_string"; 130 } 131 132 static const char * 133 utf8string_symbol(const char *basename, const Type *t) 134 { 135 return "heim_utf8_string"; 136 } 137 138 static const char * 139 bmpstring_symbol(const char *basename, const Type *t) 140 { 141 return "heim_bmp_string"; 142 } 143 144 static const char * 145 universalstring_symbol(const char *basename, const Type *t) 146 { 147 return "heim_universal_string"; 148 } 149 150 static const char * 151 oid_symbol(const char *basename, const Type *t) 152 { 153 return "heim_oid"; 154 } 155 156 static const char * 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 * 197 get_code_file(void) 198 { 199 if (!one_code_file) 200 return templatefile; 201 return codefile; 202 } 203 204 205 static int 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 217 is_template_compat (const Symbol *s) 218 { 219 return is_supported_type_p(s->type); 220 } 221 222 static const char * 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 * 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 * 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 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 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 309 tlist_add(struct tlist *tl) 310 { 311 ASN1_TAILQ_INSERT_TAIL(&tlistmaster, tl, tmembers); 312 } 313 314 static void 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 * 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 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 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 * 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 * 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 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 442 use_extern(const Symbol *s) 443 { 444 if (s->type == NULL) 445 return 1; 446 return 0; 447 } 448 449 static int 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 * 474 compact_tag(const Type *t) 475 { 476 while (t->type == TTag) 477 t = t->subtype; 478 return t; 479 } 480 481 static void 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 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 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 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 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