dwarf_getlocation.c revision c16966a0043dc173fcaab5d3f8b754b4e9c9ceb7
1/* Return location expression list. 2 Copyright (C) 2000-2010 Red Hat, Inc. 3 This file is part of Red Hat elfutils. 4 Written by Ulrich Drepper <drepper@redhat.com>, 2000. 5 6 Red Hat elfutils is free software; you can redistribute it and/or modify 7 it under the terms of the GNU General Public License as published by the 8 Free Software Foundation; version 2 of the License. 9 10 Red Hat elfutils is distributed in the hope that it will be useful, but 11 WITHOUT ANY WARRANTY; without even the implied warranty of 12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 13 General Public License for more details. 14 15 You should have received a copy of the GNU General Public License along 16 with Red Hat elfutils; if not, write to the Free Software Foundation, 17 Inc., 51 Franklin Street, Fifth Floor, Boston MA 02110-1301 USA. 18 19 In addition, as a special exception, Red Hat, Inc. gives You the 20 additional right to link the code of Red Hat elfutils with code licensed 21 under any Open Source Initiative certified open source license 22 (http://www.opensource.org/licenses/index.php) which requires the 23 distribution of source code with any binary distribution and to 24 distribute linked combinations of the two. Non-GPL Code permitted under 25 this exception must only link to the code of Red Hat elfutils through 26 those well defined interfaces identified in the file named EXCEPTION 27 found in the source code files (the "Approved Interfaces"). The files 28 of Non-GPL Code may instantiate templates or use macros or inline 29 functions from the Approved Interfaces without causing the resulting 30 work to be covered by the GNU General Public License. Only Red Hat, 31 Inc. may make changes or additions to the list of Approved Interfaces. 32 Red Hat's grant of this exception is conditioned upon your not adding 33 any new exceptions. If you wish to add a new Approved Interface or 34 exception, please contact Red Hat. You must obey the GNU General Public 35 License in all respects for all of the Red Hat elfutils code and other 36 code used in conjunction with Red Hat elfutils except the Non-GPL Code 37 covered by this exception. If you modify this file, you may extend this 38 exception to your version of the file, but you are not obligated to do 39 so. If you do not wish to provide this exception without modification, 40 you must delete this exception statement from your version and license 41 this file solely under the GPL without exception. 42 43 Red Hat elfutils is an included package of the Open Invention Network. 44 An included package of the Open Invention Network is a package for which 45 Open Invention Network licensees cross-license their patents. No patent 46 license is granted, either expressly or impliedly, by designation as an 47 included package. Should you wish to participate in the Open Invention 48 Network licensing program, please visit www.openinventionnetwork.com 49 <http://www.openinventionnetwork.com>. */ 50 51#ifdef HAVE_CONFIG_H 52# include <config.h> 53#endif 54 55#include <dwarf.h> 56#include <search.h> 57#include <stdlib.h> 58#include <assert.h> 59 60#include <libdwP.h> 61 62 63static bool 64attr_ok (Dwarf_Attribute *attr) 65{ 66 if (attr == NULL) 67 return false; 68 69 /* Must be one of the attributes listed below. */ 70 switch (attr->code) 71 { 72 case DW_AT_location: 73 case DW_AT_data_member_location: 74 case DW_AT_vtable_elem_location: 75 case DW_AT_string_length: 76 case DW_AT_use_location: 77 case DW_AT_frame_base: 78 case DW_AT_return_addr: 79 case DW_AT_static_link: 80 break; 81 82 default: 83 __libdw_seterrno (DWARF_E_NO_LOCLIST); 84 return false; 85 } 86 87 return true; 88} 89 90 91struct loclist 92{ 93 uint8_t atom; 94 Dwarf_Word number; 95 Dwarf_Word number2; 96 Dwarf_Word offset; 97 struct loclist *next; 98}; 99 100 101static int 102loc_compare (const void *p1, const void *p2) 103{ 104 const struct loc_s *l1 = (const struct loc_s *) p1; 105 const struct loc_s *l2 = (const struct loc_s *) p2; 106 107 if ((uintptr_t) l1->addr < (uintptr_t) l2->addr) 108 return -1; 109 if ((uintptr_t) l1->addr > (uintptr_t) l2->addr) 110 return 1; 111 112 return 0; 113} 114 115/* For each DW_OP_implicit_value, we store a special entry in the cache. 116 This points us directly to the block data for later fetching. */ 117static void 118store_implicit_value (Dwarf *dbg, void **cache, Dwarf_Op *op, 119 unsigned char *data) 120{ 121 struct loc_block_s *block = libdw_alloc (dbg, struct loc_block_s, 122 sizeof (struct loc_block_s), 1); 123 block->addr = op; 124 block->data = data + op->number2; 125 block->length = op->number; 126 (void) tsearch (block, cache, loc_compare); 127} 128 129int 130dwarf_getlocation_implicit_value (attr, op, return_block) 131 Dwarf_Attribute *attr; 132 const Dwarf_Op *op; 133 Dwarf_Block *return_block; 134{ 135 if (attr == NULL) 136 return -1; 137 138 struct loc_block_s fake = { .addr = (void *) op }; 139 struct loc_block_s **found = tfind (&fake, &attr->cu->locs, loc_compare); 140 if (unlikely (found == NULL)) 141 { 142 __libdw_seterrno (DWARF_E_NO_BLOCK); 143 return -1; 144 } 145 146 return_block->length = (*found)->length; 147 return_block->data = (*found)->data; 148 return 0; 149} 150 151/* DW_AT_data_member_location can be a constant as well as a loclistptr. 152 Only data[48] indicate a loclistptr. */ 153static int 154check_constant_offset (Dwarf_Attribute *attr, 155 Dwarf_Op **llbuf, size_t *listlen) 156{ 157 if (attr->code != DW_AT_data_member_location) 158 return 1; 159 160 switch (attr->form) 161 { 162 /* Punt for any non-constant form. */ 163 default: 164 return 1; 165 166 case DW_FORM_data1: 167 case DW_FORM_data2: 168 case DW_FORM_data4: 169 case DW_FORM_data8: 170 case DW_FORM_sdata: 171 case DW_FORM_udata: 172 break; 173 } 174 175 /* Check whether we already cached this location. */ 176 struct loc_s fake = { .addr = attr->valp }; 177 struct loc_s **found = tfind (&fake, &attr->cu->locs, loc_compare); 178 179 if (found == NULL) 180 { 181 Dwarf_Word offset; 182 if (INTUSE(dwarf_formudata) (attr, &offset) != 0) 183 return -1; 184 185 Dwarf_Op *result = libdw_alloc (attr->cu->dbg, 186 Dwarf_Op, sizeof (Dwarf_Op), 1); 187 188 result->atom = DW_OP_plus_uconst; 189 result->number = offset; 190 result->number2 = 0; 191 result->offset = 0; 192 193 /* Insert a record in the search tree so we can find it again later. */ 194 struct loc_s *newp = libdw_alloc (attr->cu->dbg, 195 struct loc_s, sizeof (struct loc_s), 196 1); 197 newp->addr = attr->valp; 198 newp->loc = result; 199 newp->nloc = 1; 200 201 found = tsearch (newp, &attr->cu->locs, loc_compare); 202 } 203 204 assert ((*found)->nloc == 1); 205 206 if (llbuf != NULL) 207 { 208 *llbuf = (*found)->loc; 209 *listlen = 1; 210 } 211 212 return 0; 213} 214 215int 216internal_function 217__libdw_intern_expression (Dwarf *dbg, bool other_byte_order, 218 unsigned int address_size, unsigned int ref_size, 219 void **cache, const Dwarf_Block *block, 220 bool cfap, bool valuep, 221 Dwarf_Op **llbuf, size_t *listlen, int sec_index) 222{ 223 /* Check whether we already looked at this list. */ 224 struct loc_s fake = { .addr = block->data }; 225 struct loc_s **found = tfind (&fake, cache, loc_compare); 226 if (found != NULL) 227 { 228 /* We already saw it. */ 229 *llbuf = (*found)->loc; 230 *listlen = (*found)->nloc; 231 232 if (valuep) 233 { 234 assert (*listlen > 1); 235 assert ((*llbuf)[*listlen - 1].atom == DW_OP_stack_value); 236 } 237 238 return 0; 239 } 240 241 const unsigned char *data = block->data; 242 const unsigned char *const end_data = data + block->length; 243 244 const struct { bool other_byte_order; } bo = { other_byte_order }; 245 246 struct loclist *loclist = NULL; 247 unsigned int n = 0; 248 /* Decode the opcodes. It is possible in some situations to have a 249 block of size zero. */ 250 while (data < end_data) 251 { 252 struct loclist *newloc; 253 newloc = (struct loclist *) alloca (sizeof (struct loclist)); 254 newloc->number = 0; 255 newloc->number2 = 0; 256 newloc->offset = data - block->data; 257 newloc->next = loclist; 258 loclist = newloc; 259 ++n; 260 261 switch ((newloc->atom = *data++)) 262 { 263 case DW_OP_addr: 264 /* Address, depends on address size of CU. */ 265 if (__libdw_read_address_inc (dbg, sec_index, &data, 266 address_size, &newloc->number)) 267 return -1; 268 break; 269 270 case DW_OP_call_ref: 271 /* DW_FORM_ref_addr, depends on offset size of CU. */ 272 if (__libdw_read_offset_inc (dbg, sec_index, &data, ref_size, 273 &newloc->number, IDX_debug_info, 0)) 274 return -1; 275 break; 276 277 case DW_OP_deref: 278 case DW_OP_dup: 279 case DW_OP_drop: 280 case DW_OP_over: 281 case DW_OP_swap: 282 case DW_OP_rot: 283 case DW_OP_xderef: 284 case DW_OP_abs: 285 case DW_OP_and: 286 case DW_OP_div: 287 case DW_OP_minus: 288 case DW_OP_mod: 289 case DW_OP_mul: 290 case DW_OP_neg: 291 case DW_OP_not: 292 case DW_OP_or: 293 case DW_OP_plus: 294 case DW_OP_shl: 295 case DW_OP_shr: 296 case DW_OP_shra: 297 case DW_OP_xor: 298 case DW_OP_eq: 299 case DW_OP_ge: 300 case DW_OP_gt: 301 case DW_OP_le: 302 case DW_OP_lt: 303 case DW_OP_ne: 304 case DW_OP_lit0 ... DW_OP_lit31: 305 case DW_OP_reg0 ... DW_OP_reg31: 306 case DW_OP_nop: 307 case DW_OP_push_object_address: 308 case DW_OP_call_frame_cfa: 309 case DW_OP_form_tls_address: 310 case DW_OP_GNU_push_tls_address: 311 case DW_OP_stack_value: 312 /* No operand. */ 313 break; 314 315 case DW_OP_const1u: 316 case DW_OP_pick: 317 case DW_OP_deref_size: 318 case DW_OP_xderef_size: 319 if (unlikely (data >= end_data)) 320 { 321 invalid: 322 __libdw_seterrno (DWARF_E_INVALID_DWARF); 323 return -1; 324 } 325 326 newloc->number = *data++; 327 break; 328 329 case DW_OP_const1s: 330 if (unlikely (data >= end_data)) 331 goto invalid; 332 333 newloc->number = *((int8_t *) data); 334 ++data; 335 break; 336 337 case DW_OP_const2u: 338 if (unlikely (data + 2 > end_data)) 339 goto invalid; 340 341 newloc->number = read_2ubyte_unaligned_inc (&bo, data); 342 break; 343 344 case DW_OP_const2s: 345 case DW_OP_skip: 346 case DW_OP_bra: 347 case DW_OP_call2: 348 if (unlikely (data + 2 > end_data)) 349 goto invalid; 350 351 newloc->number = read_2sbyte_unaligned_inc (&bo, data); 352 break; 353 354 case DW_OP_const4u: 355 if (unlikely (data + 4 > end_data)) 356 goto invalid; 357 358 newloc->number = read_4ubyte_unaligned_inc (&bo, data); 359 break; 360 361 case DW_OP_const4s: 362 case DW_OP_call4: 363 if (unlikely (data + 4 > end_data)) 364 goto invalid; 365 366 newloc->number = read_4sbyte_unaligned_inc (&bo, data); 367 break; 368 369 case DW_OP_const8u: 370 if (unlikely (data + 8 > end_data)) 371 goto invalid; 372 373 newloc->number = read_8ubyte_unaligned_inc (&bo, data); 374 break; 375 376 case DW_OP_const8s: 377 if (unlikely (data + 8 > end_data)) 378 goto invalid; 379 380 newloc->number = read_8sbyte_unaligned_inc (&bo, data); 381 break; 382 383 case DW_OP_constu: 384 case DW_OP_plus_uconst: 385 case DW_OP_regx: 386 case DW_OP_piece: 387 /* XXX Check size. */ 388 get_uleb128 (newloc->number, data); 389 break; 390 391 case DW_OP_consts: 392 case DW_OP_breg0 ... DW_OP_breg31: 393 case DW_OP_fbreg: 394 /* XXX Check size. */ 395 get_sleb128 (newloc->number, data); 396 break; 397 398 case DW_OP_bregx: 399 /* XXX Check size. */ 400 get_uleb128 (newloc->number, data); 401 get_sleb128 (newloc->number2, data); 402 break; 403 404 case DW_OP_bit_piece: 405 /* XXX Check size. */ 406 get_uleb128 (newloc->number, data); 407 get_uleb128 (newloc->number2, data); 408 break; 409 410 case DW_OP_implicit_value: 411 /* This cannot be used in a CFI expression. */ 412 if (unlikely (dbg == NULL)) 413 goto invalid; 414 415 /* XXX Check size. */ 416 get_uleb128 (newloc->number, data); /* Block length. */ 417 if (unlikely ((Dwarf_Word) (end_data - data) < newloc->number)) 418 goto invalid; 419 newloc->number2 = data - block->data; /* Relative block offset. */ 420 data += newloc->number; /* Skip the block. */ 421 break; 422 423 default: 424 goto invalid; 425 } 426 } 427 428 if (unlikely (n == 0)) 429 { 430 /* This is not allowed. 431 432 XXX Is it? */ 433 goto invalid; 434 } 435 436 if (valuep) 437 { 438 struct loclist *newloc; 439 newloc = (struct loclist *) alloca (sizeof (struct loclist)); 440 newloc->atom = DW_OP_stack_value; 441 newloc->number = 0; 442 newloc->number2 = 0; 443 newloc->offset = data - block->data; 444 newloc->next = loclist; 445 loclist = newloc; 446 ++n; 447 } 448 449 if (cfap) 450 ++n; 451 452 /* Allocate the array. */ 453 Dwarf_Op *result; 454 if (dbg != NULL) 455 result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n); 456 else 457 { 458 result = malloc (sizeof *result * n); 459 if (result == NULL) 460 { 461 nomem: 462 __libdw_seterrno (DWARF_E_NOMEM); 463 return -1; 464 } 465 } 466 467 /* Store the result. */ 468 *llbuf = result; 469 *listlen = n; 470 471 if (cfap) 472 { 473 /* Synthesize the operation to push the CFA before the expression. */ 474 --n; 475 result[0].atom = DW_OP_call_frame_cfa; 476 result[0].number = 0; 477 result[0].number2 = 0; 478 result[0].offset = -1; 479 } 480 481 do 482 { 483 /* We populate the array from the back since the list is backwards. */ 484 --n; 485 result[n].atom = loclist->atom; 486 result[n].number = loclist->number; 487 result[n].number2 = loclist->number2; 488 result[n].offset = loclist->offset; 489 490 if (result[n].atom == DW_OP_implicit_value) 491 store_implicit_value (dbg, cache, &result[n], block->data); 492 493 loclist = loclist->next; 494 } 495 while (n > 0); 496 497 /* Insert a record in the search tree so that we can find it again later. */ 498 struct loc_s *newp; 499 if (dbg != NULL) 500 newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 1); 501 else 502 { 503 newp = malloc (sizeof *newp); 504 if (newp == NULL) 505 { 506 free (result); 507 goto nomem; 508 } 509 } 510 511 newp->addr = block->data; 512 newp->loc = result; 513 newp->nloc = *listlen; 514 (void) tsearch (newp, cache, loc_compare); 515 516 /* We did it. */ 517 return 0; 518} 519 520static int 521getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, 522 Dwarf_Op **llbuf, size_t *listlen, int sec_index) 523{ 524 return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order, 525 cu->address_size, (cu->version == 2 526 ? cu->address_size 527 : cu->offset_size), 528 &cu->locs, block, 529 false, false, 530 llbuf, listlen, sec_index); 531} 532 533int 534dwarf_getlocation (attr, llbuf, listlen) 535 Dwarf_Attribute *attr; 536 Dwarf_Op **llbuf; 537 size_t *listlen; 538{ 539 if (! attr_ok (attr)) 540 return -1; 541 542 int result = check_constant_offset (attr, llbuf, listlen); 543 if (result != 1) 544 return result; 545 546 /* If it has a block form, it's a single location expression. */ 547 Dwarf_Block block; 548 if (INTUSE(dwarf_formblock) (attr, &block) != 0) 549 return -1; 550 551 return getlocation (attr->cu, &block, llbuf, listlen, cu_sec_idx (attr->cu)); 552} 553 554int 555dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs) 556 Dwarf_Attribute *attr; 557 Dwarf_Addr address; 558 Dwarf_Op **llbufs; 559 size_t *listlens; 560 size_t maxlocs; 561{ 562 if (! attr_ok (attr)) 563 return -1; 564 565 if (llbufs == NULL) 566 maxlocs = SIZE_MAX; 567 568 /* If it has a block form, it's a single location expression. */ 569 Dwarf_Block block; 570 if (INTUSE(dwarf_formblock) (attr, &block) == 0) 571 { 572 if (maxlocs == 0) 573 return 0; 574 if (llbufs != NULL && 575 getlocation (attr->cu, &block, &llbufs[0], &listlens[0], 576 cu_sec_idx (attr->cu)) != 0) 577 return -1; 578 return listlens[0] == 0 ? 0 : 1; 579 } 580 581 int error = INTUSE(dwarf_errno) (); 582 if (unlikely (error != DWARF_E_NO_BLOCK)) 583 { 584 __libdw_seterrno (error); 585 return -1; 586 } 587 588 int result = check_constant_offset (attr, &llbufs[0], &listlens[0]); 589 if (result != 1) 590 return result ?: 1; 591 592 unsigned char *endp; 593 unsigned char *readp = __libdw_formptr (attr, IDX_debug_loc, 594 DWARF_E_NO_LOCLIST, &endp, NULL); 595 if (readp == NULL) 596 return -1; 597 598 Dwarf_Addr base = (Dwarf_Addr) -1; 599 size_t got = 0; 600 while (got < maxlocs) 601 { 602 if (endp - readp < attr->cu->address_size * 2) 603 { 604 invalid: 605 __libdw_seterrno (DWARF_E_INVALID_DWARF); 606 return -1; 607 } 608 609 Dwarf_Addr begin; 610 Dwarf_Addr end; 611 612 int status 613 = __libdw_read_begin_end_pair_inc (attr->cu->dbg, IDX_debug_loc, 614 &readp, attr->cu->address_size, 615 &begin, &end, &base); 616 if (status == 2) /* End of list entry. */ 617 break; 618 else if (status == 1) /* Base address selected. */ 619 continue; 620 else if (status < 0) 621 return status; 622 623 if (endp - readp < 2) 624 goto invalid; 625 626 /* We have a location expression. */ 627 block.length = read_2ubyte_unaligned_inc (attr->cu->dbg, readp); 628 block.data = readp; 629 if (endp - readp < (ptrdiff_t) block.length) 630 goto invalid; 631 readp += block.length; 632 633 if (base == (Dwarf_Addr) -1) 634 { 635 /* Fetch the CU's base address. */ 636 Dwarf_Die cudie = CUDIE (attr->cu); 637 638 /* Find the base address of the compilation unit. It will 639 normally be specified by DW_AT_low_pc. In DWARF-3 draft 4, 640 the base address could be overridden by DW_AT_entry_pc. It's 641 been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc 642 for compilation units with discontinuous ranges. */ 643 Dwarf_Attribute attr_mem; 644 if (unlikely (INTUSE(dwarf_lowpc) (&cudie, &base) != 0) 645 && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie, 646 DW_AT_entry_pc, 647 &attr_mem), 648 &base) != 0) 649 { 650 if (INTUSE(dwarf_errno) () != 0) 651 return -1; 652 653 /* The compiler provided no base address when it should 654 have. Buggy GCC does this when it used absolute 655 addresses in the location list and no DW_AT_ranges. */ 656 base = 0; 657 } 658 } 659 660 if (address >= base + begin && address < base + end) 661 { 662 /* This one matches the address. */ 663 if (llbufs != NULL 664 && unlikely (getlocation (attr->cu, &block, 665 &llbufs[got], &listlens[got], 666 IDX_debug_loc) != 0)) 667 return -1; 668 ++got; 669 } 670 } 671 672 return got; 673} 674