Annotation of src/usr.bin/ctfconv/parse.c, Revision 1.1
1.1 ! mpi 1: /*
! 2: * Copyright (c) 2016-2017 Martin Pieuchot
! 3: * Copyright (c) 2016 Jasper Lievisse Adriaanse <jasper@openbsd.org>
! 4: *
! 5: * Permission to use, copy, modify, and distribute this software for any
! 6: * purpose with or without fee is hereby granted, provided that the above
! 7: * copyright notice and this permission notice appear in all copies.
! 8: *
! 9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
! 10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
! 11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
! 12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
! 13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
! 14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
! 15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
! 16: */
! 17:
! 18: /*
! 19: * DWARF to IT (internal type) representation parser.
! 20: */
! 21:
! 22: #include <sys/param.h>
! 23: #include <sys/types.h>
! 24: #include <sys/queue.h>
! 25: #include <sys/tree.h>
! 26: #include <sys/ctf.h>
! 27:
! 28: #include <assert.h>
! 29: #include <err.h>
! 30: #include <stdlib.h>
! 31: #include <string.h>
! 32:
! 33: #include "itype.h"
! 34: #include "xmalloc.h"
! 35: #include "dwarf.h"
! 36: #include "dw.h"
! 37: #include "pool.h"
! 38:
! 39: #ifdef DEBUG
! 40: #include <stdio.h>
! 41: #endif
! 42:
! 43: #ifndef NOPOOL
! 44: struct pool it_pool, im_pool, ir_pool;
! 45: #endif /* NOPOOL */
! 46:
! 47: #define DPRINTF(x...) do { /*printf(x)*/ } while (0)
! 48:
! 49: #define VOID_OFFSET 1 /* Fake offset for generating "void" type. */
! 50:
! 51: /*
! 52: * Tree used to resolve per-CU types based on their offset in
! 53: * the abbrev section.
! 54: */
! 55: RB_HEAD(ioff_tree, itype);
! 56:
! 57: /*
! 58: * Per-type trees used to merge exsiting types with the ones of
! 59: * a newly parsed CU.
! 60: */
! 61: RB_HEAD(itype_tree, itype) itypet[CTF_K_MAX];
! 62:
! 63: /*
! 64: * Tree of symbols used to build a list matching the order of
! 65: * the ELF symbol table.
! 66: */
! 67: struct isymb_tree isymbt;
! 68:
! 69: struct itype *void_it;
! 70: uint16_t tidx, fidx, oidx; /* type, func & object IDs */
! 71: uint16_t long_tidx; /* index of "long", for array */
! 72:
! 73:
! 74: void cu_stat(void);
! 75: void cu_parse(struct dwcu *, struct itype_queue *,
! 76: struct ioff_tree *);
! 77: void cu_resolve(struct dwcu *, struct itype_queue *,
! 78: struct ioff_tree *);
! 79: void cu_reference(struct dwcu *, struct itype_queue *);
! 80: void cu_merge(struct dwcu *, struct itype_queue *);
! 81:
! 82: struct itype *parse_base(struct dwdie *, size_t);
! 83: struct itype *parse_refers(struct dwdie *, size_t, int);
! 84: struct itype *parse_array(struct dwdie *, size_t);
! 85: struct itype *parse_enum(struct dwdie *, size_t);
! 86: struct itype *parse_struct(struct dwdie *, size_t, int, size_t);
! 87: struct itype *parse_function(struct dwdie *, size_t);
! 88: struct itype *parse_funcptr(struct dwdie *, size_t);
! 89: struct itype *parse_variable(struct dwdie *, size_t);
! 90:
! 91: void subparse_subrange(struct dwdie *, size_t, struct itype *);
! 92: void subparse_enumerator(struct dwdie *, size_t, struct itype *);
! 93: void subparse_member(struct dwdie *, size_t, struct itype *, size_t);
! 94: void subparse_arguments(struct dwdie *, size_t, struct itype *);
! 95:
! 96: size_t dav2val(struct dwaval *, size_t);
! 97: const char *dav2str(struct dwaval *);
! 98: const char *enc2name(unsigned short);
! 99:
! 100: struct itype *it_new(uint64_t, size_t, const char *, uint32_t, uint16_t,
! 101: uint64_t, uint16_t, unsigned int);
! 102: void it_reference(struct itype *);
! 103: void it_free(struct itype *);
! 104: int it_cmp(struct itype *, struct itype *);
! 105: int it_name_cmp(struct itype *, struct itype *);
! 106: int it_off_cmp(struct itype *, struct itype *);
! 107: void ir_add(struct itype *, struct itype *);
! 108: void ir_purge(struct itype *);
! 109: struct imember *im_new(const char *, size_t, size_t);
! 110:
! 111: RB_GENERATE(itype_tree, itype, it_node, it_cmp);
! 112: RB_GENERATE(isymb_tree, itype, it_node, it_name_cmp);
! 113: RB_GENERATE(ioff_tree, itype, it_node, it_off_cmp);
! 114:
! 115: /*
! 116: * Construct a list of internal type and functions based on DWARF
! 117: * INFO and ABBREV sections.
! 118: *
! 119: * Multiple CUs are supported.
! 120: */
! 121: void
! 122: dwarf_parse(const char *infobuf, size_t infolen, const char *abbuf,
! 123: size_t ablen)
! 124: {
! 125: struct dwbuf info = { .buf = infobuf, .len = infolen };
! 126: struct dwbuf abbrev = { .buf = abbuf, .len = ablen };
! 127: struct dwcu *dcu = NULL;
! 128: struct ioff_tree cu_iofft;
! 129: struct itype_queue cu_itypeq;
! 130: struct itype *it;
! 131: int i;
! 132:
! 133: for (i = 0; i < CTF_K_MAX; i++)
! 134: RB_INIT(&itypet[i]);
! 135: RB_INIT(&isymbt);
! 136:
! 137: void_it = it_new(++tidx, VOID_OFFSET, "void", 0,
! 138: CTF_INT_SIGNED, 0, CTF_K_INTEGER, 0);
! 139: TAILQ_INSERT_TAIL(&itypeq, void_it, it_next);
! 140:
! 141: while (dw_cu_parse(&info, &abbrev, infolen, &dcu) == 0) {
! 142: TAILQ_INIT(&cu_itypeq);
! 143: RB_INIT(&cu_iofft);
! 144:
! 145: /* Parse this CU */
! 146: cu_parse(dcu, &cu_itypeq, &cu_iofft);
! 147:
! 148: /* Resolve its types. */
! 149: cu_resolve(dcu, &cu_itypeq, &cu_iofft);
! 150: assert(RB_EMPTY(&cu_iofft));
! 151:
! 152: /* Mark used type as such. */
! 153: cu_reference(dcu, &cu_itypeq);
! 154:
! 155: #ifdef DEBUG
! 156: /* Dump statistics for current CU. */
! 157: cu_stat();
! 158: #endif
! 159:
! 160: /* Merge them with the common type list. */
! 161: cu_merge(dcu, &cu_itypeq);
! 162:
! 163: dw_dcu_free(dcu);
! 164: }
! 165:
! 166: /* We force array's index type to be 'long', for that we need its ID. */
! 167: RB_FOREACH(it, itype_tree, &itypet[CTF_K_INTEGER]) {
! 168: if (it_name(it) == NULL || it->it_size != (8 * sizeof(long)))
! 169: continue;
! 170:
! 171: if (strcmp(it_name(it), "unsigned") == 0) {
! 172: long_tidx = it->it_idx;
! 173: break;
! 174: }
! 175: }
! 176: }
! 177:
! 178: struct itype *
! 179: it_new(uint64_t index, size_t off, const char *name, uint32_t size,
! 180: uint16_t enc, uint64_t ref, uint16_t type, unsigned int flags)
! 181: {
! 182: struct itype *it;
! 183: #ifndef NOPOOL
! 184: static int it_pool_inited = 0;
! 185:
! 186: if (!it_pool_inited) {
! 187: pool_init(&it_pool, "it", 512, sizeof(struct itype));
! 188: pool_init(&im_pool, "im", 1024, sizeof(struct imember));
! 189: pool_init(&ir_pool, "ir", 1024, sizeof(struct itref));
! 190: it_pool_inited = 1;
! 191: }
! 192: #endif
! 193:
! 194: assert((name != NULL) || !(flags & (ITF_FUNC|ITF_OBJ)));
! 195:
! 196: it = pmalloc(&it_pool, sizeof(*it));
! 197: SIMPLEQ_INIT(&it->it_refs);
! 198: TAILQ_INIT(&it->it_members);
! 199: it->it_off = off;
! 200: it->it_ref = ref;
! 201: it->it_refp = NULL;
! 202: it->it_size = size;
! 203: it->it_nelems = 0;
! 204: it->it_enc = enc;
! 205: it->it_idx = index;
! 206: it->it_type = type;
! 207: it->it_flags = flags;
! 208:
! 209: if (name == NULL) {
! 210: it->it_flags |= ITF_ANON;
! 211: } else {
! 212: size_t n;
! 213:
! 214: if ((n = strlcpy(it->it_name, name, ITNAME_MAX)) > ITNAME_MAX)
! 215: warnx("name %s too long %zd > %d", name, n, ITNAME_MAX);
! 216: }
! 217:
! 218: return it;
! 219: }
! 220:
! 221: struct itype *
! 222: it_dup(struct itype *it)
! 223: {
! 224: struct imember *copim, *im;
! 225: struct itype *copit;
! 226:
! 227: copit = it_new(it->it_idx, it->it_off, it_name(it), it->it_size,
! 228: it->it_enc, it->it_ref, it->it_type, it->it_flags);
! 229:
! 230: copit->it_refp = it->it_refp;
! 231: copit->it_nelems = it->it_nelems;
! 232:
! 233: TAILQ_FOREACH(im, &it->it_members, im_next) {
! 234: copim = im_new(im->im_name, im->im_ref, im->im_off);
! 235: copim->im_refp = im->im_refp;
! 236: TAILQ_INSERT_TAIL(&copit->it_members, copim, im_next);
! 237: }
! 238:
! 239: return copit;
! 240: }
! 241:
! 242: const char *
! 243: it_name(struct itype *it)
! 244: {
! 245: if (!(it->it_flags & ITF_ANON))
! 246: return it->it_name;
! 247:
! 248: return NULL;
! 249: }
! 250:
! 251: void
! 252: it_reference(struct itype *it)
! 253: {
! 254: struct imember *im;
! 255:
! 256: if (it == NULL || it->it_flags & ITF_USED)
! 257: return;
! 258:
! 259: it->it_flags |= ITF_USED;
! 260:
! 261: it_reference(it->it_refp);
! 262: TAILQ_FOREACH(im, &it->it_members, im_next)
! 263: it_reference(im->im_refp);
! 264: }
! 265:
! 266: void
! 267: it_free(struct itype *it)
! 268: {
! 269: struct imember *im;
! 270:
! 271: if (it == NULL)
! 272: return;
! 273:
! 274: while ((im = TAILQ_FIRST(&it->it_members)) != NULL) {
! 275: TAILQ_REMOVE(&it->it_members, im, im_next);
! 276: pfree(&im_pool, im);
! 277: }
! 278:
! 279: ir_purge(it);
! 280: pfree(&it_pool, it);
! 281: }
! 282:
! 283: /*
! 284: * Return 0 if ``a'' matches ``b''.
! 285: */
! 286: int
! 287: it_cmp(struct itype *a, struct itype *b)
! 288: {
! 289: int diff;
! 290:
! 291: if ((diff = (a->it_type - b->it_type)) != 0)
! 292: return diff;
! 293:
! 294: if ((diff = (a->it_size - b->it_size)) != 0)
! 295: return diff;
! 296:
! 297: if ((diff = (a->it_nelems - b->it_nelems)) != 0)
! 298: return diff;
! 299:
! 300: /* Match by name */
! 301: if (!(a->it_flags & ITF_ANON) && !(b->it_flags & ITF_ANON))
! 302: return strcmp(it_name(a), it_name(b));
! 303:
! 304: /* Only one of them is anonym */
! 305: if ((a->it_flags & ITF_ANON) != (b->it_flags & ITF_ANON))
! 306: return (a->it_flags & ITF_ANON) ? -1 : 1;
! 307:
! 308: /* Match by reference */
! 309: if ((a->it_refp != NULL) && (b->it_refp != NULL))
! 310: return it_cmp(a->it_refp, b->it_refp);
! 311:
! 312: return 1;
! 313: }
! 314:
! 315: int
! 316: it_name_cmp(struct itype *a, struct itype *b)
! 317: {
! 318: int diff;
! 319:
! 320: if ((diff = strcmp(it_name(a), it_name(b))) != 0)
! 321: return diff;
! 322:
! 323: return ((a->it_flags|ITF_MASK) - (b->it_flags|ITF_MASK));
! 324: }
! 325:
! 326: int
! 327: it_off_cmp(struct itype *a, struct itype *b)
! 328: {
! 329: return a->it_off - b->it_off;
! 330: }
! 331:
! 332: void
! 333: ir_add(struct itype *it, struct itype *tmp)
! 334: {
! 335: struct itref *ir;
! 336:
! 337: SIMPLEQ_FOREACH(ir, &tmp->it_refs, ir_next) {
! 338: if (ir->ir_itp == it)
! 339: return;
! 340: }
! 341:
! 342: ir = pmalloc(&ir_pool, sizeof(*ir));
! 343: ir->ir_itp = it;
! 344: SIMPLEQ_INSERT_TAIL(&tmp->it_refs, ir, ir_next);
! 345: }
! 346:
! 347: void
! 348: ir_purge(struct itype *it)
! 349: {
! 350: struct itref *ir;
! 351:
! 352: while ((ir = SIMPLEQ_FIRST(&it->it_refs)) != NULL) {
! 353: SIMPLEQ_REMOVE_HEAD(&it->it_refs, ir_next);
! 354: pfree(&ir_pool, ir);
! 355: }
! 356: }
! 357:
! 358: struct imember *
! 359: im_new(const char *name, size_t ref, size_t off)
! 360: {
! 361: struct imember *im;
! 362:
! 363: im = pmalloc(&im_pool, sizeof(*im));
! 364: im->im_ref = ref;
! 365: im->im_off = off;
! 366: im->im_refp = NULL;
! 367: if (name == NULL) {
! 368: im->im_flags = ITM_ANON;
! 369: } else {
! 370: size_t n;
! 371:
! 372: n = strlcpy(im->im_name, name, ITNAME_MAX);
! 373: if (n > ITNAME_MAX)
! 374: warnx("name %s too long %zd > %d", name, n,
! 375: ITNAME_MAX);
! 376: im->im_flags = 0;
! 377: }
! 378:
! 379: return im;
! 380: }
! 381:
! 382: void
! 383: cu_stat(void)
! 384: {
! 385: #ifndef NOPOOL
! 386: pool_dump();
! 387: #endif
! 388: }
! 389: /*
! 390: * Worst case it's a O(n*n) resolution lookup, with ``n'' being the number
! 391: * of elements in ``cutq''.
! 392: */
! 393: void
! 394: cu_resolve(struct dwcu *dcu, struct itype_queue *cutq, struct ioff_tree *cuot)
! 395: {
! 396: struct itype *it, *ref, tmp;
! 397: struct imember *im;
! 398: unsigned int toresolve;
! 399: size_t off = dcu->dcu_offset;
! 400:
! 401: TAILQ_FOREACH(it, cutq, it_next) {
! 402: if (!(it->it_flags & (ITF_UNRES|ITF_UNRES_MEMB)))
! 403: continue;
! 404:
! 405: if (it->it_flags & ITF_UNRES) {
! 406: tmp.it_off = it->it_ref + off;
! 407: ref = RB_FIND(ioff_tree, cuot, &tmp);
! 408: if (ref != NULL) {
! 409: it->it_refp = ref;
! 410: ir_add(it, ref);
! 411: it->it_flags &= ~ITF_UNRES;
! 412: }
! 413: }
! 414:
! 415: /* All members need to be resolved. */
! 416: toresolve = it->it_nelems;
! 417: if ((it->it_flags & ITF_UNRES_MEMB) && toresolve > 0) {
! 418: TAILQ_FOREACH(im, &it->it_members, im_next) {
! 419: tmp.it_off = im->im_ref + off;
! 420: ref = RB_FIND(ioff_tree, cuot, &tmp);
! 421: if (ref != NULL) {
! 422: im->im_refp = ref;
! 423: ir_add(it, ref);
! 424: toresolve--;
! 425: }
! 426: }
! 427: if (toresolve == 0)
! 428: it->it_flags &= ~ITF_UNRES_MEMB;
! 429: }
! 430: #if defined(DEBUG)
! 431: if (it->it_flags & (ITF_UNRES|ITF_UNRES_MEMB)) {
! 432: printf("0x%zx: %s type=%d unresolved 0x%llx",
! 433: it->it_off, it_name(it), it->it_type, it->it_ref);
! 434: if (toresolve)
! 435: printf(": %d members", toresolve);
! 436: TAILQ_FOREACH(im, &it->it_members, im_next) {
! 437: if (im->im_refp == NULL) {
! 438: printf("\n%zu: %s", im->im_ref,
! 439: im->im_name);
! 440: }
! 441: }
! 442: printf("\n");
! 443: }
! 444: #endif /* defined(DEBUG) */
! 445: }
! 446:
! 447: RB_FOREACH_SAFE(it, ioff_tree, cuot, ref)
! 448: RB_REMOVE(ioff_tree, cuot, it);
! 449: }
! 450:
! 451: void
! 452: cu_reference(struct dwcu *dcu, struct itype_queue *cutq)
! 453: {
! 454: struct itype *it;
! 455:
! 456: TAILQ_FOREACH(it, cutq, it_next) {
! 457: if (it->it_flags & (ITF_OBJ|ITF_FUNC))
! 458: it_reference(it);
! 459: }
! 460: }
! 461:
! 462: /*
! 463: * Merge type representation from a CU with already known types.
! 464: */
! 465: void
! 466: cu_merge(struct dwcu *dcu, struct itype_queue *cutq)
! 467: {
! 468: struct itype *it, *nit, *prev, *first;
! 469: int diff;
! 470:
! 471: /* First ``it'' that needs a duplicate check. */
! 472: first = TAILQ_FIRST(cutq);
! 473: if (first == NULL)
! 474: return;
! 475:
! 476: TAILQ_CONCAT(&itypeq, cutq, it_next);
! 477:
! 478: /*
! 479: * First pass: merge types
! 480: */
! 481: for (it = first; it != NULL; it = nit) {
! 482: nit = TAILQ_NEXT(it, it_next);
! 483:
! 484: /* Move functions & variable to their own list. */
! 485: if (it->it_flags & (ITF_FUNC|ITF_OBJ)) {
! 486: /*
! 487: * FIXME: allow static variables with the same name
! 488: * to be of different type.
! 489: */
! 490: if (RB_FIND(isymb_tree, &isymbt, it) == NULL)
! 491: RB_INSERT(isymb_tree, &isymbt, it);
! 492: continue;
! 493: }
! 494:
! 495: /* Look if we already have this type. */
! 496: if (it->it_flags & ITF_USED)
! 497: prev = RB_FIND(itype_tree, &itypet[it->it_type], it);
! 498: else
! 499: prev = NULL;
! 500:
! 501: if (prev != NULL) {
! 502: struct itype *old = it;
! 503: struct itref *ir;
! 504: struct imember *im;
! 505:
! 506: /* Substitute references */
! 507: while ((ir = SIMPLEQ_FIRST(&old->it_refs)) != NULL) {
! 508: it = ir->ir_itp;
! 509:
! 510: SIMPLEQ_REMOVE_HEAD(&old->it_refs, ir_next);
! 511: pfree(&ir_pool, ir);
! 512:
! 513: if (it->it_refp == old)
! 514: it->it_refp = prev;
! 515:
! 516: TAILQ_FOREACH(im, &it->it_members, im_next) {
! 517: if (im->im_refp == old)
! 518: im->im_refp = prev;
! 519: }
! 520: }
! 521:
! 522: old->it_flags &= ~ITF_USED;
! 523: } else if (it->it_flags & ITF_USED) {
! 524: RB_INSERT(itype_tree, &itypet[it->it_type], it);
! 525: }
! 526: }
! 527:
! 528: /*
! 529: * Second pass: update indexes
! 530: */
! 531: diff = 0;
! 532: for (it = first; it != NULL; it = nit) {
! 533: nit = TAILQ_NEXT(it, it_next);
! 534:
! 535: if (it->it_flags & (ITF_FUNC|ITF_OBJ))
! 536: continue;
! 537:
! 538: /* Adjust indexes */
! 539: if (it->it_flags & ITF_USED) {
! 540: it->it_idx -= diff;
! 541: continue;
! 542: }
! 543:
! 544: /* Remove unused */
! 545: TAILQ_REMOVE(&itypeq, it, it_next);
! 546: it_free(it);
! 547: diff++;
! 548: }
! 549:
! 550: /* Update global index to match removed entries. */
! 551: it = TAILQ_LAST(&itypeq, itype_queue);
! 552: while (it->it_flags & (ITF_FUNC|ITF_OBJ))
! 553: it = TAILQ_PREV(it, itype_queue, it_next);
! 554:
! 555: tidx = it->it_idx;
! 556: }
! 557:
! 558: /*
! 559: * Parse a CU.
! 560: */
! 561: void
! 562: cu_parse(struct dwcu *dcu, struct itype_queue *cutq, struct ioff_tree *cuot)
! 563: {
! 564: struct itype *it = NULL;
! 565: struct dwdie *die;
! 566: size_t psz = dcu->dcu_psize;
! 567: size_t off = dcu->dcu_offset;
! 568:
! 569: assert(RB_EMPTY(cuot));
! 570:
! 571: SIMPLEQ_FOREACH(die, &dcu->dcu_dies, die_next) {
! 572: uint64_t tag = die->die_dab->dab_tag;
! 573:
! 574: switch (tag) {
! 575: case DW_TAG_array_type:
! 576: it = parse_array(die, dcu->dcu_psize);
! 577: break;
! 578: case DW_TAG_enumeration_type:
! 579: it = parse_enum(die, dcu->dcu_psize);
! 580: break;
! 581: case DW_TAG_pointer_type:
! 582: it = parse_refers(die, psz, CTF_K_POINTER);
! 583: break;
! 584: case DW_TAG_structure_type:
! 585: it = parse_struct(die, psz, CTF_K_STRUCT, off);
! 586: if (it == NULL)
! 587: continue;
! 588: break;
! 589: case DW_TAG_typedef:
! 590: it = parse_refers(die, psz, CTF_K_TYPEDEF);
! 591: break;
! 592: case DW_TAG_union_type:
! 593: it = parse_struct(die, psz, CTF_K_UNION, off);
! 594: if (it == NULL)
! 595: continue;
! 596: break;
! 597: case DW_TAG_base_type:
! 598: it = parse_base(die, psz);
! 599: break;
! 600: case DW_TAG_const_type:
! 601: it = parse_refers(die, psz, CTF_K_CONST);
! 602: break;
! 603: case DW_TAG_volatile_type:
! 604: it = parse_refers(die, psz, CTF_K_VOLATILE);
! 605: break;
! 606: case DW_TAG_restrict_type:
! 607: it = parse_refers(die, psz, CTF_K_RESTRICT);
! 608: break;
! 609: case DW_TAG_subprogram:
! 610: it = parse_function(die, psz);
! 611: if (it == NULL)
! 612: continue;
! 613: break;
! 614: case DW_TAG_subroutine_type:
! 615: it = parse_funcptr(die, psz);
! 616: break;
! 617: /*
! 618: * Children are assumed to be right after their parent in
! 619: * the list. The parent parsing function takes care of
! 620: * parsing them.
! 621: */
! 622: case DW_TAG_member:
! 623: assert(it->it_type == CTF_K_STRUCT ||
! 624: it->it_type == CTF_K_UNION ||
! 625: it->it_type == CTF_K_ENUM);
! 626: continue;
! 627: case DW_TAG_subrange_type:
! 628: assert(it->it_type == CTF_K_ARRAY);
! 629: continue;
! 630: case DW_TAG_formal_parameter:
! 631: /*
! 632: * If we skipped the second inline definition,
! 633: * skip its arguments.
! 634: */
! 635: if (it == NULL)
! 636: continue;
! 637:
! 638: /* See comment in subparse_arguments(). */
! 639: if (it->it_type == CTF_K_STRUCT ||
! 640: it->it_type == CTF_K_UNION ||
! 641: it->it_type == CTF_K_ENUM ||
! 642: it->it_type == CTF_K_TYPEDEF)
! 643: continue;
! 644:
! 645: if (it->it_flags & ITF_OBJ)
! 646: continue;
! 647:
! 648: assert(it->it_type == CTF_K_FUNCTION);
! 649: continue;
! 650: case DW_TAG_variable:
! 651: it = parse_variable(die, psz);
! 652: /* Unnamed variables are discarded. */
! 653: if (it == NULL)
! 654: continue;
! 655: break;
! 656: #if 1
! 657: case DW_TAG_lexical_block:
! 658: case DW_TAG_inlined_subroutine:
! 659: continue;
! 660: #endif
! 661: case DW_TAG_compile_unit:
! 662: default:
! 663: DPRINTF("%s\n", dw_tag2name(tag));
! 664: continue;
! 665: }
! 666:
! 667: TAILQ_INSERT_TAIL(cutq, it, it_next);
! 668: RB_INSERT(ioff_tree, cuot, it);
! 669: }
! 670: }
! 671:
! 672: struct itype *
! 673: parse_base(struct dwdie *die, size_t psz)
! 674: {
! 675: struct itype *it;
! 676: struct dwaval *dav;
! 677: uint16_t encoding, enc = 0, bits = 0;
! 678: int type;
! 679:
! 680: SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
! 681: switch (dav->dav_dat->dat_attr) {
! 682: case DW_AT_encoding:
! 683: enc = dav2val(dav, psz);
! 684: break;
! 685: case DW_AT_byte_size:
! 686: bits = 8 * dav2val(dav, psz);
! 687: break;
! 688: default:
! 689: DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr));
! 690: break;
! 691: }
! 692: }
! 693:
! 694: switch (enc) {
! 695: case DW_ATE_unsigned:
! 696: case DW_ATE_address:
! 697: encoding = 0;
! 698: type = CTF_K_INTEGER;
! 699: break;
! 700: case DW_ATE_unsigned_char:
! 701: encoding = CTF_INT_CHAR;
! 702: type = CTF_K_INTEGER;
! 703: break;
! 704: case DW_ATE_signed:
! 705: encoding = CTF_INT_SIGNED;
! 706: type = CTF_K_INTEGER;
! 707: break;
! 708: case DW_ATE_signed_char:
! 709: encoding = CTF_INT_SIGNED | CTF_INT_CHAR;
! 710: type = CTF_K_INTEGER;
! 711: break;
! 712: case DW_ATE_boolean:
! 713: encoding = CTF_INT_SIGNED | CTF_INT_BOOL;
! 714: type = CTF_K_INTEGER;
! 715: break;
! 716: case DW_ATE_float:
! 717: if (bits < psz)
! 718: encoding = CTF_FP_SINGLE;
! 719: else if (bits == psz)
! 720: encoding = CTF_FP_DOUBLE;
! 721: else
! 722: encoding = CTF_FP_LDOUBLE;
! 723: type = CTF_K_FLOAT;
! 724: break;
! 725: case DW_ATE_complex_float:
! 726: if (bits < psz)
! 727: encoding = CTF_FP_CPLX;
! 728: else if (bits == psz)
! 729: encoding = CTF_FP_DCPLX;
! 730: else
! 731: encoding = CTF_FP_LDCPLX;
! 732: type = CTF_K_FLOAT;
! 733: break;
! 734: case DW_ATE_imaginary_float:
! 735: if (bits < psz)
! 736: encoding = CTF_FP_IMAGRY;
! 737: else if (bits == psz)
! 738: encoding = CTF_FP_DIMAGRY;
! 739: else
! 740: encoding = CTF_FP_LDIMAGRY;
! 741: type = CTF_K_FLOAT;
! 742: break;
! 743: default:
! 744: DPRINTF("unknown encoding: %d\n", enc);
! 745: return (NULL);
! 746: }
! 747:
! 748: it = it_new(++tidx, die->die_offset, enc2name(enc), bits,
! 749: encoding, 0, type, 0);
! 750:
! 751: return it;
! 752: }
! 753:
! 754: struct itype *
! 755: parse_refers(struct dwdie *die, size_t psz, int type)
! 756: {
! 757: struct itype *it;
! 758: struct dwaval *dav;
! 759: const char *name = NULL;
! 760: size_t ref = 0, size = 0;
! 761:
! 762: SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
! 763: switch (dav->dav_dat->dat_attr) {
! 764: case DW_AT_name:
! 765: name = dav2str(dav);
! 766: break;
! 767: case DW_AT_type:
! 768: ref = dav2val(dav, psz);
! 769: break;
! 770: case DW_AT_byte_size:
! 771: size = dav2val(dav, psz);
! 772: assert(size < UINT_MAX);
! 773: break;
! 774: default:
! 775: DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr));
! 776: break;
! 777: }
! 778: }
! 779:
! 780: it = it_new(++tidx, die->die_offset, name, size, 0, ref, type,
! 781: ITF_UNRES);
! 782:
! 783: if (it->it_ref == 0 && (it->it_size == sizeof(void *) ||
! 784: type == CTF_K_CONST || type == CTF_K_VOLATILE ||
! 785: type == CTF_K_POINTER)) {
! 786: /* Work around GCC/clang not emiting a type for void */
! 787: it->it_flags &= ~ITF_UNRES;
! 788: it->it_ref = VOID_OFFSET;
! 789: it->it_refp = void_it;
! 790: }
! 791:
! 792: return it;
! 793: }
! 794:
! 795: struct itype *
! 796: parse_array(struct dwdie *die, size_t psz)
! 797: {
! 798: struct itype *it;
! 799: struct dwaval *dav;
! 800: const char *name = NULL;
! 801: size_t ref = 0;
! 802:
! 803: SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
! 804: switch (dav->dav_dat->dat_attr) {
! 805: case DW_AT_name:
! 806: name = dav2str(dav);
! 807: break;
! 808: case DW_AT_type:
! 809: ref = dav2val(dav, psz);
! 810: break;
! 811: default:
! 812: DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr));
! 813: break;
! 814: }
! 815: }
! 816:
! 817: it = it_new(++tidx, die->die_offset, name, 0, 0, ref, CTF_K_ARRAY,
! 818: ITF_UNRES);
! 819:
! 820: subparse_subrange(die, psz, it);
! 821:
! 822: return it;
! 823: }
! 824:
! 825: struct itype *
! 826: parse_enum(struct dwdie *die, size_t psz)
! 827: {
! 828: struct itype *it;
! 829: struct dwaval *dav;
! 830: const char *name = NULL;
! 831: size_t size = 0;
! 832:
! 833: SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
! 834: switch (dav->dav_dat->dat_attr) {
! 835: case DW_AT_byte_size:
! 836: size = dav2val(dav, psz);
! 837: assert(size < UINT_MAX);
! 838: break;
! 839: case DW_AT_name:
! 840: name = dav2str(dav);
! 841: break;
! 842: default:
! 843: DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr));
! 844: break;
! 845: }
! 846: }
! 847:
! 848: it = it_new(++tidx, die->die_offset, name, size, 0, 0, CTF_K_ENUM, 0);
! 849:
! 850: subparse_enumerator(die, psz, it);
! 851:
! 852: return it;
! 853: }
! 854:
! 855: void
! 856: subparse_subrange(struct dwdie *die, size_t psz, struct itype *it)
! 857: {
! 858: struct dwaval *dav;
! 859:
! 860: assert(it->it_type == CTF_K_ARRAY);
! 861:
! 862: if (die->die_dab->dab_children == DW_CHILDREN_no)
! 863: return;
! 864:
! 865: /*
! 866: * This loop assumes that the children of a DIE are just
! 867: * after it on the list.
! 868: */
! 869: while ((die = SIMPLEQ_NEXT(die, die_next)) != NULL) {
! 870: uint64_t tag = die->die_dab->dab_tag;
! 871: size_t nelems = 0;
! 872:
! 873: if (tag != DW_TAG_subrange_type)
! 874: break;
! 875:
! 876: SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
! 877: switch (dav->dav_dat->dat_attr) {
! 878: case DW_AT_count:
! 879: nelems = dav2val(dav, psz);
! 880: break;
! 881: case DW_AT_upper_bound:
! 882: nelems = dav2val(dav, psz) + 1;
! 883: break;
! 884: default:
! 885: DPRINTF("%s\n",
! 886: dw_at2name(dav->dav_dat->dat_attr));
! 887: break;
! 888: }
! 889: }
! 890:
! 891: assert(nelems < UINT_MAX);
! 892: it->it_nelems = nelems;
! 893: }
! 894: }
! 895:
! 896: void
! 897: subparse_enumerator(struct dwdie *die, size_t psz, struct itype *it)
! 898: {
! 899: struct imember *im;
! 900: struct dwaval *dav;
! 901:
! 902: assert(it->it_type == CTF_K_ENUM);
! 903:
! 904: if (die->die_dab->dab_children == DW_CHILDREN_no)
! 905: return;
! 906:
! 907: /*
! 908: * This loop assumes that the children of a DIE are just
! 909: * after it on the list.
! 910: */
! 911: while ((die = SIMPLEQ_NEXT(die, die_next)) != NULL) {
! 912: uint64_t tag = die->die_dab->dab_tag;
! 913: size_t val = 0;
! 914: const char *name = NULL;
! 915:
! 916: if (tag != DW_TAG_enumerator)
! 917: break;
! 918:
! 919: SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
! 920: switch (dav->dav_dat->dat_attr) {
! 921: case DW_AT_name:
! 922: name = dav2str(dav);
! 923: break;
! 924: case DW_AT_const_value:
! 925: val = dav2val(dav, psz);
! 926: break;
! 927: default:
! 928: DPRINTF("%s\n",
! 929: dw_at2name(dav->dav_dat->dat_attr));
! 930: break;
! 931: }
! 932: }
! 933:
! 934: if (name == NULL) {
! 935: warnx("%s with anon member", it_name(it));
! 936: continue;
! 937: }
! 938:
! 939: im = im_new(name, val, 0);
! 940: assert(it->it_nelems < UINT_MAX);
! 941: it->it_nelems++;
! 942: TAILQ_INSERT_TAIL(&it->it_members, im, im_next);
! 943: }
! 944: }
! 945:
! 946: struct itype *
! 947: parse_struct(struct dwdie *die, size_t psz, int type, size_t off)
! 948: {
! 949: struct itype *it = NULL;
! 950: struct dwaval *dav;
! 951: const char *name = NULL;
! 952: size_t size = 0;
! 953:
! 954: SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
! 955: switch (dav->dav_dat->dat_attr) {
! 956: case DW_AT_byte_size:
! 957: size = dav2val(dav, psz);
! 958: assert(size < UINT_MAX);
! 959: break;
! 960: case DW_AT_name:
! 961: name = dav2str(dav);
! 962: break;
! 963: default:
! 964: DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr));
! 965: break;
! 966: }
! 967: }
! 968:
! 969: it = it_new(++tidx, die->die_offset, name, size, 0, 0, type, 0);
! 970:
! 971: subparse_member(die, psz, it, off);
! 972:
! 973: return it;
! 974: }
! 975:
! 976: void
! 977: subparse_member(struct dwdie *die, size_t psz, struct itype *it, size_t offset)
! 978: {
! 979: struct imember *im;
! 980: struct dwaval *dav;
! 981: const char *name;
! 982: size_t off = 0, ref = 0, bits = 0;
! 983: uint8_t lvl = die->die_lvl;
! 984:
! 985: assert(it->it_type == CTF_K_STRUCT || it->it_type == CTF_K_UNION);
! 986:
! 987: if (die->die_dab->dab_children == DW_CHILDREN_no)
! 988: return;
! 989:
! 990: /*
! 991: * This loop assumes that the children of a DIE are just
! 992: * after it on the list.
! 993: */
! 994: while ((die = SIMPLEQ_NEXT(die, die_next)) != NULL) {
! 995: int64_t tag = die->die_dab->dab_tag;
! 996:
! 997: name = NULL;
! 998: if (die->die_lvl <= lvl)
! 999: break;
! 1000:
! 1001: /* Skip members of members */
! 1002: if (die->die_lvl > lvl + 1)
! 1003: continue;
! 1004:
! 1005: it->it_flags |= ITF_UNRES_MEMB;
! 1006:
! 1007: SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
! 1008: switch (dav->dav_dat->dat_attr) {
! 1009: case DW_AT_name:
! 1010: name = dav2str(dav);
! 1011: break;
! 1012: case DW_AT_type:
! 1013: ref = dav2val(dav, psz);
! 1014: break;
! 1015: case DW_AT_data_member_location:
! 1016: off = 8 * dav2val(dav, psz);
! 1017: break;
! 1018: case DW_AT_bit_size:
! 1019: bits = dav2val(dav, psz);
! 1020: assert(bits < USHRT_MAX);
! 1021: break;
! 1022: default:
! 1023: DPRINTF("%s\n",
! 1024: dw_at2name(dav->dav_dat->dat_attr));
! 1025: break;
! 1026: }
! 1027: }
! 1028:
! 1029: /*
! 1030: * When a structure is declared inside an union, we
! 1031: * have to generate a reference to make the resolver
! 1032: * happy.
! 1033: */
! 1034: if ((ref == 0) && (tag == DW_TAG_structure_type))
! 1035: ref = die->die_offset - offset;
! 1036:
! 1037: im = im_new(name, ref, off);
! 1038: assert(it->it_nelems < UINT_MAX);
! 1039: it->it_nelems++;
! 1040: TAILQ_INSERT_TAIL(&it->it_members, im, im_next);
! 1041: }
! 1042: }
! 1043:
! 1044:
! 1045: void
! 1046: subparse_arguments(struct dwdie *die, size_t psz, struct itype *it)
! 1047: {
! 1048: struct imember *im;
! 1049: struct dwaval *dav;
! 1050: size_t ref = 0;
! 1051:
! 1052: assert(it->it_type == CTF_K_FUNCTION);
! 1053:
! 1054: if (die->die_dab->dab_children == DW_CHILDREN_no)
! 1055: return;
! 1056:
! 1057: /*
! 1058: * This loop assumes that the children of a DIE are after it
! 1059: * on the list.
! 1060: */
! 1061: while ((die = SIMPLEQ_NEXT(die, die_next)) != NULL) {
! 1062: uint64_t tag = die->die_dab->dab_tag;
! 1063:
! 1064: if (tag == DW_TAG_unspecified_parameters) {
! 1065: it->it_flags |= ITF_VARARGS;
! 1066: continue;
! 1067: }
! 1068:
! 1069: /*
! 1070: * Nested declaration.
! 1071: *
! 1072: * This matches the case where a ``struct'', ``union'',
! 1073: * ``enum'' or ``typedef'' is first declared "inside" a
! 1074: * function declaration.
! 1075: */
! 1076: if (tag == DW_TAG_structure_type || tag == DW_TAG_union_type ||
! 1077: tag == DW_TAG_enumeration_type || tag == DW_TAG_typedef)
! 1078: continue;
! 1079:
! 1080: if (tag != DW_TAG_formal_parameter)
! 1081: break;
! 1082:
! 1083: it->it_flags |= ITF_UNRES_MEMB;
! 1084:
! 1085: SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
! 1086: switch (dav->dav_dat->dat_attr) {
! 1087: case DW_AT_type:
! 1088: ref = dav2val(dav, psz);
! 1089: break;
! 1090: default:
! 1091: DPRINTF("%s\n",
! 1092: dw_at2name(dav->dav_dat->dat_attr));
! 1093: break;
! 1094: }
! 1095: }
! 1096:
! 1097: im = im_new(NULL, ref, 0);
! 1098: assert(it->it_nelems < UINT_MAX);
! 1099: it->it_nelems++;
! 1100: TAILQ_INSERT_TAIL(&it->it_members, im, im_next);
! 1101: }
! 1102: }
! 1103:
! 1104: struct itype *
! 1105: parse_function(struct dwdie *die, size_t psz)
! 1106: {
! 1107: struct itype *it;
! 1108: struct dwaval *dav;
! 1109: const char *name = NULL;
! 1110: size_t ref = 0;
! 1111:
! 1112: SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
! 1113: switch (dav->dav_dat->dat_attr) {
! 1114: case DW_AT_name:
! 1115: name = dav2str(dav);
! 1116: break;
! 1117: case DW_AT_type:
! 1118: ref = dav2val(dav, psz);
! 1119: break;
! 1120: case DW_AT_abstract_origin:
! 1121: /*
! 1122: * Skip second empty definition for inline
! 1123: * functions.
! 1124: */
! 1125: return NULL;
! 1126: default:
! 1127: DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr));
! 1128: break;
! 1129: }
! 1130: }
! 1131:
! 1132: /*
! 1133: * Work around for clang 4.0 generating DW_TAG_subprogram without
! 1134: * any attribute.
! 1135: */
! 1136: if (name == NULL)
! 1137: return NULL;
! 1138:
! 1139: it = it_new(++fidx, die->die_offset, name, 0, 0, ref, CTF_K_FUNCTION,
! 1140: ITF_UNRES|ITF_FUNC);
! 1141:
! 1142: subparse_arguments(die, psz, it);
! 1143:
! 1144: if (it->it_ref == 0) {
! 1145: /* Work around GCC not emiting a type for void */
! 1146: it->it_flags &= ~ITF_UNRES;
! 1147: it->it_ref = VOID_OFFSET;
! 1148: it->it_refp = void_it;
! 1149: }
! 1150:
! 1151: return it;
! 1152: }
! 1153:
! 1154: struct itype *
! 1155: parse_funcptr(struct dwdie *die, size_t psz)
! 1156: {
! 1157: struct itype *it;
! 1158: struct dwaval *dav;
! 1159: const char *name = NULL;
! 1160: size_t ref = 0;
! 1161:
! 1162: SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
! 1163: switch (dav->dav_dat->dat_attr) {
! 1164: case DW_AT_name:
! 1165: name = dav2str(dav);
! 1166: break;
! 1167: case DW_AT_type:
! 1168: ref = dav2val(dav, psz);
! 1169: break;
! 1170: default:
! 1171: DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr));
! 1172: break;
! 1173: }
! 1174: }
! 1175:
! 1176: it = it_new(++tidx, die->die_offset, name, 0, 0, ref, CTF_K_FUNCTION,
! 1177: ITF_UNRES);
! 1178:
! 1179: subparse_arguments(die, psz, it);
! 1180:
! 1181: if (it->it_ref == 0) {
! 1182: /* Work around GCC not emiting a type for void */
! 1183: it->it_flags &= ~ITF_UNRES;
! 1184: it->it_ref = VOID_OFFSET;
! 1185: it->it_refp = void_it;
! 1186: }
! 1187:
! 1188: return it;
! 1189: }
! 1190:
! 1191: struct itype *
! 1192: parse_variable(struct dwdie *die, size_t psz)
! 1193: {
! 1194: struct itype *it = NULL;
! 1195: struct dwaval *dav;
! 1196: const char *name = NULL;
! 1197: size_t ref = 0;
! 1198: int declaration = 0;
! 1199:
! 1200: SIMPLEQ_FOREACH(dav, &die->die_avals, dav_next) {
! 1201: switch (dav->dav_dat->dat_attr) {
! 1202: case DW_AT_declaration:
! 1203: declaration = dav2val(dav, psz);
! 1204: break;
! 1205: case DW_AT_name:
! 1206: name = dav2str(dav);
! 1207: break;
! 1208: case DW_AT_type:
! 1209: ref = dav2val(dav, psz);
! 1210: break;
! 1211: default:
! 1212: DPRINTF("%s\n", dw_at2name(dav->dav_dat->dat_attr));
! 1213: break;
! 1214: }
! 1215: }
! 1216:
! 1217:
! 1218: if (!declaration && name != NULL) {
! 1219: it = it_new(++oidx, die->die_offset, name, 0, 0, ref, 0,
! 1220: ITF_UNRES|ITF_OBJ);
! 1221: }
! 1222:
! 1223: return it;
! 1224: }
! 1225:
! 1226: size_t
! 1227: dav2val(struct dwaval *dav, size_t psz)
! 1228: {
! 1229: uint64_t val = (uint64_t)-1;
! 1230:
! 1231: switch (dav->dav_dat->dat_form) {
! 1232: case DW_FORM_addr:
! 1233: case DW_FORM_ref_addr:
! 1234: if (psz == sizeof(uint32_t))
! 1235: val = dav->dav_u32;
! 1236: else
! 1237: val = dav->dav_u64;
! 1238: break;
! 1239: case DW_FORM_block1:
! 1240: case DW_FORM_block2:
! 1241: case DW_FORM_block4:
! 1242: case DW_FORM_block:
! 1243: dw_loc_parse(&dav->dav_buf, NULL, &val, NULL);
! 1244: break;
! 1245: case DW_FORM_flag:
! 1246: case DW_FORM_data1:
! 1247: case DW_FORM_ref1:
! 1248: val = dav->dav_u8;
! 1249: break;
! 1250: case DW_FORM_data2:
! 1251: case DW_FORM_ref2:
! 1252: val = dav->dav_u16;
! 1253: break;
! 1254: case DW_FORM_data4:
! 1255: case DW_FORM_ref4:
! 1256: val = dav->dav_u32;
! 1257: break;
! 1258: case DW_FORM_sdata:
! 1259: case DW_FORM_data8:
! 1260: case DW_FORM_ref8:
! 1261: val = dav->dav_u64;
! 1262: break;
! 1263: case DW_FORM_strp:
! 1264: val = dav->dav_u32;
! 1265: break;
! 1266: case DW_FORM_flag_present:
! 1267: val = 1;
! 1268: break;
! 1269: default:
! 1270: break;
! 1271: }
! 1272:
! 1273: return val;
! 1274: }
! 1275:
! 1276: const char *
! 1277: dav2str(struct dwaval *dav)
! 1278: {
! 1279: const char *str = NULL;
! 1280: extern const char *dstrbuf;
! 1281:
! 1282: switch (dav->dav_dat->dat_form) {
! 1283: case DW_FORM_string:
! 1284: str = dav->dav_str;
! 1285: break;
! 1286: case DW_FORM_strp:
! 1287: str = dstrbuf + dav->dav_u32;
! 1288: break;
! 1289: default:
! 1290: break;
! 1291: }
! 1292:
! 1293: return str;
! 1294: }
! 1295:
! 1296: const char *
! 1297: enc2name(unsigned short enc)
! 1298: {
! 1299: static const char *enc_name[] = { "address", "boolean", "complex float",
! 1300: "float", "signed", "char", "unsigned", "unsigned char",
! 1301: "imaginary float", "packed decimal", "numeric string", "edited",
! 1302: "signed fixed", "unsigned fixed", "decimal float" };
! 1303:
! 1304: if (enc > 0 && enc <= nitems(enc_name))
! 1305: return enc_name[enc - 1];
! 1306:
! 1307: return "invalid";
! 1308: }