dwarf_getlocation.c revision f0371041995308d197447019eb2ac9285c96477b
1/* Return location expression list. 2 Copyright (C) 2000-2009 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 Dwarf_Op *op; 133 Dwarf_Block *return_block; 134{ 135 if (attr == NULL) 136 return -1; 137 138 struct loc_block_s fake = { .addr = 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 || attr->form == DW_FORM_data4 159 || attr->form == DW_FORM_data8) 160 return 1; 161 162 /* Check whether we already cached this location. */ 163 struct loc_s fake = { .addr = attr->valp }; 164 struct loc_s **found = tfind (&fake, &attr->cu->locs, loc_compare); 165 166 if (found == NULL) 167 { 168 Dwarf_Word offset; 169 if (INTUSE(dwarf_formudata) (attr, &offset) != 0) 170 return -1; 171 172 Dwarf_Op *result = libdw_alloc (attr->cu->dbg, 173 Dwarf_Op, sizeof (Dwarf_Op), 1); 174 175 result->atom = DW_OP_plus_uconst; 176 result->number = offset; 177 result->number2 = 0; 178 result->offset = 0; 179 180 /* Insert a record in the search tree so we can find it again later. */ 181 struct loc_s *newp = libdw_alloc (attr->cu->dbg, 182 struct loc_s, sizeof (struct loc_s), 183 1); 184 newp->addr = attr->valp; 185 newp->loc = result; 186 newp->nloc = 1; 187 188 found = tsearch (newp, &attr->cu->locs, loc_compare); 189 } 190 191 assert ((*found)->nloc == 1); 192 193 if (llbuf != NULL) 194 { 195 *llbuf = (*found)->loc; 196 *listlen = 1; 197 } 198 199 return 0; 200} 201 202int 203internal_function 204__libdw_intern_expression (Dwarf *dbg, 205 bool other_byte_order, unsigned int address_size, 206 void **cache, const Dwarf_Block *block, bool valuep, 207 Dwarf_Op **llbuf, size_t *listlen, int sec_index) 208{ 209 /* Check whether we already looked at this list. */ 210 struct loc_s fake = { .addr = block->data }; 211 struct loc_s **found = tfind (&fake, cache, loc_compare); 212 if (found != NULL) 213 { 214 /* We already saw it. */ 215 *llbuf = (*found)->loc; 216 *listlen = (*found)->nloc; 217 218 if (valuep) 219 { 220 assert (*listlen > 1); 221 assert ((*llbuf)[*listlen - 1].atom == DW_OP_stack_value); 222 } 223 224 return 0; 225 } 226 227 const unsigned char *data = block->data; 228 const unsigned char *const end_data = data + block->length; 229 230 const struct { bool other_byte_order; } bo = { other_byte_order }; 231 232 struct loclist *loclist = NULL; 233 unsigned int n = 0; 234 /* Decode the opcodes. It is possible in some situations to have a 235 block of size zero. */ 236 while (data < end_data) 237 { 238 struct loclist *newloc; 239 newloc = (struct loclist *) alloca (sizeof (struct loclist)); 240 newloc->number = 0; 241 newloc->number2 = 0; 242 newloc->offset = data - block->data; 243 newloc->next = loclist; 244 loclist = newloc; 245 ++n; 246 247 switch ((newloc->atom = *data++)) 248 { 249 case DW_OP_addr: 250 /* Address, depends on address size of CU. */ 251 if (__libdw_read_address_inc (dbg, sec_index, &data, 252 address_size, &newloc->number)) 253 return -1; 254 break; 255 256 case DW_OP_deref: 257 case DW_OP_dup: 258 case DW_OP_drop: 259 case DW_OP_over: 260 case DW_OP_swap: 261 case DW_OP_rot: 262 case DW_OP_xderef: 263 case DW_OP_abs: 264 case DW_OP_and: 265 case DW_OP_div: 266 case DW_OP_minus: 267 case DW_OP_mod: 268 case DW_OP_mul: 269 case DW_OP_neg: 270 case DW_OP_not: 271 case DW_OP_or: 272 case DW_OP_plus: 273 case DW_OP_shl: 274 case DW_OP_shr: 275 case DW_OP_shra: 276 case DW_OP_xor: 277 case DW_OP_eq: 278 case DW_OP_ge: 279 case DW_OP_gt: 280 case DW_OP_le: 281 case DW_OP_lt: 282 case DW_OP_ne: 283 case DW_OP_lit0 ... DW_OP_lit31: 284 case DW_OP_reg0 ... DW_OP_reg31: 285 case DW_OP_nop: 286 case DW_OP_push_object_address: 287 case DW_OP_call_ref: 288 case DW_OP_call_frame_cfa: 289 case DW_OP_form_tls_address: 290 case DW_OP_GNU_push_tls_address: 291 case DW_OP_stack_value: 292 /* No operand. */ 293 break; 294 295 case DW_OP_const1u: 296 case DW_OP_pick: 297 case DW_OP_deref_size: 298 case DW_OP_xderef_size: 299 if (unlikely (data >= end_data)) 300 { 301 invalid: 302 __libdw_seterrno (DWARF_E_INVALID_DWARF); 303 return -1; 304 } 305 306 newloc->number = *data++; 307 break; 308 309 case DW_OP_const1s: 310 if (unlikely (data >= end_data)) 311 goto invalid; 312 313 newloc->number = *((int8_t *) data); 314 ++data; 315 break; 316 317 case DW_OP_const2u: 318 if (unlikely (data + 2 > end_data)) 319 goto invalid; 320 321 newloc->number = read_2ubyte_unaligned_inc (&bo, data); 322 break; 323 324 case DW_OP_const2s: 325 case DW_OP_skip: 326 case DW_OP_bra: 327 case DW_OP_call2: 328 if (unlikely (data + 2 > end_data)) 329 goto invalid; 330 331 newloc->number = read_2sbyte_unaligned_inc (&bo, data); 332 break; 333 334 case DW_OP_const4u: 335 if (unlikely (data + 4 > end_data)) 336 goto invalid; 337 338 newloc->number = read_4ubyte_unaligned_inc (&bo, data); 339 break; 340 341 case DW_OP_const4s: 342 case DW_OP_call4: 343 if (unlikely (data + 4 > end_data)) 344 goto invalid; 345 346 newloc->number = read_4sbyte_unaligned_inc (&bo, data); 347 break; 348 349 case DW_OP_const8u: 350 if (unlikely (data + 8 > end_data)) 351 goto invalid; 352 353 newloc->number = read_8ubyte_unaligned_inc (&bo, data); 354 break; 355 356 case DW_OP_const8s: 357 if (unlikely (data + 8 > end_data)) 358 goto invalid; 359 360 newloc->number = read_8sbyte_unaligned_inc (&bo, data); 361 break; 362 363 case DW_OP_constu: 364 case DW_OP_plus_uconst: 365 case DW_OP_regx: 366 case DW_OP_piece: 367 /* XXX Check size. */ 368 get_uleb128 (newloc->number, data); 369 break; 370 371 case DW_OP_consts: 372 case DW_OP_breg0 ... DW_OP_breg31: 373 case DW_OP_fbreg: 374 /* XXX Check size. */ 375 get_sleb128 (newloc->number, data); 376 break; 377 378 case DW_OP_bregx: 379 /* XXX Check size. */ 380 get_uleb128 (newloc->number, data); 381 get_sleb128 (newloc->number2, data); 382 break; 383 384 case DW_OP_bit_piece: 385 /* XXX Check size. */ 386 get_uleb128 (newloc->number, data); 387 get_uleb128 (newloc->number2, data); 388 break; 389 390 case DW_OP_implicit_value: 391 /* This cannot be used in a CFI expression. */ 392 if (unlikely (dbg == NULL)) 393 goto invalid; 394 395 /* XXX Check size. */ 396 get_uleb128 (newloc->number, data); /* Block length. */ 397 if (unlikely ((Dwarf_Word) (end_data - data) < newloc->number)) 398 goto invalid; 399 newloc->number2 = data - block->data; /* Relative block offset. */ 400 data += newloc->number; /* Skip the block. */ 401 break; 402 403 default: 404 goto invalid; 405 } 406 } 407 408 if (unlikely (n == 0)) 409 { 410 /* This is not allowed. 411 412 XXX Is it? */ 413 goto invalid; 414 } 415 416 if (valuep) 417 { 418 struct loclist *newloc; 419 newloc = (struct loclist *) alloca (sizeof (struct loclist)); 420 newloc->atom = DW_OP_stack_value; 421 newloc->number = 0; 422 newloc->number2 = 0; 423 newloc->offset = data - block->data; 424 newloc->next = loclist; 425 loclist = newloc; 426 ++n; 427 } 428 429 /* Allocate the array. */ 430 Dwarf_Op *result; 431 if (dbg != NULL) 432 result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n); 433 else 434 { 435 result = malloc (sizeof *result * n); 436 if (result == NULL) 437 { 438 nomem: 439 __libdw_seterrno (DWARF_E_NOMEM); 440 return -1; 441 } 442 } 443 444 /* Store the result. */ 445 *llbuf = result; 446 *listlen = n; 447 448 do 449 { 450 /* We populate the array from the back since the list is backwards. */ 451 --n; 452 result[n].atom = loclist->atom; 453 result[n].number = loclist->number; 454 result[n].number2 = loclist->number2; 455 result[n].offset = loclist->offset; 456 457 if (result[n].atom == DW_OP_implicit_value) 458 store_implicit_value (dbg, cache, &result[n], block->data); 459 460 loclist = loclist->next; 461 } 462 while (n > 0); 463 464 /* Insert a record in the search tree so that we can find it again later. */ 465 struct loc_s *newp; 466 if (dbg != NULL) 467 newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 1); 468 else 469 { 470 newp = malloc (sizeof *newp); 471 if (newp == NULL) 472 { 473 free (result); 474 goto nomem; 475 } 476 } 477 478 newp->addr = block->data; 479 newp->loc = result; 480 newp->nloc = *listlen; 481 (void) tsearch (newp, cache, loc_compare); 482 483 /* We did it. */ 484 return 0; 485} 486 487static int 488getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, 489 Dwarf_Op **llbuf, size_t *listlen, int sec_index) 490{ 491 return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order, 492 cu->address_size, &cu->locs, block, false, 493 llbuf, listlen, sec_index); 494} 495 496int 497dwarf_getlocation (attr, llbuf, listlen) 498 Dwarf_Attribute *attr; 499 Dwarf_Op **llbuf; 500 size_t *listlen; 501{ 502 int result = check_constant_offset (attr, llbuf, listlen); 503 if (result != 1) 504 return result; 505 506 if (! attr_ok (attr)) 507 return -1; 508 509 /* If it has a block form, it's a single location expression. */ 510 Dwarf_Block block; 511 if (INTUSE(dwarf_formblock) (attr, &block) != 0) 512 return -1; 513 514 return getlocation (attr->cu, &block, llbuf, listlen, IDX_debug_info); 515} 516 517int 518dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs) 519 Dwarf_Attribute *attr; 520 Dwarf_Addr address; 521 Dwarf_Op **llbufs; 522 size_t *listlens; 523 size_t maxlocs; 524{ 525 if (! attr_ok (attr)) 526 return -1; 527 528 if (llbufs == NULL) 529 maxlocs = SIZE_MAX; 530 531 /* If it has a block form, it's a single location expression. */ 532 Dwarf_Block block; 533 if (INTUSE(dwarf_formblock) (attr, &block) == 0) 534 { 535 if (maxlocs == 0) 536 return 0; 537 if (llbufs != NULL && 538 getlocation (attr->cu, &block, &llbufs[0], &listlens[0], 539 IDX_debug_info) != 0) 540 return -1; 541 return listlens[0] == 0 ? 0 : 1; 542 } 543 544 int error = INTUSE(dwarf_errno) (); 545 if (unlikely (error != DWARF_E_NO_BLOCK)) 546 { 547 __libdw_seterrno (error); 548 return -1; 549 } 550 551 int result = check_constant_offset (attr, &llbufs[0], &listlens[0]); 552 if (result != 1) 553 return result ?: 1; 554 555 unsigned char *endp; 556 unsigned char *readp = __libdw_formptr (attr, IDX_debug_loc, 557 DWARF_E_NO_LOCLIST, &endp, NULL); 558 if (readp == NULL) 559 return -1; 560 561 Dwarf_Addr base = (Dwarf_Addr) -1; 562 size_t got = 0; 563 while (got < maxlocs) 564 { 565 if (endp - readp < attr->cu->address_size * 2) 566 { 567 invalid: 568 __libdw_seterrno (DWARF_E_INVALID_DWARF); 569 return -1; 570 } 571 572 Dwarf_Addr begin; 573 Dwarf_Addr end; 574 575 int status 576 = __libdw_read_begin_end_pair_inc (attr->cu->dbg, IDX_debug_loc, 577 &readp, attr->cu->address_size, 578 &begin, &end, &base); 579 if (status == 2) /* End of list entry. */ 580 break; 581 else if (status == 1) /* Base address selected. */ 582 continue; 583 else if (status < 0) 584 return status; 585 586 if (endp - readp < 2) 587 goto invalid; 588 589 /* We have a location expression. */ 590 block.length = read_2ubyte_unaligned_inc (attr->cu->dbg, readp); 591 block.data = readp; 592 if (endp - readp < (ptrdiff_t) block.length) 593 goto invalid; 594 readp += block.length; 595 596 if (base == (Dwarf_Addr) -1) 597 { 598 /* Fetch the CU's base address. */ 599 Dwarf_Die cudie = CUDIE (attr->cu); 600 601 /* Find the base address of the compilation unit. It will 602 normally be specified by DW_AT_low_pc. In DWARF-3 draft 4, 603 the base address could be overridden by DW_AT_entry_pc. It's 604 been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc 605 for compilation units with discontinuous ranges. */ 606 Dwarf_Attribute attr_mem; 607 if (unlikely (INTUSE(dwarf_lowpc) (&cudie, &base) != 0) 608 && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie, 609 DW_AT_entry_pc, 610 &attr_mem), 611 &base) != 0) 612 { 613 if (INTUSE(dwarf_errno) () != 0) 614 return -1; 615 616 /* The compiler provided no base address when it should 617 have. Buggy GCC does this when it used absolute 618 addresses in the location list and no DW_AT_ranges. */ 619 base = 0; 620 } 621 } 622 623 if (address >= base + begin && address < base + end) 624 { 625 /* This one matches the address. */ 626 if (llbufs != NULL 627 && unlikely (getlocation (attr->cu, &block, 628 &llbufs[got], &listlens[got], 629 IDX_debug_loc) != 0)) 630 return -1; 631 ++got; 632 } 633 } 634 635 return got; 636} 637