|
31 | 31 |
|
32 | 32 | #include "dwarf_find.h" |
33 | 33 |
|
| 34 | +#include <cassert> |
| 35 | +#include <cstdlib> |
| 36 | +#include <cstring> |
34 | 37 | #include <stdlib.h> |
| 38 | +#include <vector> |
35 | 39 |
|
| 40 | +#include "dwarf.h" |
| 41 | +#include "libdwarf.h" |
36 | 42 | #include "outdbg.h" |
37 | 43 |
|
| 44 | +static int |
| 45 | +create_aranges(Dwarf_Debug dbg, std::vector<My_Arange *> &myrec, Dwarf_Error *error); |
38 | 46 |
|
39 | 47 | static char unknown[] = {'?', '?', '\0'}; |
40 | 48 |
|
@@ -167,7 +175,15 @@ dwarf_find_symbol(dwarf_module *dwarf, Dwarf_Addr addr, struct dwarf_symbol_info |
167 | 175 |
|
168 | 176 | Dwarf_Arange arange; |
169 | 177 | if (dwarf_get_arange(dwarf->aranges, dwarf->arange_count, addr, &arange, &error) != DW_DLV_OK) { |
170 | | - goto no_arange; |
| 178 | + if (dwarf->my_aranges.empty()) { |
| 179 | + if (create_aranges(dbg, dwarf->my_aranges, &error) == DW_DLV_ERROR) { |
| 180 | + goto no_arange; |
| 181 | + } |
| 182 | + } |
| 183 | + if (dwarf_get_arange((Dwarf_Arange *)dwarf->my_aranges.data(), dwarf->my_aranges.size(), |
| 184 | + addr, &arange, &error) != DW_DLV_OK) { |
| 185 | + goto no_arange; |
| 186 | + } |
171 | 187 | } |
172 | 188 |
|
173 | 189 | Dwarf_Off cu_die_offset; |
@@ -204,7 +220,15 @@ dwarf_find_line(dwarf_module *dwarf, Dwarf_Addr addr, struct dwarf_line_info *in |
204 | 220 |
|
205 | 221 | Dwarf_Arange arange; |
206 | 222 | if (dwarf_get_arange(dwarf->aranges, dwarf->arange_count, addr, &arange, &error) != DW_DLV_OK) { |
207 | | - goto no_arange; |
| 223 | + if (dwarf->my_aranges.empty()) { |
| 224 | + if (create_aranges(dbg, dwarf->my_aranges, &error) == DW_DLV_ERROR) { |
| 225 | + goto no_arange; |
| 226 | + } |
| 227 | + } |
| 228 | + if (dwarf_get_arange((Dwarf_Arange *)dwarf->my_aranges.data(), dwarf->my_aranges.size(), |
| 229 | + addr, &arange, &error) != DW_DLV_OK) { |
| 230 | + goto no_arange; |
| 231 | + } |
208 | 232 | } |
209 | 233 |
|
210 | 234 | Dwarf_Off cu_die_offset; |
@@ -333,3 +357,284 @@ no_die_offset:; |
333 | 357 | } |
334 | 358 | return result; |
335 | 359 | } |
| 360 | + |
| 361 | +static int |
| 362 | +getlowhighpc(Dwarf_Die die, Dwarf_Addr *lowpc_out, Dwarf_Addr *highpc_out, Dwarf_Error *error) |
| 363 | +{ |
| 364 | + Dwarf_Addr hipc = 0; |
| 365 | + int res = 0; |
| 366 | + Dwarf_Half form = 0; |
| 367 | + enum Dwarf_Form_Class formclass = DW_FORM_CLASS_UNKNOWN; |
| 368 | + |
| 369 | + res = dwarf_lowpc(die, lowpc_out, error); |
| 370 | + if (res == DW_DLV_OK) { |
| 371 | + res = dwarf_highpc_b(die, &hipc, &form, &formclass, error); |
| 372 | + if (res == DW_DLV_OK) { |
| 373 | + if (formclass == DW_FORM_CLASS_CONSTANT) { |
| 374 | + hipc += *lowpc_out; |
| 375 | + } |
| 376 | + *highpc_out = hipc; |
| 377 | + return DW_DLV_OK; |
| 378 | + } |
| 379 | + } |
| 380 | + /* Cannot check ranges yet, we don't know the ranges base |
| 381 | + offset yet. */ |
| 382 | + return DW_DLV_NO_ENTRY; |
| 383 | +} |
| 384 | + |
| 385 | +/* Based on 'examplev' in 'checkexamples.c'. |
| 386 | + There is another example in 'check_comp_dir()' in 'findfuncbypc.c', |
| 387 | + but it seems wrong because the base address is not read from 'DW_AT_low_pc' of the CU die. |
| 388 | + */ |
| 389 | +static int |
| 390 | +record_range(Dwarf_Debug dbg, |
| 391 | + Dwarf_Die die, |
| 392 | + std::vector<My_Arange *> &myrec, |
| 393 | + Dwarf_Off info_offset, |
| 394 | + Dwarf_Error *error) |
| 395 | +{ |
| 396 | + Dwarf_Signed count = 0; |
| 397 | + Dwarf_Off realoffset = 0; |
| 398 | + Dwarf_Ranges *rangesbuf = 0; |
| 399 | + Dwarf_Unsigned bytecount = 0; |
| 400 | + int res = 0; |
| 401 | + Dwarf_Unsigned base_address = 0; |
| 402 | + Dwarf_Bool have_base_addr = FALSE; |
| 403 | + Dwarf_Bool have_rangesoffset = FALSE; |
| 404 | + Dwarf_Unsigned rangesoffset = (Dwarf_Unsigned)info_offset; |
| 405 | + |
| 406 | + /* Find the ranges for a specific DIE */ |
| 407 | + res = dwarf_get_ranges_baseaddress(dbg, die, &have_base_addr, &base_address, &have_rangesoffset, |
| 408 | + &rangesoffset, error); |
| 409 | + if (res == DW_DLV_ERROR) { |
| 410 | + /* Just pretend not an error. */ |
| 411 | + dwarf_dealloc_error(dbg, *error); |
| 412 | + *error = 0; |
| 413 | + } |
| 414 | + |
| 415 | + res = dwarf_get_ranges_b(dbg, rangesoffset, die, &realoffset, &rangesbuf, &count, &bytecount, |
| 416 | + error); |
| 417 | + if (res != DW_DLV_OK) { |
| 418 | + return res; |
| 419 | + } |
| 420 | + Dwarf_Signed i = 0; |
| 421 | + for (i = 0; i < count; ++i) { |
| 422 | + Dwarf_Ranges *cur = rangesbuf + i; |
| 423 | + Dwarf_Addr base = base_address; |
| 424 | + Dwarf_Addr lowpc; |
| 425 | + Dwarf_Addr highpc; |
| 426 | + |
| 427 | + switch (cur->dwr_type) { |
| 428 | + case DW_RANGES_ENTRY: |
| 429 | + lowpc = cur->dwr_addr1 + base; |
| 430 | + highpc = cur->dwr_addr2 + base; |
| 431 | + myrec.push_back(new My_Arange{0, lowpc, highpc - lowpc, info_offset, dbg, 0}); |
| 432 | + break; |
| 433 | + case DW_RANGES_ADDRESS_SELECTION: |
| 434 | + base = cur->dwr_addr2; |
| 435 | + break; |
| 436 | + case DW_RANGES_END: |
| 437 | + break; |
| 438 | + default: |
| 439 | + fprintf(stderr, |
| 440 | + "Impossible debug_ranges content!" |
| 441 | + " enum val %d \n", |
| 442 | + (int)cur->dwr_type); |
| 443 | + return DW_DLV_ERROR; |
| 444 | + } |
| 445 | + } |
| 446 | + dwarf_dealloc_ranges(dbg, rangesbuf, count); |
| 447 | + |
| 448 | + return DW_DLV_OK; |
| 449 | +} |
| 450 | + |
| 451 | +/* Based on 'example_rnglist_for_attribute()' in 'checkexamples.c'. */ |
| 452 | +static int |
| 453 | +record_rnglist_for_attribute(Dwarf_Debug dbg, |
| 454 | + Dwarf_Attribute attr, |
| 455 | + Dwarf_Unsigned attrvalue, |
| 456 | + Dwarf_Half form, |
| 457 | + std::vector<My_Arange *> &myrec, |
| 458 | + Dwarf_Off info_offset, |
| 459 | + Dwarf_Error *error) |
| 460 | +{ |
| 461 | + /* attrvalue must be the DW_AT_ranges |
| 462 | + DW_FORM_rnglistx or DW_FORM_sec_offset value |
| 463 | + extracted from attr. */ |
| 464 | + int res = 0; |
| 465 | + Dwarf_Unsigned entries_count; |
| 466 | + Dwarf_Unsigned global_offset_of_rle_set; |
| 467 | + Dwarf_Rnglists_Head rnglhead = 0; |
| 468 | + Dwarf_Unsigned i = 0; |
| 469 | + |
| 470 | + res = dwarf_rnglists_get_rle_head(attr, form, attrvalue, &rnglhead, &entries_count, |
| 471 | + &global_offset_of_rle_set, error); |
| 472 | + if (res != DW_DLV_OK) { |
| 473 | + return res; |
| 474 | + } |
| 475 | + for (i = 0; i < entries_count; ++i) { |
| 476 | + unsigned entrylen = 0; |
| 477 | + unsigned code = 0; |
| 478 | + Dwarf_Unsigned rawlowpc = 0; |
| 479 | + Dwarf_Unsigned rawhighpc = 0; |
| 480 | + Dwarf_Bool debug_addr_unavailable = FALSE; |
| 481 | + Dwarf_Unsigned lowpc = 0; |
| 482 | + Dwarf_Unsigned highpc = 0; |
| 483 | + |
| 484 | + /* Actual addresses are most likely what one |
| 485 | + wants to know, not the lengths/offsets |
| 486 | + recorded in .debug_rnglists. */ |
| 487 | + res = |
| 488 | + dwarf_get_rnglists_entry_fields_a(rnglhead, i, &entrylen, &code, &rawlowpc, &rawhighpc, |
| 489 | + &debug_addr_unavailable, &lowpc, &highpc, error); |
| 490 | + if (res != DW_DLV_OK) { |
| 491 | + dwarf_dealloc_rnglists_head(rnglhead); |
| 492 | + return res; |
| 493 | + } |
| 494 | + if (code == DW_RLE_end_of_list) { |
| 495 | + /* we are done */ |
| 496 | + break; |
| 497 | + } |
| 498 | + if (code == DW_RLE_base_addressx || code == DW_RLE_base_address) { |
| 499 | + /* We do not need to use these, they |
| 500 | + have been accounted for already. */ |
| 501 | + continue; |
| 502 | + } |
| 503 | + if (debug_addr_unavailable) { |
| 504 | + /* lowpc and highpc are not real addresses */ |
| 505 | + continue; |
| 506 | + } |
| 507 | + /* Here do something with lowpc and highpc, these |
| 508 | + are real addresses */ |
| 509 | + myrec.push_back(new My_Arange{0, lowpc, highpc - lowpc, info_offset, dbg, 0}); |
| 510 | + } |
| 511 | + dwarf_dealloc_rnglists_head(rnglhead); |
| 512 | + return DW_DLV_OK; |
| 513 | +} |
| 514 | + |
| 515 | +/* Based on 'print_die_data_i() in 'simplereader.c'. */ |
| 516 | +static int |
| 517 | +record_rnglist(Dwarf_Debug dbg, |
| 518 | + Dwarf_Die cur_die, |
| 519 | + std::vector<My_Arange *> &myrec, |
| 520 | + Dwarf_Off info_offset, |
| 521 | + Dwarf_Error *error) |
| 522 | +{ |
| 523 | + Dwarf_Attribute attr = nullptr; |
| 524 | + int res = DW_DLV_OK; |
| 525 | + Dwarf_Unsigned attrvalue = 0; |
| 526 | + Dwarf_Half form = 0; |
| 527 | + |
| 528 | + res = dwarf_attr(cur_die, DW_AT_ranges, &attr, error); |
| 529 | + if (res != DW_DLV_OK) |
| 530 | + return res; |
| 531 | + |
| 532 | + res = dwarf_whatform(attr, &form, error); |
| 533 | + if (res == DW_DLV_OK) { |
| 534 | + if (form == DW_FORM_rnglistx) { |
| 535 | + res = dwarf_formudata(attr, &attrvalue, error); |
| 536 | + } else { |
| 537 | + assert(form == DW_FORM_sec_offset); |
| 538 | + res = dwarf_global_formref(attr, &attrvalue, error); |
| 539 | + } |
| 540 | + if (res == DW_DLV_OK) { |
| 541 | + res = |
| 542 | + record_rnglist_for_attribute(dbg, attr, attrvalue, form, myrec, info_offset, error); |
| 543 | + } |
| 544 | + } |
| 545 | + dwarf_dealloc(dbg, attr, DW_DLA_ATTR); |
| 546 | + |
| 547 | + return res; |
| 548 | +} |
| 549 | + |
| 550 | +static int |
| 551 | +record_die(Dwarf_Debug dbg, |
| 552 | + Dwarf_Die cur_die, |
| 553 | + int is_info, |
| 554 | + int in_level, |
| 555 | + std::vector<My_Arange *> &myrec, |
| 556 | + Dwarf_Error *error) |
| 557 | +{ |
| 558 | + Dwarf_Off info_offset, cu_offset; |
| 559 | + Dwarf_Addr lowpc = 0; |
| 560 | + Dwarf_Addr highpc = 0; |
| 561 | + int res; |
| 562 | + |
| 563 | + res = dwarf_dieoffset(cur_die, &info_offset, error); |
| 564 | + if (res != DW_DLV_OK) |
| 565 | + return res; |
| 566 | + dwarf_die_CU_offset(cur_die, &cu_offset, error); |
| 567 | + if (res != DW_DLV_OK) |
| 568 | + return res; |
| 569 | + info_offset -= cu_offset; |
| 570 | + |
| 571 | + res = getlowhighpc(cur_die, &lowpc, &highpc, error); |
| 572 | + if (res == DW_DLV_OK) { |
| 573 | + myrec.push_back(new My_Arange{0, lowpc, highpc - lowpc, info_offset, dbg, 0}); |
| 574 | + } else { |
| 575 | + Dwarf_Attribute attr = 0; |
| 576 | + Dwarf_Half version = 0; |
| 577 | + Dwarf_Half offset_size = 0; |
| 578 | + res = dwarf_attr(cur_die, DW_AT_ranges, &attr, error); |
| 579 | + if (res != DW_DLV_OK) |
| 580 | + return res; |
| 581 | + res = dwarf_get_version_of_die(cur_die, &version, &offset_size); |
| 582 | + if (res != DW_DLV_OK) |
| 583 | + return res; |
| 584 | + |
| 585 | + if (version <= 4) { |
| 586 | + res = record_range(dbg, cur_die, myrec, info_offset, error); |
| 587 | + } else { |
| 588 | + res = record_rnglist(dbg, cur_die, myrec, info_offset, error); |
| 589 | + } |
| 590 | + if (res != DW_DLV_OK) |
| 591 | + return res; |
| 592 | + } |
| 593 | + return DW_DLV_OK; |
| 594 | +} |
| 595 | + |
| 596 | +int |
| 597 | +create_aranges(Dwarf_Debug dbg, std::vector<My_Arange *> &myrec, Dwarf_Error *error) |
| 598 | +{ |
| 599 | + Dwarf_Unsigned abbrev_offset = 0; |
| 600 | + Dwarf_Half address_size = 0; |
| 601 | + Dwarf_Half version_stamp = 0; |
| 602 | + Dwarf_Half offset_size = 0; |
| 603 | + Dwarf_Half extension_size = 0; |
| 604 | + Dwarf_Sig8 signature; |
| 605 | + Dwarf_Unsigned typeoffset = 0; |
| 606 | + Dwarf_Unsigned next_cu_header = 0; |
| 607 | + Dwarf_Half header_cu_type = 0; |
| 608 | + Dwarf_Bool is_info = TRUE; |
| 609 | + int res = DW_DLV_OK; |
| 610 | + |
| 611 | + while (true) { |
| 612 | + Dwarf_Die cu_die = NULL; |
| 613 | + Dwarf_Unsigned cu_header_length = 0; |
| 614 | + |
| 615 | + memset(&signature, 0, sizeof(signature)); |
| 616 | + res = dwarf_next_cu_header_e(dbg, is_info, &cu_die, &cu_header_length, &version_stamp, |
| 617 | + &abbrev_offset, &address_size, &offset_size, &extension_size, |
| 618 | + &signature, &typeoffset, &next_cu_header, &header_cu_type, |
| 619 | + error); |
| 620 | + if (res == DW_DLV_ERROR) { |
| 621 | + return res; |
| 622 | + } |
| 623 | + if (res == DW_DLV_NO_ENTRY) { |
| 624 | + if (is_info == TRUE) { |
| 625 | + /* Done with .debug_info, now check for |
| 626 | + .debug_types. */ |
| 627 | + is_info = FALSE; |
| 628 | + continue; |
| 629 | + } |
| 630 | + /* No more CUs to read! Never found |
| 631 | + what we were looking for in either |
| 632 | + .debug_info or .debug_types. */ |
| 633 | + return res; |
| 634 | + } |
| 635 | + /* We have the cu_die . */ |
| 636 | + res = record_die(dbg, cu_die, is_info, 0, myrec, error); |
| 637 | + dwarf_dealloc_die(cu_die); |
| 638 | + } |
| 639 | + return res; |
| 640 | +} |
0 commit comments