1 /* Return location expression list. 2 Copyright (C) 2000, 2001, 2002, 2004, 2005, 2006 Red Hat, Inc. 3 This file is part of Red Hat elfutils. 4 Written by Ulrich Drepper <drepper (at) 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 59 #include <libdwP.h> 60 61 62 static bool 63 attr_ok (Dwarf_Attribute *attr) 64 { 65 if (attr == NULL) 66 return false; 67 68 /* Must be one of the attributes listed below. */ 69 switch (attr->code) 70 { 71 case DW_AT_location: 72 case DW_AT_data_member_location: 73 case DW_AT_vtable_elem_location: 74 case DW_AT_string_length: 75 case DW_AT_use_location: 76 case DW_AT_frame_base: 77 case DW_AT_return_addr: 78 case DW_AT_static_link: 79 break; 80 81 default: 82 __libdw_seterrno (DWARF_E_NO_LOCLIST); 83 return false; 84 } 85 86 return true; 87 } 88 89 90 struct loclist 91 { 92 uint8_t atom; 93 Dwarf_Word number; 94 Dwarf_Word number2; 95 Dwarf_Word offset; 96 struct loclist *next; 97 }; 98 99 100 static int 101 loc_compare (const void *p1, const void *p2) 102 { 103 const struct loc_s *l1 = (const struct loc_s *) p1; 104 const struct loc_s *l2 = (const struct loc_s *) p2; 105 106 if ((uintptr_t) l1->addr < (uintptr_t) l2->addr) 107 return -1; 108 if ((uintptr_t) l1->addr > (uintptr_t) l2->addr) 109 return 1; 110 111 return 0; 112 } 113 114 static int 115 getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, 116 Dwarf_Op **llbuf, size_t *listlen) 117 { 118 Dwarf *dbg = cu->dbg; 119 120 /* Check whether we already looked at this list. */ 121 struct loc_s fake = { .addr = block->data }; 122 struct loc_s **found = tfind (&fake, &cu->locs, loc_compare); 123 if (found != NULL) 124 { 125 /* We already saw it. */ 126 *llbuf = (*found)->loc; 127 *listlen = (*found)->nloc; 128 129 return 0; 130 } 131 132 const unsigned char *data = block->data; 133 const unsigned char *const end_data = data + block->length; 134 135 struct loclist *loclist = NULL; 136 unsigned int n = 0; 137 /* Decode the opcodes. It is possible in some situations to have a 138 block of size zero. */ 139 while (data < end_data) 140 { 141 struct loclist *newloc; 142 newloc = (struct loclist *) alloca (sizeof (struct loclist)); 143 newloc->number = 0; 144 newloc->number2 = 0; 145 newloc->offset = data - block->data; 146 newloc->next = loclist; 147 loclist = newloc; 148 ++n; 149 150 switch ((newloc->atom = *data++)) 151 { 152 case DW_OP_addr: 153 /* Address, depends on address size of CU. */ 154 if (cu->address_size == 4) 155 { 156 if (unlikely (data + 4 > end_data)) 157 { 158 invalid: 159 __libdw_seterrno (DWARF_E_INVALID_DWARF); 160 return -1; 161 } 162 163 newloc->number = read_4ubyte_unaligned_inc (dbg, data); 164 } 165 else 166 { 167 if (unlikely (data + 8 > end_data)) 168 goto invalid; 169 170 newloc->number = read_8ubyte_unaligned_inc (dbg, data); 171 } 172 break; 173 174 case DW_OP_deref: 175 case DW_OP_dup: 176 case DW_OP_drop: 177 case DW_OP_over: 178 case DW_OP_swap: 179 case DW_OP_rot: 180 case DW_OP_xderef: 181 case DW_OP_abs: 182 case DW_OP_and: 183 case DW_OP_div: 184 case DW_OP_minus: 185 case DW_OP_mod: 186 case DW_OP_mul: 187 case DW_OP_neg: 188 case DW_OP_not: 189 case DW_OP_or: 190 case DW_OP_plus: 191 case DW_OP_shl: 192 case DW_OP_shr: 193 case DW_OP_shra: 194 case DW_OP_xor: 195 case DW_OP_eq: 196 case DW_OP_ge: 197 case DW_OP_gt: 198 case DW_OP_le: 199 case DW_OP_lt: 200 case DW_OP_ne: 201 case DW_OP_lit0 ... DW_OP_lit31: 202 case DW_OP_reg0 ... DW_OP_reg31: 203 case DW_OP_nop: 204 case DW_OP_push_object_address: 205 case DW_OP_call_ref: 206 /* No operand. */ 207 break; 208 209 case DW_OP_const1u: 210 case DW_OP_pick: 211 case DW_OP_deref_size: 212 case DW_OP_xderef_size: 213 if (unlikely (data >= end_data)) 214 goto invalid; 215 216 newloc->number = *data++; 217 break; 218 219 case DW_OP_const1s: 220 if (unlikely (data >= end_data)) 221 goto invalid; 222 223 newloc->number = *((int8_t *) data); 224 ++data; 225 break; 226 227 case DW_OP_const2u: 228 if (unlikely (data + 2 > end_data)) 229 goto invalid; 230 231 newloc->number = read_2ubyte_unaligned_inc (dbg, data); 232 break; 233 234 case DW_OP_const2s: 235 case DW_OP_skip: 236 case DW_OP_bra: 237 case DW_OP_call2: 238 if (unlikely (data + 2 > end_data)) 239 goto invalid; 240 241 newloc->number = read_2sbyte_unaligned_inc (dbg, data); 242 break; 243 244 case DW_OP_const4u: 245 if (unlikely (data + 4 > end_data)) 246 goto invalid; 247 248 newloc->number = read_4ubyte_unaligned_inc (dbg, data); 249 break; 250 251 case DW_OP_const4s: 252 case DW_OP_call4: 253 if (unlikely (data + 4 > end_data)) 254 goto invalid; 255 256 newloc->number = read_4sbyte_unaligned_inc (dbg, data); 257 break; 258 259 case DW_OP_const8u: 260 if (unlikely (data + 8 > end_data)) 261 goto invalid; 262 263 newloc->number = read_8ubyte_unaligned_inc (dbg, data); 264 break; 265 266 case DW_OP_const8s: 267 if (unlikely (data + 8 > end_data)) 268 goto invalid; 269 270 newloc->number = read_8sbyte_unaligned_inc (dbg, data); 271 break; 272 273 case DW_OP_constu: 274 case DW_OP_plus_uconst: 275 case DW_OP_regx: 276 case DW_OP_piece: 277 /* XXX Check size. */ 278 get_uleb128 (newloc->number, data); 279 break; 280 281 case DW_OP_consts: 282 case DW_OP_breg0 ... DW_OP_breg31: 283 case DW_OP_fbreg: 284 /* XXX Check size. */ 285 get_sleb128 (newloc->number, data); 286 break; 287 288 case DW_OP_bregx: 289 /* XXX Check size. */ 290 get_uleb128 (newloc->number, data); 291 get_sleb128 (newloc->number2, data); 292 break; 293 294 default: 295 goto invalid; 296 } 297 } 298 299 if (unlikely (n == 0)) 300 { 301 /* This is not allowed. 302 303 XXX Is it? */ 304 goto invalid; 305 } 306 307 /* Allocate the array. */ 308 Dwarf_Op *result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n); 309 310 /* Store the result. */ 311 *llbuf = result; 312 *listlen = n; 313 314 do 315 { 316 /* We populate the array from the back since the list is 317 backwards. */ 318 --n; 319 result[n].atom = loclist->atom; 320 result[n].number = loclist->number; 321 result[n].number2 = loclist->number2; 322 result[n].offset = loclist->offset; 323 324 loclist = loclist->next; 325 } 326 while (n > 0); 327 328 /* Insert a record in the search tree so that we can find it again 329 later. */ 330 struct loc_s *newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 331 1); 332 newp->addr = block->data; 333 newp->loc = result; 334 newp->nloc = *listlen; 335 (void) tsearch (newp, &cu->locs, loc_compare); 336 337 /* We did it. */ 338 return 0; 339 } 340 341 int 342 dwarf_getlocation (attr, llbuf, listlen) 343 Dwarf_Attribute *attr; 344 Dwarf_Op **llbuf; 345 size_t *listlen; 346 { 347 if (! attr_ok (attr)) 348 return -1; 349 350 /* If it has a block form, it's a single location expression. */ 351 Dwarf_Block block; 352 if (INTUSE(dwarf_formblock) (attr, &block) != 0) 353 return -1; 354 355 return getlocation (attr->cu, &block, llbuf, listlen); 356 } 357 358 int 359 dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs) 360 Dwarf_Attribute *attr; 361 Dwarf_Addr address; 362 Dwarf_Op **llbufs; 363 size_t *listlens; 364 size_t maxlocs; 365 { 366 if (! attr_ok (attr)) 367 return -1; 368 369 if (llbufs == NULL) 370 maxlocs = SIZE_MAX; 371 372 /* If it has a block form, it's a single location expression. */ 373 Dwarf_Block block; 374 if (INTUSE(dwarf_formblock) (attr, &block) == 0) 375 { 376 if (maxlocs == 0) 377 return 0; 378 if (llbufs != NULL && 379 getlocation (attr->cu, &block, &llbufs[0], &listlens[0]) != 0) 380 return -1; 381 return listlens[0] == 0 ? 0 : 1; 382 } 383 384 int error = INTUSE(dwarf_errno) (); 385 if (unlikely (error != DWARF_E_NO_BLOCK)) 386 { 387 __libdw_seterrno (error); 388 return -1; 389 } 390 391 /* Must have the form data4 or data8 which act as an offset. */ 392 Dwarf_Word offset; 393 if (unlikely (INTUSE(dwarf_formudata) (attr, &offset) != 0)) 394 return -1; 395 396 const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc]; 397 if (unlikely (d == NULL)) 398 { 399 __libdw_seterrno (DWARF_E_NO_LOCLIST); 400 return -1; 401 } 402 403 Dwarf_Addr base = (Dwarf_Addr) -1; 404 unsigned char *readp = d->d_buf + offset; 405 size_t got = 0; 406 while (got < maxlocs) 407 { 408 if ((unsigned char *) d->d_buf + d->d_size - readp 409 < attr->cu->address_size * 2) 410 { 411 invalid: 412 __libdw_seterrno (DWARF_E_INVALID_DWARF); 413 return -1; 414 } 415 416 Dwarf_Addr begin; 417 Dwarf_Addr end; 418 if (attr->cu->address_size == 8) 419 { 420 begin = read_8ubyte_unaligned_inc (attr->cu->dbg, readp); 421 end = read_8ubyte_unaligned_inc (attr->cu->dbg, readp); 422 423 if (begin == (Elf64_Addr) -1l) /* Base address entry. */ 424 { 425 base = end; 426 if (unlikely (base == (Dwarf_Addr) -1)) 427 goto invalid; 428 continue; 429 } 430 } 431 else 432 { 433 begin = read_4ubyte_unaligned_inc (attr->cu->dbg, readp); 434 end = read_4ubyte_unaligned_inc (attr->cu->dbg, readp); 435 436 if (begin == (Elf32_Addr) -1) /* Base address entry. */ 437 { 438 base = end; 439 continue; 440 } 441 } 442 443 if (begin == 0 && end == 0) /* End of list entry. */ 444 break; 445 446 if ((unsigned char *) d->d_buf + d->d_size - readp < 2) 447 goto invalid; 448 449 /* We have a location expression. */ 450 block.length = read_2ubyte_unaligned_inc (attr->cu->dbg, readp); 451 block.data = readp; 452 if ((unsigned char *) d->d_buf + d->d_size - readp 453 < (ptrdiff_t) block.length) 454 goto invalid; 455 readp += block.length; 456 457 if (base == (Dwarf_Addr) -1) 458 { 459 /* Fetch the CU's base address. */ 460 Dwarf_Die cudie = CUDIE (attr->cu); 461 462 /* Find the base address of the compilation unit. It will 463 normally be specified by DW_AT_low_pc. In DWARF-3 draft 4, 464 the base address could be overridden by DW_AT_entry_pc. It's 465 been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc 466 for compilation units with discontinuous ranges. */ 467 Dwarf_Attribute attr_mem; 468 if (unlikely (INTUSE(dwarf_lowpc) (&cudie, &base) != 0) 469 && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie, 470 DW_AT_entry_pc, 471 &attr_mem), 472 &base) != 0) 473 { 474 if (INTUSE(dwarf_errno) () != 0) 475 return -1; 476 477 /* The compiler provided no base address when it should 478 have. Buggy GCC does this when it used absolute 479 addresses in the location list and no DW_AT_ranges. */ 480 base = 0; 481 } 482 } 483 484 if (address >= base + begin && address < base + end) 485 { 486 /* This one matches the address. */ 487 if (llbufs != NULL 488 && unlikely (getlocation (attr->cu, &block, 489 &llbufs[got], &listlens[got]) != 0)) 490 return -1; 491 ++got; 492 } 493 } 494 495 return got; 496 } 497