1 /* 2 3 Copyright (C) 2000-2004 Silicon Graphics, Inc. All Rights Reserved. 4 5 This program is free software; you can redistribute it and/or modify it 6 under the terms of version 2.1 of the GNU Lesser General Public License 7 as published by the Free Software Foundation. 8 9 This program is distributed in the hope that it would be useful, but 10 WITHOUT ANY WARRANTY; without even the implied warranty of 11 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. 12 13 Further, this software is distributed without any warranty that it is 14 free of the rightful claim of any third person regarding infringement 15 or the like. Any license provided herein, whether implied or 16 otherwise, applies only to this software file. Patent licenses, if 17 any, provided herein do not apply to combinations of this program with 18 other software, or any other product whatsoever. 19 20 You should have received a copy of the GNU Lesser General Public 21 License along with this program; if not, write the Free Software 22 Foundation, Inc., 51 Franklin Street - Fifth Floor, Boston MA 02110-1301, 23 USA. 24 25 Contact information: Silicon Graphics, Inc., 1500 Crittenden Lane, 26 Mountain View, CA 94043, or: 27 28 http://www.sgi.com 29 30 For further information regarding this notice, see: 31 32 http://oss.sgi.com/projects/GenInfo/NoticeExplan 33 34 */ 35 /* This code used by SGI-IRIX rqs processing, not needed by 36 any other system or application. 37 */ 38 39 #include "config.h" 40 #include "libdwarfdefs.h" 41 #ifdef HAVE_ELF_H 42 #include <elf.h> 43 #endif 44 #include <dwarf.h> 45 #include <libdwarf.h> 46 #include "dwarf_base_types.h" 47 #include "dwarf_alloc.h" 48 #include "dwarf_opaque.h" 49 #include "dwarf_arange.h" 50 #include "dwarf_line.h" 51 #include "dwarf_frame.h" 52 #include <cmplrs/dwarf_addr_finder.h> 53 #include "dwarf_error.h" 54 55 typedef unsigned long long ull; 56 57 static int do_this_die_and_dealloc(Dwarf_Debug dbg, Dwarf_Die die, 58 int *errval); 59 static int 60 handle_debug_info(Dwarf_Debug dbg, int *errval); 61 static int 62 handle_debug_frame(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, int *errval); 63 static int 64 handle_debug_aranges(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, int *errval); 65 static int 66 handle_debug_line(Dwarf_Debug dbg, Dwarf_Die cu_die, Dwarf_addr_callback_func cb_func, int *errval); 67 static int 68 handle_debug_loc(void); 69 70 71 static Dwarf_addr_callback_func send_addr_note; 72 73 int 74 _dwarf_addr_finder(dwarf_elf_handle elf_file_ptr, 75 Dwarf_addr_callback_func cb_func, int *dwerr) 76 { 77 78 Dwarf_Error err = 0; 79 Dwarf_Debug dbg = 0; 80 int res = 0; 81 int errval = 0; 82 int sections_found = 0; 83 84 res = dwarf_elf_init(elf_file_ptr, DW_DLC_READ, /* errhand */ 0, 85 /* errarg */ 0, &dbg, &err); 86 if (res == DW_DLV_ERROR) { 87 int errv = (int) dwarf_errno(err); 88 89 return errv; 90 } 91 if (res == DW_DLV_NO_ENTRY) { 92 return res; 93 } 94 95 send_addr_note = cb_func; 96 97 res = handle_debug_info(dbg, &errval); 98 switch (res) { 99 case DW_DLV_OK: 100 ++sections_found; 101 break; 102 case DW_DLV_NO_ENTRY: 103 104 break; 105 default: 106 case DW_DLV_ERROR: 107 dwarf_finish(dbg, &err); 108 *dwerr = errval; 109 return res; 110 } 111 112 res = handle_debug_aranges(dbg, cb_func, &errval); 113 switch (res) { 114 case DW_DLV_OK: 115 ++sections_found; 116 break; 117 case DW_DLV_NO_ENTRY: 118 break; 119 default: 120 case DW_DLV_ERROR: 121 dwarf_finish(dbg, &err); 122 *dwerr = errval; 123 return res; 124 } 125 res = handle_debug_frame(dbg, cb_func, &errval); 126 switch (res) { 127 case DW_DLV_OK: 128 ++sections_found; 129 break; 130 case DW_DLV_NO_ENTRY: 131 break; 132 default: 133 case DW_DLV_ERROR: 134 dwarf_finish(dbg, &err); 135 *dwerr = errval; 136 return res; 137 } 138 139 res = handle_debug_loc(); /* does nothing */ 140 switch (res) { 141 case DW_DLV_OK: 142 ++sections_found; 143 break; 144 case DW_DLV_NO_ENTRY: 145 break; 146 default: 147 case DW_DLV_ERROR: 148 /* IMPOSSIBLE : handle_debug_loc cannot return this */ 149 dwarf_finish(dbg, &err); 150 *dwerr = errval; 151 return res; 152 } 153 154 155 156 *dwerr = 0; 157 res = dwarf_finish(dbg, &err); 158 if (res == DW_DLV_ERROR) { 159 *dwerr = (int) dwarf_errno(err); 160 return DW_DLV_ERROR; 161 } 162 if (sections_found == 0) { 163 return DW_DLV_NO_ENTRY; 164 } 165 return DW_DLV_OK; 166 167 } 168 169 /* 170 Return DW_DLV_OK, ERROR, or NO_ENTRY. 171 */ 172 static int 173 handle_debug_info(Dwarf_Debug dbg, int *errval) 174 { 175 Dwarf_Unsigned nxtoff = 1; 176 Dwarf_Unsigned hdr_length; 177 Dwarf_Half version_stamp; 178 Dwarf_Unsigned abbrev_offset; 179 Dwarf_Half addr_size; 180 Dwarf_Error err; 181 int terminate_now = 0; 182 int res = 0; 183 Dwarf_Die sibdie; 184 int sibres; 185 int nres = DW_DLV_OK; 186 187 188 for (nres = dwarf_next_cu_header(dbg, &hdr_length, &version_stamp, 189 &abbrev_offset, 190 &addr_size, &nxtoff, &err); 191 terminate_now == 0 && nres == DW_DLV_OK; 192 nres = dwarf_next_cu_header(dbg, &hdr_length, &version_stamp, 193 &abbrev_offset, 194 &addr_size, &nxtoff, &err) 195 ) { 196 197 Dwarf_Die curdie = 0; 198 199 /* try to get the compilation unit die */ 200 sibres = dwarf_siblingof(dbg, curdie, &sibdie, &err); 201 if (sibres == DW_DLV_OK) { 202 res = do_this_die_and_dealloc(dbg, sibdie, errval); 203 switch (res) { 204 case DW_DLV_OK: 205 break; 206 case DW_DLV_NO_ENTRY: 207 break; 208 default: 209 case DW_DLV_ERROR: 210 return DW_DLV_ERROR; 211 } 212 } else if (sibres == DW_DLV_ERROR) { 213 *errval = (int) dwarf_errno(err); 214 return DW_DLV_ERROR; 215 } else { 216 /* NO ENTRY! */ 217 /* impossible? */ 218 } 219 220 } 221 if (nres == DW_DLV_ERROR) { 222 int localerr = (int) dwarf_errno(err); 223 224 *errval = localerr; 225 return DW_DLV_ERROR; 226 } 227 return DW_DLV_OK; 228 } 229 230 static int 231 might_have_addr[] = { 232 DW_AT_high_pc, 233 DW_AT_low_pc, 234 }; 235 static int 236 might_have_locdesc[] = { 237 DW_AT_segment, 238 DW_AT_return_addr, 239 DW_AT_frame_base, 240 DW_AT_static_link, 241 DW_AT_data_member_location, 242 DW_AT_string_length, 243 DW_AT_location, 244 DW_AT_use_location, 245 DW_AT_vtable_elem_location, 246 }; 247 248 /* 249 Return DW_DLV_OK if handling this went ok. 250 */ 251 static int 252 handle_attr_addr(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Half attrnum, 253 Dwarf_Error * perr) 254 { 255 int res = DW_DLV_OK; 256 Dwarf_Off offset; 257 Dwarf_Addr addr; 258 Dwarf_Half form; 259 int ares; 260 261 Dwarf_Attribute attr; 262 263 ares = dwarf_attr(die, attrnum, &attr, perr); 264 if (ares == DW_DLV_OK) { 265 int formres = dwarf_whatform(attr, &form, perr); 266 267 switch (formres) { 268 case DW_DLV_OK: 269 break; 270 case DW_DLV_ERROR: 271 case DW_DLV_NO_ENTRY: /* impossible. */ 272 return formres; 273 274 } 275 276 switch (form) { 277 case DW_FORM_ref_addr: 278 case DW_FORM_addr: 279 res = dwarf_attr_offset(die, attr, &offset, perr); 280 if (res == DW_DLV_OK) { 281 ares = dwarf_formaddr(attr, &addr, perr); 282 if (ares == DW_DLV_OK) { 283 send_addr_note(DW_SECTION_INFO, offset, addr); 284 } else if (ares == DW_DLV_ERROR) { 285 return ares; 286 } /* no entry: ok. */ 287 } else { 288 res = DW_DLV_ERROR; /* NO_ENTRY is impossible. */ 289 } 290 break; 291 292 default: 293 /* surprising! An error? */ 294 295 ; /* do nothing */ 296 } 297 dwarf_dealloc(dbg, attr, DW_DLA_ATTR); 298 299 } else { 300 res = ares; 301 } 302 return res; 303 } 304 305 /* 306 Return DW_DLV_OK if handling this went ok. 307 */ 308 static int 309 handle_attr_locdesc(Dwarf_Debug dbg, Dwarf_Die die, Dwarf_Half attrnum, 310 Dwarf_Error * perr) 311 { 312 int retval = DW_DLV_OK; 313 Dwarf_Attribute attr; 314 Dwarf_Locdesc *llbuf; 315 Dwarf_Signed i; 316 Dwarf_Off offset; 317 Dwarf_Loc *locp; 318 unsigned int entindx; 319 int res; 320 int ares; 321 322 323 ares = dwarf_attr(die, attrnum, &attr, perr); 324 if (ares == DW_DLV_OK) { 325 Dwarf_Half form; 326 int fres = dwarf_whatform(attr, &form, perr); 327 328 if (fres == DW_DLV_OK) { 329 switch (form) { 330 case DW_FORM_block1: 331 case DW_FORM_block2: 332 case DW_FORM_block4: 333 /* must be location description */ 334 res = dwarf_attr_offset(die, attr, &offset, perr); 335 llbuf = 0; 336 if (res == DW_DLV_OK) { 337 Dwarf_Signed count; 338 int lres = dwarf_loclist(attr, &llbuf, &count, perr); 339 if (lres != DW_DLV_OK) { 340 return lres; 341 } 342 if (count != 1) { 343 /* this cannot happen! */ 344 /* perr? */ 345 _dwarf_error(dbg, perr, 346 DW_DLE_LOCDESC_COUNT_WRONG); 347 retval = DW_DLV_ERROR; 348 return retval; 349 } 350 for (i = 0; i < count; ++i) { 351 unsigned int ents = llbuf[i].ld_cents; 352 353 locp = llbuf[i].ld_s; 354 for (entindx = 0; entindx < ents; entindx++) { 355 Dwarf_Loc *llocp; 356 357 llocp = locp + entindx; 358 if (llocp->lr_atom == DW_OP_addr) { 359 send_addr_note(DW_SECTION_INFO, offset + 360 llocp->lr_offset + 1 361 /* The offset is the 362 offset of the atom, 363 ** and we know the 364 addr is 1 past it. */ 365 , llocp->lr_number); 366 } 367 } 368 } 369 370 371 if (count > 0) { 372 for (i = 0; i < count; ++i) { 373 dwarf_dealloc(dbg, llbuf[i].ld_s, 374 DW_DLA_LOC_BLOCK); 375 } 376 dwarf_dealloc(dbg, llbuf, DW_DLA_LOCDESC); 377 } 378 } else { 379 retval = res; 380 } 381 break; 382 383 default: 384 /* must be a const offset in debug_loc */ 385 ; /* do nothing */ 386 } 387 dwarf_dealloc(dbg, attr, DW_DLA_ATTR); 388 } /* else error or no entry */ 389 retval = fres; 390 } else { 391 retval = ares; 392 } 393 return retval; 394 } 395 396 /* 397 Return DW_DLV_OK, or DW_DLV_ERROR 398 399 Handle the addrs in a single die. 400 */ 401 static int 402 process_this_die_attrs(Dwarf_Debug dbg, Dwarf_Die newdie, int *errval) 403 { 404 Dwarf_Error err; 405 Dwarf_Half i; 406 Dwarf_Half newattrnum; 407 int res; 408 int tres; 409 Dwarf_Half ltag; 410 411 Dwarf_Off doff; 412 int doffres = dwarf_dieoffset(newdie, &doff, &err); 413 414 if (doffres != DW_DLV_OK) { 415 if (doffres == DW_DLV_ERROR) { 416 *errval = (int) dwarf_errno(err); 417 } 418 return doffres; 419 } 420 tres = dwarf_tag(newdie, <ag, &err); 421 if (tres != DW_DLV_OK) { 422 return tres; 423 } 424 if (DW_TAG_compile_unit == ltag) { 425 /* because of the way the dwarf_line code works, we do lines 426 only per compile unit. This may turn out to be wrong if 427 we have lines left unconnected to a CU. of course such 428 lines will not, at present, be used by gnome. This is 429 not ideal as coded due to the dwarf_line.c issue. */ 430 int lres = handle_debug_line(dbg, newdie, send_addr_note, errval); 431 if (lres == DW_DLV_ERROR) { 432 return lres; 433 } 434 } 435 436 for (i = 0; i < sizeof(might_have_addr) / sizeof(int); i++) { 437 int resattr; 438 Dwarf_Bool hasattr; 439 440 newattrnum = might_have_addr[i]; 441 err = 0; 442 resattr = dwarf_hasattr(newdie, newattrnum, &hasattr, &err); 443 if (DW_DLV_OK == resattr) { 444 if (hasattr) { 445 res = handle_attr_addr(dbg, newdie, newattrnum, &err); 446 if (res != DW_DLV_OK) { 447 *errval = (int) dwarf_errno(err); 448 return DW_DLV_ERROR; 449 } 450 } 451 } else { 452 if (resattr == DW_DLV_ERROR) { 453 *errval = (int) dwarf_errno(err); 454 return resattr; 455 } 456 } 457 } 458 for (i = 0; i < sizeof(might_have_locdesc) / sizeof(int); i++) { 459 int resattr; 460 Dwarf_Bool hasattr; 461 462 newattrnum = might_have_locdesc[i]; 463 err = 0; 464 resattr = dwarf_hasattr(newdie, newattrnum, &hasattr, &err); 465 if (DW_DLV_OK == resattr) { 466 if (hasattr) { 467 res = 468 handle_attr_locdesc(dbg, newdie, newattrnum, &err); 469 if (res != DW_DLV_OK) { 470 *errval = (int) dwarf_errno(err); 471 return DW_DLV_ERROR; 472 } 473 } 474 } else { 475 if (resattr == DW_DLV_ERROR) { 476 *errval = (int) dwarf_errno(err); 477 return resattr; 478 } 479 } 480 } 481 482 return DW_DLV_OK; 483 } 484 485 /* 486 Handle siblings as a list, 487 Do children by recursing. 488 Effectively this is walking the tree preorder. 489 490 This dealloc's any die passed to it, so the 491 caller should not do that dealloc. 492 It seems more logical to have the one causing 493 the alloc to do the dealloc, but that way this 494 routine became a mess. 495 496 */ 497 static int 498 do_this_die_and_dealloc(Dwarf_Debug dbg, Dwarf_Die die, int *errval) 499 { 500 501 Dwarf_Die prevdie = 0; 502 Dwarf_Die newdie = die; 503 Dwarf_Error err = 0; 504 int res = 0; 505 int sibres = DW_DLV_OK; 506 int tres = DW_DLV_OK; 507 Dwarf_Die sibdie; 508 509 while (sibres == DW_DLV_OK) { 510 Dwarf_Die ch_die; 511 512 513 res = process_this_die_attrs(dbg, newdie, errval); 514 switch (res) { 515 case DW_DLV_OK: 516 break; 517 case DW_DLV_NO_ENTRY: 518 break; 519 default: 520 case DW_DLV_ERROR: 521 if (prevdie) { 522 dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); 523 prevdie = 0; 524 } 525 return DW_DLV_ERROR; 526 } 527 528 tres = dwarf_child(newdie, &ch_die, &err); 529 530 if (tres == DW_DLV_OK) { 531 res = do_this_die_and_dealloc(dbg, ch_die, errval); 532 switch (res) { 533 case DW_DLV_OK: 534 break; 535 case DW_DLV_NO_ENTRY: 536 break; 537 default: 538 case DW_DLV_ERROR: 539 if (prevdie) { 540 dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); 541 prevdie = 0; 542 } 543 return DW_DLV_ERROR; 544 } 545 } else if (tres == DW_DLV_ERROR) { 546 /* An error! */ 547 *errval = (int) dwarf_errno(err); 548 if (prevdie) { 549 dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); 550 prevdie = 0; 551 } 552 dwarf_dealloc(dbg, err, DW_DLA_ERROR); 553 return DW_DLV_ERROR; 554 } /* else was NO ENTRY */ 555 prevdie = newdie; 556 sibdie = 0; 557 sibres = dwarf_siblingof(dbg, newdie, &sibdie, &err); 558 if (prevdie) { 559 dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); 560 prevdie = 0; 561 } 562 newdie = sibdie; 563 564 } 565 if (sibres == DW_DLV_NO_ENTRY) { 566 return DW_DLV_OK; 567 } 568 /* error. */ 569 *errval = (int) dwarf_errno(err); 570 if (prevdie) { 571 dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); 572 prevdie = 0; 573 } 574 dwarf_dealloc(dbg, err, DW_DLA_ERROR); 575 return DW_DLV_ERROR; 576 577 } 578 579 580 static int 581 handle_debug_frame(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, 582 int *errval) 583 { 584 int retval = DW_DLV_OK; 585 int res; 586 Dwarf_Error err; 587 Dwarf_Addr *addrlist; 588 Dwarf_Off *offsetlist; 589 Dwarf_Signed count; 590 int i; 591 592 res = 593 _dwarf_frame_address_offsets(dbg, &addrlist, &offsetlist, 594 &count, &err); 595 if (res == DW_DLV_OK) { 596 for (i = 0; i < count; i++) { 597 cb_func(DW_SECTION_FRAME, offsetlist[i], addrlist[i]); 598 } 599 dwarf_dealloc(dbg, offsetlist, DW_DLA_ADDR); 600 dwarf_dealloc(dbg, addrlist, DW_DLA_ADDR); 601 } else if (res == DW_DLV_NO_ENTRY) { 602 retval = res; 603 } else { 604 *errval = (int) dwarf_errno(err); 605 retval = DW_DLV_ERROR; 606 } 607 return retval; 608 609 } 610 static int 611 handle_debug_aranges(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, 612 int *errval) 613 { 614 int retval = DW_DLV_OK; 615 Dwarf_Error err; 616 Dwarf_Addr *aranges; 617 Dwarf_Signed count; 618 int indx; 619 Dwarf_Off *offsets; 620 621 retval = 622 _dwarf_get_aranges_addr_offsets(dbg, &aranges, &offsets, &count, 623 &err); 624 if (retval == DW_DLV_OK) { 625 if (count == 0) { 626 retval = DW_DLV_NO_ENTRY; 627 } else { 628 for (indx = 0; indx < count; indx++) { 629 cb_func(DW_SECTION_ARANGES, offsets[indx], 630 aranges[indx]); 631 } 632 } 633 dwarf_dealloc(dbg, aranges, DW_DLA_ADDR); 634 dwarf_dealloc(dbg, offsets, DW_DLA_ADDR); 635 } else if (retval == DW_DLV_NO_ENTRY) { 636 ; /* do nothing */ 637 } else { 638 *errval = (int) dwarf_errno(err); 639 retval = DW_DLV_ERROR; 640 } 641 return retval; 642 } 643 static int 644 handle_debug_line(Dwarf_Debug dbg, Dwarf_Die cu_die, 645 Dwarf_addr_callback_func cb_func, int *errval) 646 { 647 int retval = DW_DLV_OK; 648 int res; 649 Dwarf_Error err; 650 Dwarf_Addr *addrlist; 651 Dwarf_Off *offsetlist; 652 Dwarf_Unsigned count; 653 Dwarf_Unsigned i; 654 655 res = 656 _dwarf_line_address_offsets(dbg, cu_die, &addrlist, &offsetlist, 657 &count, &err); 658 if (res == DW_DLV_OK) { 659 for (i = 0; i < count; i++) { 660 cb_func(DW_SECTION_LINE, offsetlist[i], addrlist[i]); 661 662 } 663 dwarf_dealloc(dbg, offsetlist, DW_DLA_ADDR); 664 dwarf_dealloc(dbg, addrlist, DW_DLA_ADDR); 665 } else if (res == DW_DLV_NO_ENTRY) { 666 retval = res; 667 } else { 668 *errval = (int) dwarf_errno(err); 669 retval = DW_DLV_ERROR; 670 } 671 return retval; 672 } 673 674 /* 675 We need to add support for this. Currently we do not 676 generate this section. 677 FIX! 678 */ 679 static int 680 handle_debug_loc(void) 681 { 682 int retval = DW_DLV_NO_ENTRY; 683 684 return retval; 685 } 686