1/* 2 3 Copyright (C) 2000,2002,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., 59 Temple Place - Suite 330, Boston MA 02111-1307, 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 "dwarf_addr_finder.h" 53#include "dwarf_error.h" 54 55typedef unsigned long long ull; 56 57static int do_this_die_and_dealloc(Dwarf_Debug dbg, Dwarf_Die die, 58 int *errval); 59static int 60 handle_debug_info(Dwarf_Debug dbg, int *errval); 61static int 62 handle_debug_frame(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, int *errval); 63static int 64 handle_debug_aranges(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, int *errval); 65static int 66 handle_debug_line(Dwarf_Debug dbg, Dwarf_Die cu_die, Dwarf_addr_callback_func cb_func, int *errval); 67static int 68 handle_debug_loc(void); 69 70 71static Dwarf_addr_callback_func send_addr_note; 72 73int 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*/ 172static int 173handle_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 230static int 231 might_have_addr[] = { 232 DW_AT_high_pc, 233 DW_AT_low_pc, 234}; 235static 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*/ 251static int 252handle_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*/ 308static int 309handle_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 = 339 dwarf_loclist(attr, &llbuf, &count, perr); 340 if (lres != DW_DLV_OK) { 341 return lres; 342 } 343 if (count != 1) { 344 /* this cannot happen! */ 345 /* perr? */ 346 _dwarf_error(dbg, perr, 347 DW_DLE_LOCDESC_COUNT_WRONG); 348 retval = DW_DLV_ERROR; 349 return retval; 350 } 351 for (i = 0; i < count; ++i) { 352 unsigned int ents = llbuf[i].ld_cents; 353 354 locp = llbuf[i].ld_s; 355 for (entindx = 0; entindx < ents; entindx++) { 356 Dwarf_Loc *llocp; 357 358 llocp = locp + entindx; 359 if (llocp->lr_atom == DW_OP_addr) { 360 send_addr_note(DW_SECTION_INFO, offset + 361 llocp->lr_offset + 1 362 /* The offset is the 363 offset of the atom, 364 ** and we know the 365 addr is 1 past it. */ 366 , llocp->lr_number); 367 } 368 } 369 } 370 371 372 if (count > 0) { 373 for (i = 0; i < count; ++i) { 374 dwarf_dealloc(dbg, llbuf[i].ld_s, 375 DW_DLA_LOC_BLOCK); 376 } 377 dwarf_dealloc(dbg, llbuf, DW_DLA_LOCDESC); 378 } 379 } else { 380 retval = res; 381 } 382 break; 383 384 default: 385 /* must be a const offset in debug_loc */ 386 ; /* do nothing */ 387 } 388 dwarf_dealloc(dbg, attr, DW_DLA_ATTR); 389 } /* else error or no entry */ 390 retval = fres; 391 } else { 392 retval = ares; 393 } 394 return retval; 395} 396 397/* 398 Return DW_DLV_OK, or DW_DLV_ERROR 399 400 Handle the addrs in a single die. 401*/ 402static int 403process_this_die_attrs(Dwarf_Debug dbg, Dwarf_Die newdie, int *errval) 404{ 405 Dwarf_Error err; 406 Dwarf_Half i; 407 Dwarf_Half newattrnum; 408 int res; 409 int tres; 410 Dwarf_Half ltag; 411 412 Dwarf_Off doff; 413 int doffres = dwarf_dieoffset(newdie, &doff, &err); 414 415 if (doffres != DW_DLV_OK) { 416 if (doffres == DW_DLV_ERROR) { 417 *errval = (int) dwarf_errno(err); 418 } 419 return doffres; 420 } 421 tres = dwarf_tag(newdie, <ag, &err); 422 if (tres != DW_DLV_OK) { 423 return tres; 424 } 425 if (DW_TAG_compile_unit == ltag) { 426 /* because of the way the dwarf_line code works, we ** do lines 427 only per compile unit. ** This may turn out to be wrong if 428 we have lines ** left unconnected to a CU. ** of course such 429 lines will not, at present, be ** used by gnome ** This is 430 not ideal as coded due to the dwarf_line.c issue. */ 431 int lres; 432 433 lres = handle_debug_line(dbg, newdie, send_addr_note, errval); 434 if (lres == DW_DLV_ERROR) { 435 return lres; 436 } 437 } 438 439 for (i = 0; i < sizeof(might_have_addr) / sizeof(int); i++) { 440 int resattr; 441 Dwarf_Bool hasattr; 442 443 newattrnum = might_have_addr[i]; 444 err = 0; 445 resattr = dwarf_hasattr(newdie, newattrnum, &hasattr, &err); 446 if (DW_DLV_OK == resattr) { 447 if (hasattr) { 448 res = handle_attr_addr(dbg, newdie, newattrnum, &err); 449 if (res != DW_DLV_OK) { 450 *errval = (int) dwarf_errno(err); 451 return DW_DLV_ERROR; 452 } 453 } 454 } else { 455 if (resattr == DW_DLV_ERROR) { 456 *errval = (int) dwarf_errno(err); 457 return resattr; 458 } 459 } 460 } 461 for (i = 0; i < sizeof(might_have_locdesc) / sizeof(int); i++) { 462 int resattr; 463 Dwarf_Bool hasattr; 464 465 newattrnum = might_have_locdesc[i]; 466 err = 0; 467 resattr = dwarf_hasattr(newdie, newattrnum, &hasattr, &err); 468 if (DW_DLV_OK == resattr) { 469 if (hasattr) { 470 res = 471 handle_attr_locdesc(dbg, newdie, newattrnum, &err); 472 if (res != DW_DLV_OK) { 473 *errval = (int) dwarf_errno(err); 474 return DW_DLV_ERROR; 475 } 476 } 477 } else { 478 if (resattr == DW_DLV_ERROR) { 479 *errval = (int) dwarf_errno(err); 480 return resattr; 481 } 482 } 483 } 484 485 return DW_DLV_OK; 486} 487 488/* 489 Handle siblings as a list, 490 Do children by recursing. 491 Effectively this is walking the tree preorder. 492 493 This dealloc's any die passed to it, so the 494 caller should not do that dealloc. 495 It seems more logical to have the one causing 496 the alloc to do the dealloc, but that way this 497 routine became a mess. 498 499*/ 500static int 501do_this_die_and_dealloc(Dwarf_Debug dbg, Dwarf_Die die, int *errval) 502{ 503 504 Dwarf_Die prevdie = 0; 505 Dwarf_Die newdie = die; 506 Dwarf_Error err = 0; 507 int res = 0; 508 int sibres = DW_DLV_OK; 509 int tres = DW_DLV_OK; 510 Dwarf_Die sibdie; 511 512 while (sibres == DW_DLV_OK) { 513 Dwarf_Die ch_die; 514 515 516 res = process_this_die_attrs(dbg, newdie, errval); 517 switch (res) { 518 case DW_DLV_OK: 519 break; 520 case DW_DLV_NO_ENTRY: 521 break; 522 default: 523 case DW_DLV_ERROR: 524 if (prevdie) { 525 dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); 526 prevdie = 0; 527 } 528 return DW_DLV_ERROR; 529 } 530 531 tres = dwarf_child(newdie, &ch_die, &err); 532 533 if (tres == DW_DLV_OK) { 534 res = do_this_die_and_dealloc(dbg, ch_die, errval); 535 switch (res) { 536 case DW_DLV_OK: 537 break; 538 case DW_DLV_NO_ENTRY: 539 break; 540 default: 541 case DW_DLV_ERROR: 542 if (prevdie) { 543 dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); 544 prevdie = 0; 545 } 546 return DW_DLV_ERROR; 547 } 548 } else if (tres == DW_DLV_ERROR) { 549 /* An error! */ 550 *errval = (int) dwarf_errno(err); 551 if (prevdie) { 552 dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); 553 prevdie = 0; 554 } 555 dwarf_dealloc(dbg, err, DW_DLA_ERROR); 556 return DW_DLV_ERROR; 557 } /* else was NO ENTRY */ 558 prevdie = newdie; 559 sibdie = 0; 560 sibres = dwarf_siblingof(dbg, newdie, &sibdie, &err); 561 if (prevdie) { 562 dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); 563 prevdie = 0; 564 } 565 newdie = sibdie; 566 567 } 568 if (sibres == DW_DLV_NO_ENTRY) { 569 return DW_DLV_OK; 570 } 571 /* error. */ 572 *errval = (int) dwarf_errno(err); 573 if (prevdie) { 574 dwarf_dealloc(dbg, prevdie, DW_DLA_DIE); 575 prevdie = 0; 576 } 577 dwarf_dealloc(dbg, err, DW_DLA_ERROR); 578 return DW_DLV_ERROR; 579 580} 581 582 583static int 584handle_debug_frame(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, 585 int *errval) 586{ 587 int retval = DW_DLV_OK; 588 int res; 589 Dwarf_Error err; 590 Dwarf_Addr *addrlist; 591 Dwarf_Off *offsetlist; 592 Dwarf_Signed count; 593 int i; 594 595 res = 596 _dwarf_frame_address_offsets(dbg, &addrlist, &offsetlist, 597 &count, &err); 598 if (res == DW_DLV_OK) { 599 for (i = 0; i < count; i++) { 600 cb_func(DW_SECTION_FRAME, offsetlist[i], addrlist[i]); 601 } 602 dwarf_dealloc(dbg, offsetlist, DW_DLA_ADDR); 603 dwarf_dealloc(dbg, addrlist, DW_DLA_ADDR); 604 } else if (res == DW_DLV_NO_ENTRY) { 605 retval = res; 606 } else { 607 *errval = (int) dwarf_errno(err); 608 retval = DW_DLV_ERROR; 609 } 610 return retval; 611 612} 613static int 614handle_debug_aranges(Dwarf_Debug dbg, Dwarf_addr_callback_func cb_func, 615 int *errval) 616{ 617 int retval = DW_DLV_OK; 618 Dwarf_Error err; 619 Dwarf_Addr *aranges; 620 Dwarf_Signed count; 621 int indx; 622 Dwarf_Off *offsets; 623 624 retval = 625 _dwarf_get_aranges_addr_offsets(dbg, &aranges, &offsets, &count, 626 &err); 627 if (retval == DW_DLV_OK) { 628 if (count == 0) { 629 retval = DW_DLV_NO_ENTRY; 630 } else { 631 for (indx = 0; indx < count; indx++) { 632 cb_func(DW_SECTION_ARANGES, offsets[indx], 633 aranges[indx]); 634 } 635 } 636 dwarf_dealloc(dbg, aranges, DW_DLA_ADDR); 637 dwarf_dealloc(dbg, offsets, DW_DLA_ADDR); 638 } else if (retval == DW_DLV_NO_ENTRY) { 639 ; /* do nothing */ 640 } else { 641 *errval = (int) dwarf_errno(err); 642 retval = DW_DLV_ERROR; 643 } 644 return retval; 645} 646static int 647handle_debug_line(Dwarf_Debug dbg, Dwarf_Die cu_die, 648 Dwarf_addr_callback_func cb_func, int *errval) 649{ 650 int retval = DW_DLV_OK; 651 int res; 652 Dwarf_Error err; 653 Dwarf_Addr *addrlist; 654 Dwarf_Off *offsetlist; 655 Dwarf_Unsigned count; 656 Dwarf_Unsigned i; 657 658 res = 659 _dwarf_line_address_offsets(dbg, cu_die, &addrlist, &offsetlist, 660 &count, &err); 661 if (res == DW_DLV_OK) { 662 for (i = 0; i < count; i++) { 663 cb_func(DW_SECTION_LINE, offsetlist[i], addrlist[i]); 664 665 } 666 dwarf_dealloc(dbg, offsetlist, DW_DLA_ADDR); 667 dwarf_dealloc(dbg, addrlist, DW_DLA_ADDR); 668 } else if (res == DW_DLV_NO_ENTRY) { 669 retval = res; 670 } else { 671 *errval = (int) dwarf_errno(err); 672 retval = DW_DLV_ERROR; 673 } 674 return retval; 675} 676 677/* 678 We need to add support for this. Currently we do not 679 generate this section. 680 FIX! 681*/ 682static int 683handle_debug_loc(void) 684{ 685 int retval = DW_DLV_NO_ENTRY; 686 687 return retval; 688} 689