1 /* $OpenBSD: dw.c,v 1.4 2017/09/27 08:59:38 mpi Exp $ */ 2 3 /* 4 * Copyright (c) 2016 Martin Pieuchot 5 * Copyright (c) 2014 Matthew Dempsky <matthew@dempsky.org> 6 * 7 * Permission to use, copy, modify, and distribute this software for any 8 * purpose with or without fee is hereby granted, provided that the above 9 * copyright notice and this permission notice appear in all copies. 10 * 11 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 12 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 13 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 14 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 15 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 16 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 17 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 18 */ 19 20 #include <sys/queue.h> 21 22 #include <errno.h> 23 #include <stdint.h> 24 #include <stdlib.h> 25 #include <string.h> 26 27 #include "dw.h" 28 #include "dwarf.h" 29 #include "pool.h" 30 31 #ifndef NOPOOL 32 struct pool dcu_pool, die_pool, dav_pool, dab_pool, dat_pool; 33 #endif /* NOPOOL */ 34 35 #ifndef nitems 36 #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0])) 37 #endif 38 39 static int dw_read_u8(struct dwbuf *, uint8_t *); 40 static int dw_read_u16(struct dwbuf *, uint16_t *); 41 static int dw_read_u32(struct dwbuf *, uint32_t *); 42 static int dw_read_u64(struct dwbuf *, uint64_t *); 43 44 static int dw_read_sleb128(struct dwbuf *, int64_t *); 45 static int dw_read_uleb128(struct dwbuf *, uint64_t *); 46 47 static int dw_read_bytes(struct dwbuf *, void *, size_t); 48 static int dw_read_string(struct dwbuf *, const char **); 49 static int dw_read_buf(struct dwbuf *, struct dwbuf *, size_t); 50 51 static int dw_skip_bytes(struct dwbuf *, size_t); 52 53 static int dw_read_filename(struct dwbuf *, const char **, const char **, 54 uint8_t, uint64_t); 55 56 57 static int dw_attr_parse(struct dwbuf *, struct dwattr *, uint8_t, 58 struct dwaval_queue *); 59 static void dw_attr_purge(struct dwaval_queue *); 60 static int dw_die_parse(struct dwbuf *, size_t, uint8_t, 61 struct dwabbrev_queue *, struct dwdie_queue *); 62 static void dw_die_purge(struct dwdie_queue *); 63 64 static int 65 dw_read_bytes(struct dwbuf *d, void *v, size_t n) 66 { 67 if (d->len < n) 68 return -1; 69 memcpy(v, d->buf, n); 70 d->buf += n; 71 d->len -= n; 72 return 0; 73 } 74 75 static int 76 dw_read_u8(struct dwbuf *d, uint8_t *v) 77 { 78 return dw_read_bytes(d, v, sizeof(*v)); 79 } 80 81 static int 82 dw_read_u16(struct dwbuf *d, uint16_t *v) 83 { 84 return dw_read_bytes(d, v, sizeof(*v)); 85 } 86 87 static int 88 dw_read_u32(struct dwbuf *d, uint32_t *v) 89 { 90 return dw_read_bytes(d, v, sizeof(*v)); 91 } 92 93 static int 94 dw_read_u64(struct dwbuf *d, uint64_t *v) 95 { 96 return dw_read_bytes(d, v, sizeof(*v)); 97 } 98 99 /* Read a DWARF LEB128 (little-endian base-128) value. */ 100 static inline int 101 dw_read_leb128(struct dwbuf *d, uint64_t *v, int signextend) 102 { 103 unsigned int shift = 0; 104 uint64_t res = 0; 105 uint8_t x; 106 107 while (shift < 64 && !dw_read_u8(d, &x)) { 108 res |= (uint64_t)(x & 0x7f) << shift; 109 shift += 7; 110 if ((x & 0x80) == 0) { 111 if (signextend && shift < 64 && (x & 0x40) != 0) 112 res |= ~(uint64_t)0 << shift; 113 *v = res; 114 return 0; 115 } 116 } 117 return -1; 118 } 119 120 static int 121 dw_read_sleb128(struct dwbuf *d, int64_t *v) 122 { 123 return dw_read_leb128(d, (uint64_t *)v, 1); 124 } 125 126 static int 127 dw_read_uleb128(struct dwbuf *d, uint64_t *v) 128 { 129 return dw_read_leb128(d, v, 0); 130 } 131 132 /* Read a NUL terminated string. */ 133 static int 134 dw_read_string(struct dwbuf *d, const char **s) 135 { 136 const char *end = memchr(d->buf, '\0', d->len); 137 size_t n; 138 139 if (end == NULL) 140 return -1; 141 142 n = end - d->buf + 1; 143 *s = d->buf; 144 d->buf += n; 145 d->len -= n; 146 return 0; 147 } 148 149 static int 150 dw_read_buf(struct dwbuf *d, struct dwbuf *v, size_t n) 151 { 152 if (d->len < n) 153 return -1; 154 v->buf = d->buf; 155 v->len = n; 156 d->buf += n; 157 d->len -= n; 158 return 0; 159 } 160 161 static int 162 dw_skip_bytes(struct dwbuf *d, size_t n) 163 { 164 if (d->len < n) 165 return -1; 166 d->buf += n; 167 d->len -= n; 168 return 0; 169 } 170 171 static int 172 dw_read_filename(struct dwbuf *names, const char **outdirname, 173 const char **outbasename, uint8_t opcode_base, uint64_t file) 174 { 175 struct dwbuf dirnames; 176 const char *basename = NULL, *dirname = NULL; 177 uint64_t mtime, size, dummy, dir = 0; 178 const char *name; 179 size_t i; 180 181 if (file == 0) 182 return -1; 183 184 /* Skip over opcode table. */ 185 for (i = 1; i < opcode_base; i++) { 186 if (dw_read_uleb128(names, &dummy)) 187 return -1; 188 } 189 190 /* Skip over directory name table for now. */ 191 dirnames = *names; 192 for (;;) { 193 if (dw_read_string(names, &name)) 194 return -1; 195 if (*name == '\0') 196 break; 197 } 198 199 /* Locate file entry. */ 200 for (i = 0; i < file; i++) { 201 if (dw_read_string(names, &basename) || *basename == '\0' || 202 dw_read_uleb128(names, &dir) || 203 dw_read_uleb128(names, &mtime) || 204 dw_read_uleb128(names, &size)) 205 return -1; 206 } 207 208 for (i = 0; i < dir; i++) { 209 if (!dw_read_string(&dirnames, &dirname) || *dirname == '\0') 210 return -1; 211 } 212 213 *outdirname = dirname; 214 *outbasename = basename; 215 216 return 0; 217 } 218 219 220 const char * 221 dw_tag2name(uint64_t tag) 222 { 223 static const char *dw_tags[] = { DW_TAG_NAMES }; 224 225 if (tag <= nitems(dw_tags)) 226 return dw_tags[tag - 1]; 227 228 if (tag == DW_TAG_lo_user) 229 return "DW_TAG_lo_user"; 230 if (tag == DW_TAG_hi_user) 231 return "DW_TAG_hi_user"; 232 233 return NULL; 234 } 235 236 const char * 237 dw_at2name(uint64_t at) 238 { 239 static const char *dw_attrs[] = { DW_AT_NAMES }; 240 241 if (at <= nitems(dw_attrs)) 242 return dw_attrs[at - 1]; 243 244 if (at == DW_AT_lo_user) 245 return "DW_AT_lo_user"; 246 if (at == DW_AT_hi_user) 247 return "DW_AT_hi_user"; 248 249 return NULL; 250 } 251 252 const char * 253 dw_form2name(uint64_t form) 254 { 255 static const char *dw_forms[] = { DW_FORM_NAMES }; 256 257 if (form <= nitems(dw_forms)) 258 return dw_forms[form - 1]; 259 260 if (form == DW_FORM_GNU_ref_alt) 261 return "DW_FORM_GNU_ref_alt"; 262 if (form == DW_FORM_GNU_strp_alt) 263 return "DW_FORM_GNU_strp_alt"; 264 265 return NULL; 266 } 267 268 const char * 269 dw_op2name(uint8_t op) 270 { 271 static const char *dw_ops[] = { DW_OP_NAMES }; 272 273 if (op <= nitems(dw_ops)) 274 return dw_ops[op - 1]; 275 276 if (op == DW_OP_lo_user) 277 return "DW_OP_lo_user"; 278 if (op == DW_OP_hi_user) 279 return "DW_OP_hi_user"; 280 281 return NULL; 282 } 283 284 static int 285 dw_attr_parse(struct dwbuf *dwbuf, struct dwattr *dat, uint8_t psz, 286 struct dwaval_queue *davq) 287 { 288 struct dwaval *dav; 289 uint64_t form = dat->dat_form; 290 int error = 0, i = 0; 291 292 while (form == DW_FORM_indirect) { 293 /* XXX loop prevention not strict enough? */ 294 if (dw_read_uleb128(dwbuf, &form) || (++i > 3)) 295 return ELOOP; 296 } 297 298 dav = pzalloc(&dav_pool, sizeof(*dav)); 299 if (dav == NULL) 300 return ENOMEM; 301 302 dav->dav_dat = dat; 303 304 switch (form) { 305 case DW_FORM_addr: 306 case DW_FORM_ref_addr: 307 if (psz == sizeof(uint32_t)) 308 error = dw_read_u32(dwbuf, &dav->dav_u32); 309 else 310 error = dw_read_u64(dwbuf, &dav->dav_u64); 311 break; 312 case DW_FORM_block1: 313 error = dw_read_u8(dwbuf, &dav->dav_u8); 314 if (error == 0) 315 error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u8); 316 break; 317 case DW_FORM_block2: 318 error = dw_read_u16(dwbuf, &dav->dav_u16); 319 if (error == 0) 320 error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u16); 321 break; 322 case DW_FORM_block4: 323 error = dw_read_u32(dwbuf, &dav->dav_u32); 324 if (error == 0) 325 error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u32); 326 break; 327 case DW_FORM_block: 328 error = dw_read_uleb128(dwbuf, &dav->dav_u64); 329 if (error == 0) 330 error = dw_read_buf(dwbuf, &dav->dav_buf, dav->dav_u64); 331 break; 332 case DW_FORM_data1: 333 case DW_FORM_flag: 334 case DW_FORM_ref1: 335 error = dw_read_u8(dwbuf, &dav->dav_u8); 336 break; 337 case DW_FORM_data2: 338 case DW_FORM_ref2: 339 error = dw_read_u16(dwbuf, &dav->dav_u16); 340 break; 341 case DW_FORM_data4: 342 case DW_FORM_ref4: 343 error = dw_read_u32(dwbuf, &dav->dav_u32); 344 break; 345 case DW_FORM_data8: 346 case DW_FORM_ref8: 347 error = dw_read_u64(dwbuf, &dav->dav_u64); 348 break; 349 case DW_FORM_ref_udata: 350 case DW_FORM_udata: 351 error = dw_read_uleb128(dwbuf, &dav->dav_u64); 352 break; 353 case DW_FORM_sdata: 354 error = dw_read_sleb128(dwbuf, &dav->dav_s64); 355 break; 356 case DW_FORM_string: 357 error = dw_read_string(dwbuf, &dav->dav_str); 358 break; 359 case DW_FORM_strp: 360 error = dw_read_u32(dwbuf, &dav->dav_u32); 361 break; 362 case DW_FORM_flag_present: 363 dav->dav_u8 = 1; 364 break; 365 default: 366 error = ENOENT; 367 break; 368 } 369 370 if (error) { 371 pfree(&dav_pool, dav); 372 return error; 373 } 374 375 SIMPLEQ_INSERT_TAIL(davq, dav, dav_next); 376 return 0; 377 } 378 379 static void 380 dw_attr_purge(struct dwaval_queue *davq) 381 { 382 struct dwaval *dav; 383 384 while ((dav = SIMPLEQ_FIRST(davq)) != NULL) { 385 SIMPLEQ_REMOVE_HEAD(davq, dav_next); 386 pfree(&dav_pool, dav); 387 } 388 389 SIMPLEQ_INIT(davq); 390 } 391 392 static int 393 dw_die_parse(struct dwbuf *dwbuf, size_t nextoff, uint8_t psz, 394 struct dwabbrev_queue *dabq, struct dwdie_queue *dieq) 395 { 396 struct dwdie *die; 397 struct dwabbrev *dab; 398 struct dwattr *dat; 399 uint64_t code; 400 size_t doff; 401 uint8_t lvl = 0; 402 int error; 403 404 405 while (dwbuf->len > 0) { 406 doff = nextoff - dwbuf->len; 407 if (dw_read_uleb128(dwbuf, &code)) 408 return -1; 409 410 if (code == 0) { 411 lvl--; 412 continue; 413 } 414 415 SIMPLEQ_FOREACH(dab, dabq, dab_next) { 416 if (dab->dab_code == code) 417 break; 418 } 419 if (dab == NULL) 420 return ESRCH; 421 422 die = pmalloc(&die_pool, sizeof(*die)); 423 if (die == NULL) 424 return ENOMEM; 425 426 die->die_lvl = lvl; 427 die->die_dab = dab; 428 die->die_offset = doff; 429 SIMPLEQ_INIT(&die->die_avals); 430 431 SIMPLEQ_FOREACH(dat, &dab->dab_attrs, dat_next) { 432 error = dw_attr_parse(dwbuf, dat, psz, &die->die_avals); 433 if (error != 0) { 434 dw_attr_purge(&die->die_avals); 435 return error; 436 } 437 } 438 439 if (dab->dab_children == DW_CHILDREN_yes) 440 lvl++; 441 442 SIMPLEQ_INSERT_TAIL(dieq, die, die_next); 443 } 444 445 return 0; 446 } 447 448 static void 449 dw_die_purge(struct dwdie_queue *dieq) 450 { 451 struct dwdie *die; 452 453 while ((die = SIMPLEQ_FIRST(dieq)) != NULL) { 454 SIMPLEQ_REMOVE_HEAD(dieq, die_next); 455 dw_attr_purge(&die->die_avals); 456 pfree(&die_pool, die); 457 } 458 459 SIMPLEQ_INIT(dieq); 460 } 461 462 int 463 dw_ab_parse(struct dwbuf *abseg, struct dwabbrev_queue *dabq) 464 { 465 struct dwabbrev *dab; 466 uint64_t code, tag; 467 uint8_t children; 468 469 if (abseg->len == 0) 470 return EINVAL; 471 472 for (;;) { 473 if (dw_read_uleb128(abseg, &code) || (code == 0)) 474 break; 475 476 if (dw_read_uleb128(abseg, &tag) || 477 dw_read_u8(abseg, &children)) 478 return -1; 479 480 dab = pmalloc(&dab_pool, sizeof(*dab)); 481 if (dab == NULL) 482 return ENOMEM; 483 484 dab->dab_code = code; 485 dab->dab_tag = tag; 486 dab->dab_children = children; 487 SIMPLEQ_INIT(&dab->dab_attrs); 488 489 SIMPLEQ_INSERT_TAIL(dabq, dab, dab_next); 490 491 for (;;) { 492 struct dwattr *dat; 493 uint64_t attr = 0, form = 0; 494 495 if (dw_read_uleb128(abseg, &attr) || 496 dw_read_uleb128(abseg, &form)) 497 return -1; 498 499 if ((attr == 0) && (form == 0)) 500 break; 501 502 dat = pmalloc(&dat_pool, sizeof(*dat)); 503 if (dat == NULL) 504 return ENOMEM; 505 506 dat->dat_attr = attr; 507 dat->dat_form = form; 508 509 SIMPLEQ_INSERT_TAIL(&dab->dab_attrs, dat, dat_next); 510 } 511 } 512 513 return 0; 514 } 515 516 void 517 dw_dabq_purge(struct dwabbrev_queue *dabq) 518 { 519 struct dwabbrev *dab; 520 521 while ((dab = SIMPLEQ_FIRST(dabq)) != NULL) { 522 struct dwattr *dat; 523 524 SIMPLEQ_REMOVE_HEAD(dabq, dab_next); 525 while ((dat = SIMPLEQ_FIRST(&dab->dab_attrs)) != NULL) { 526 SIMPLEQ_REMOVE_HEAD(&dab->dab_attrs, dat_next); 527 pfree(&dat_pool, dat); 528 } 529 530 pfree(&dab_pool, dab); 531 } 532 533 SIMPLEQ_INIT(dabq); 534 } 535 536 int 537 dw_cu_parse(struct dwbuf *info, struct dwbuf *abbrev, size_t seglen, 538 struct dwcu **dcup) 539 { 540 struct dwbuf abseg = *abbrev; 541 struct dwbuf dwbuf; 542 size_t segoff, nextoff, addrsize; 543 struct dwcu *dcu = NULL; 544 uint32_t length = 0, abbroff = 0; 545 uint16_t version; 546 uint8_t psz; 547 int error; 548 #ifndef NOPOOL 549 static int dw_pool_inited = 0; 550 551 if (!dw_pool_inited) { 552 pool_init(&dcu_pool, "dcu", 1, sizeof(struct dwcu)); 553 pool_init(&dab_pool, "dab", 32, sizeof(struct dwabbrev)); 554 pool_init(&dat_pool, "dat", 32, sizeof(struct dwattr)); 555 pool_init(&die_pool, "die", 512, sizeof(struct dwdie)); 556 pool_init(&dav_pool, "dav", 1024, sizeof(struct dwaval)); 557 dw_pool_inited = 1; 558 } 559 #endif /* NOPOOL */ 560 561 if (info->len == 0 || abbrev->len == 0) 562 return EINVAL; 563 564 /* Offset in the segment of the current Compile Unit. */ 565 segoff = seglen - info->len; 566 567 if (dw_read_u32(info, &length)) 568 return -1; 569 570 if (length >= 0xfffffff0 || length > info->len) 571 return EOVERFLOW; 572 573 /* Offset of the next Compile Unit. */ 574 nextoff = segoff + length + sizeof(uint32_t); 575 576 if (dw_read_buf(info, &dwbuf, length)) 577 return -1; 578 579 addrsize = 4; /* XXX */ 580 581 if (dw_read_u16(&dwbuf, &version) || 582 dw_read_bytes(&dwbuf, &abbroff, addrsize) || 583 dw_read_u8(&dwbuf, &psz)) 584 return -1; 585 586 if (dw_skip_bytes(&abseg, abbroff)) 587 return -1; 588 589 /* Only DWARF2 until extended. */ 590 if (version != 2) 591 return ENOTSUP; 592 593 dcu = pmalloc(&dcu_pool, sizeof(*dcu)); 594 if (dcu == NULL) 595 return ENOMEM; 596 597 dcu->dcu_offset = segoff; 598 dcu->dcu_length = length; 599 dcu->dcu_version = version; 600 dcu->dcu_abbroff = abbroff; 601 dcu->dcu_psize = psz; 602 SIMPLEQ_INIT(&dcu->dcu_abbrevs); 603 SIMPLEQ_INIT(&dcu->dcu_dies); 604 605 error = dw_ab_parse(&abseg, &dcu->dcu_abbrevs); 606 if (error != 0) { 607 dw_dcu_free(dcu); 608 return error; 609 } 610 611 error = dw_die_parse(&dwbuf, nextoff, psz, &dcu->dcu_abbrevs, 612 &dcu->dcu_dies); 613 if (error != 0) { 614 dw_dcu_free(dcu); 615 return error; 616 } 617 618 if (dcup != NULL) 619 *dcup = dcu; 620 else 621 dw_dcu_free(dcu); 622 623 return 0; 624 } 625 626 void 627 dw_dcu_free(struct dwcu *dcu) 628 { 629 if (dcu == NULL) 630 return; 631 632 dw_die_purge(&dcu->dcu_dies); 633 dw_dabq_purge(&dcu->dcu_abbrevs); 634 pfree(&dcu_pool, dcu); 635 } 636 637 int 638 dw_loc_parse(struct dwbuf *dwbuf, uint8_t *pop, uint64_t *poper1, 639 uint64_t *poper2) 640 { 641 uint64_t oper1 = 0, oper2 = 0; 642 uint8_t op; 643 644 if (dw_read_u8(dwbuf, &op)) 645 return -1; 646 647 if (pop != NULL) 648 *pop = op; 649 650 switch (op) { 651 case DW_OP_constu: 652 case DW_OP_plus_uconst: 653 case DW_OP_regx: 654 case DW_OP_piece: 655 dw_read_uleb128(dwbuf, &oper1); 656 break; 657 658 case DW_OP_consts: 659 case DW_OP_breg0 ... DW_OP_breg31: 660 case DW_OP_fbreg: 661 dw_read_sleb128(dwbuf, &oper1); 662 break; 663 default: 664 return ENOTSUP; 665 } 666 667 if (poper1 != NULL) 668 *poper1 = oper1; 669 if (poper2 != NULL) 670 *poper2 = oper2; 671 672 return 0; 673 } 674