1da0c48c4Sopenharmony_ci/* Return location expression list. 2da0c48c4Sopenharmony_ci Copyright (C) 2000-2010, 2013-2015, 2017, 2018 Red Hat, Inc. 3da0c48c4Sopenharmony_ci This file is part of elfutils. 4da0c48c4Sopenharmony_ci 5da0c48c4Sopenharmony_ci This file is free software; you can redistribute it and/or modify 6da0c48c4Sopenharmony_ci it under the terms of either 7da0c48c4Sopenharmony_ci 8da0c48c4Sopenharmony_ci * the GNU Lesser General Public License as published by the Free 9da0c48c4Sopenharmony_ci Software Foundation; either version 3 of the License, or (at 10da0c48c4Sopenharmony_ci your option) any later version 11da0c48c4Sopenharmony_ci 12da0c48c4Sopenharmony_ci or 13da0c48c4Sopenharmony_ci 14da0c48c4Sopenharmony_ci * the GNU General Public License as published by the Free 15da0c48c4Sopenharmony_ci Software Foundation; either version 2 of the License, or (at 16da0c48c4Sopenharmony_ci your option) any later version 17da0c48c4Sopenharmony_ci 18da0c48c4Sopenharmony_ci or both in parallel, as here. 19da0c48c4Sopenharmony_ci 20da0c48c4Sopenharmony_ci elfutils is distributed in the hope that it will be useful, but 21da0c48c4Sopenharmony_ci WITHOUT ANY WARRANTY; without even the implied warranty of 22da0c48c4Sopenharmony_ci MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 23da0c48c4Sopenharmony_ci General Public License for more details. 24da0c48c4Sopenharmony_ci 25da0c48c4Sopenharmony_ci You should have received copies of the GNU General Public License and 26da0c48c4Sopenharmony_ci the GNU Lesser General Public License along with this program. If 27da0c48c4Sopenharmony_ci not, see <http://www.gnu.org/licenses/>. */ 28da0c48c4Sopenharmony_ci 29da0c48c4Sopenharmony_ci#ifdef HAVE_CONFIG_H 30da0c48c4Sopenharmony_ci# include <config.h> 31da0c48c4Sopenharmony_ci#endif 32da0c48c4Sopenharmony_ci 33da0c48c4Sopenharmony_ci#include <dwarf.h> 34da0c48c4Sopenharmony_ci#include <search.h> 35da0c48c4Sopenharmony_ci#include <stdlib.h> 36da0c48c4Sopenharmony_ci#include <assert.h> 37da0c48c4Sopenharmony_ci 38da0c48c4Sopenharmony_ci#include <libdwP.h> 39da0c48c4Sopenharmony_ci 40da0c48c4Sopenharmony_ci 41da0c48c4Sopenharmony_cistatic bool 42da0c48c4Sopenharmony_ciattr_ok (Dwarf_Attribute *attr) 43da0c48c4Sopenharmony_ci{ 44da0c48c4Sopenharmony_ci if (attr == NULL) 45da0c48c4Sopenharmony_ci return false; 46da0c48c4Sopenharmony_ci 47da0c48c4Sopenharmony_ci /* If it is an exprloc, it is obviously OK. */ 48da0c48c4Sopenharmony_ci if (dwarf_whatform (attr) == DW_FORM_exprloc) 49da0c48c4Sopenharmony_ci return true; 50da0c48c4Sopenharmony_ci 51da0c48c4Sopenharmony_ci if (attr->cu->version >= 4) 52da0c48c4Sopenharmony_ci { 53da0c48c4Sopenharmony_ci /* Must be an exprloc (or constant), just not any block form. */ 54da0c48c4Sopenharmony_ci switch (dwarf_whatform (attr)) 55da0c48c4Sopenharmony_ci { 56da0c48c4Sopenharmony_ci case DW_FORM_block: 57da0c48c4Sopenharmony_ci case DW_FORM_block1: 58da0c48c4Sopenharmony_ci case DW_FORM_block2: 59da0c48c4Sopenharmony_ci case DW_FORM_block4: 60da0c48c4Sopenharmony_ci __libdw_seterrno (DWARF_E_NO_LOC_VALUE); 61da0c48c4Sopenharmony_ci return false; 62da0c48c4Sopenharmony_ci default: 63da0c48c4Sopenharmony_ci break; 64da0c48c4Sopenharmony_ci } 65da0c48c4Sopenharmony_ci } 66da0c48c4Sopenharmony_ci 67da0c48c4Sopenharmony_ci /* Otherwise must be one of the attributes listed below. Older 68da0c48c4Sopenharmony_ci DWARF versions might have encoded the exprloc as block, and we 69da0c48c4Sopenharmony_ci cannot easily distinguish attributes in the loclist class because 70da0c48c4Sopenharmony_ci the same forms are used for different classes. */ 71da0c48c4Sopenharmony_ci switch (attr->code) 72da0c48c4Sopenharmony_ci { 73da0c48c4Sopenharmony_ci case DW_AT_location: 74da0c48c4Sopenharmony_ci case DW_AT_byte_size: 75da0c48c4Sopenharmony_ci case DW_AT_bit_offset: 76da0c48c4Sopenharmony_ci case DW_AT_bit_size: 77da0c48c4Sopenharmony_ci case DW_AT_lower_bound: 78da0c48c4Sopenharmony_ci case DW_AT_bit_stride: 79da0c48c4Sopenharmony_ci case DW_AT_upper_bound: 80da0c48c4Sopenharmony_ci case DW_AT_count: 81da0c48c4Sopenharmony_ci case DW_AT_allocated: 82da0c48c4Sopenharmony_ci case DW_AT_associated: 83da0c48c4Sopenharmony_ci case DW_AT_data_location: 84da0c48c4Sopenharmony_ci case DW_AT_byte_stride: 85da0c48c4Sopenharmony_ci case DW_AT_rank: 86da0c48c4Sopenharmony_ci case DW_AT_call_value: 87da0c48c4Sopenharmony_ci case DW_AT_call_target: 88da0c48c4Sopenharmony_ci case DW_AT_call_target_clobbered: 89da0c48c4Sopenharmony_ci case DW_AT_call_data_location: 90da0c48c4Sopenharmony_ci case DW_AT_call_data_value: 91da0c48c4Sopenharmony_ci case DW_AT_data_member_location: 92da0c48c4Sopenharmony_ci case DW_AT_vtable_elem_location: 93da0c48c4Sopenharmony_ci case DW_AT_string_length: 94da0c48c4Sopenharmony_ci case DW_AT_use_location: 95da0c48c4Sopenharmony_ci case DW_AT_frame_base: 96da0c48c4Sopenharmony_ci case DW_AT_return_addr: 97da0c48c4Sopenharmony_ci case DW_AT_static_link: 98da0c48c4Sopenharmony_ci case DW_AT_segment: 99da0c48c4Sopenharmony_ci case DW_AT_GNU_call_site_value: 100da0c48c4Sopenharmony_ci case DW_AT_GNU_call_site_data_value: 101da0c48c4Sopenharmony_ci case DW_AT_GNU_call_site_target: 102da0c48c4Sopenharmony_ci case DW_AT_GNU_call_site_target_clobbered: 103da0c48c4Sopenharmony_ci break; 104da0c48c4Sopenharmony_ci 105da0c48c4Sopenharmony_ci default: 106da0c48c4Sopenharmony_ci __libdw_seterrno (DWARF_E_NO_LOC_VALUE); 107da0c48c4Sopenharmony_ci return false; 108da0c48c4Sopenharmony_ci } 109da0c48c4Sopenharmony_ci 110da0c48c4Sopenharmony_ci return true; 111da0c48c4Sopenharmony_ci} 112da0c48c4Sopenharmony_ci 113da0c48c4Sopenharmony_ci 114da0c48c4Sopenharmony_cistruct loclist 115da0c48c4Sopenharmony_ci{ 116da0c48c4Sopenharmony_ci uint8_t atom; 117da0c48c4Sopenharmony_ci Dwarf_Word number; 118da0c48c4Sopenharmony_ci Dwarf_Word number2; 119da0c48c4Sopenharmony_ci Dwarf_Word offset; 120da0c48c4Sopenharmony_ci struct loclist *next; 121da0c48c4Sopenharmony_ci}; 122da0c48c4Sopenharmony_ci 123da0c48c4Sopenharmony_ci 124da0c48c4Sopenharmony_cistatic int 125da0c48c4Sopenharmony_ciloc_compare (const void *p1, const void *p2) 126da0c48c4Sopenharmony_ci{ 127da0c48c4Sopenharmony_ci const struct loc_s *l1 = (const struct loc_s *) p1; 128da0c48c4Sopenharmony_ci const struct loc_s *l2 = (const struct loc_s *) p2; 129da0c48c4Sopenharmony_ci 130da0c48c4Sopenharmony_ci if ((uintptr_t) l1->addr < (uintptr_t) l2->addr) 131da0c48c4Sopenharmony_ci return -1; 132da0c48c4Sopenharmony_ci if ((uintptr_t) l1->addr > (uintptr_t) l2->addr) 133da0c48c4Sopenharmony_ci return 1; 134da0c48c4Sopenharmony_ci 135da0c48c4Sopenharmony_ci return 0; 136da0c48c4Sopenharmony_ci} 137da0c48c4Sopenharmony_ci 138da0c48c4Sopenharmony_ci/* For each DW_OP_implicit_value, we store a special entry in the cache. 139da0c48c4Sopenharmony_ci This points us directly to the block data for later fetching. 140da0c48c4Sopenharmony_ci Returns zero on success, -1 on bad DWARF or 1 if tsearch failed. */ 141da0c48c4Sopenharmony_cistatic int 142da0c48c4Sopenharmony_cistore_implicit_value (Dwarf *dbg, void **cache, Dwarf_Op *op) 143da0c48c4Sopenharmony_ci{ 144da0c48c4Sopenharmony_ci if (dbg == NULL) 145da0c48c4Sopenharmony_ci return -1; 146da0c48c4Sopenharmony_ci struct loc_block_s *block = libdw_alloc (dbg, struct loc_block_s, 147da0c48c4Sopenharmony_ci sizeof (struct loc_block_s), 1); 148da0c48c4Sopenharmony_ci const unsigned char *data = (const unsigned char *) (uintptr_t) op->number2; 149da0c48c4Sopenharmony_ci /* Skip the block length. */ 150da0c48c4Sopenharmony_ci Dwarf_Word length; 151da0c48c4Sopenharmony_ci get_uleb128_unchecked (length, data); 152da0c48c4Sopenharmony_ci if (length != op->number) 153da0c48c4Sopenharmony_ci return -1; 154da0c48c4Sopenharmony_ci block->addr = op; 155da0c48c4Sopenharmony_ci block->data = (unsigned char *) data; 156da0c48c4Sopenharmony_ci block->length = op->number; 157da0c48c4Sopenharmony_ci if (unlikely (tsearch (block, cache, loc_compare) == NULL)) 158da0c48c4Sopenharmony_ci return 1; 159da0c48c4Sopenharmony_ci return 0; 160da0c48c4Sopenharmony_ci} 161da0c48c4Sopenharmony_ci 162da0c48c4Sopenharmony_ciint 163da0c48c4Sopenharmony_cidwarf_getlocation_implicit_value (Dwarf_Attribute *attr, const Dwarf_Op *op, 164da0c48c4Sopenharmony_ci Dwarf_Block *return_block) 165da0c48c4Sopenharmony_ci{ 166da0c48c4Sopenharmony_ci if (attr == NULL) 167da0c48c4Sopenharmony_ci return -1; 168da0c48c4Sopenharmony_ci 169da0c48c4Sopenharmony_ci struct loc_block_s fake = { .addr = (void *) op }; 170da0c48c4Sopenharmony_ci struct loc_block_s **found = tfind (&fake, &attr->cu->locs, loc_compare); 171da0c48c4Sopenharmony_ci if (unlikely (found == NULL)) 172da0c48c4Sopenharmony_ci { 173da0c48c4Sopenharmony_ci __libdw_seterrno (DWARF_E_NO_BLOCK); 174da0c48c4Sopenharmony_ci return -1; 175da0c48c4Sopenharmony_ci } 176da0c48c4Sopenharmony_ci 177da0c48c4Sopenharmony_ci return_block->length = (*found)->length; 178da0c48c4Sopenharmony_ci return_block->data = (*found)->data; 179da0c48c4Sopenharmony_ci return 0; 180da0c48c4Sopenharmony_ci} 181da0c48c4Sopenharmony_ci 182da0c48c4Sopenharmony_ci/* If the given attribute is DW_AT_data_member_location and it has constant 183da0c48c4Sopenharmony_ci form then create a fake location using DW_OP_plus_uconst and the offset 184da0c48c4Sopenharmony_ci value. On success returns zero and fills in llbuf (when not NULL) and 185da0c48c4Sopenharmony_ci sets listlen to 1. Returns 1 when this isn't a DW_AT_data_member_location 186da0c48c4Sopenharmony_ci offset. Returns -1 and sets dwarf_errno on failure (bad DWARF data). */ 187da0c48c4Sopenharmony_cistatic int 188da0c48c4Sopenharmony_ciis_constant_offset (Dwarf_Attribute *attr, 189da0c48c4Sopenharmony_ci Dwarf_Op **llbuf, size_t *listlen) 190da0c48c4Sopenharmony_ci{ 191da0c48c4Sopenharmony_ci if (attr->code != DW_AT_data_member_location) 192da0c48c4Sopenharmony_ci return 1; 193da0c48c4Sopenharmony_ci 194da0c48c4Sopenharmony_ci switch (attr->form) 195da0c48c4Sopenharmony_ci { 196da0c48c4Sopenharmony_ci /* Punt for any non-constant form. */ 197da0c48c4Sopenharmony_ci default: 198da0c48c4Sopenharmony_ci return 1; 199da0c48c4Sopenharmony_ci 200da0c48c4Sopenharmony_ci /* Note, we don't regard DW_FORM_data16 as a constant form, 201da0c48c4Sopenharmony_ci even though technically it is according to the standard. */ 202da0c48c4Sopenharmony_ci case DW_FORM_data1: 203da0c48c4Sopenharmony_ci case DW_FORM_data2: 204da0c48c4Sopenharmony_ci case DW_FORM_data4: 205da0c48c4Sopenharmony_ci case DW_FORM_data8: 206da0c48c4Sopenharmony_ci case DW_FORM_sdata: 207da0c48c4Sopenharmony_ci case DW_FORM_udata: 208da0c48c4Sopenharmony_ci case DW_FORM_implicit_const: 209da0c48c4Sopenharmony_ci break; 210da0c48c4Sopenharmony_ci } 211da0c48c4Sopenharmony_ci 212da0c48c4Sopenharmony_ci /* Check whether we already cached this location. */ 213da0c48c4Sopenharmony_ci struct loc_s fake = { .addr = attr->valp }; 214da0c48c4Sopenharmony_ci struct loc_s **found = tfind (&fake, &attr->cu->locs, loc_compare); 215da0c48c4Sopenharmony_ci 216da0c48c4Sopenharmony_ci if (found == NULL) 217da0c48c4Sopenharmony_ci { 218da0c48c4Sopenharmony_ci Dwarf_Word offset; 219da0c48c4Sopenharmony_ci if (INTUSE(dwarf_formudata) (attr, &offset) != 0) 220da0c48c4Sopenharmony_ci return -1; 221da0c48c4Sopenharmony_ci 222da0c48c4Sopenharmony_ci Dwarf_Op *result = libdw_alloc (attr->cu->dbg, 223da0c48c4Sopenharmony_ci Dwarf_Op, sizeof (Dwarf_Op), 1); 224da0c48c4Sopenharmony_ci 225da0c48c4Sopenharmony_ci result->atom = DW_OP_plus_uconst; 226da0c48c4Sopenharmony_ci result->number = offset; 227da0c48c4Sopenharmony_ci result->number2 = 0; 228da0c48c4Sopenharmony_ci result->offset = 0; 229da0c48c4Sopenharmony_ci 230da0c48c4Sopenharmony_ci /* Insert a record in the search tree so we can find it again later. */ 231da0c48c4Sopenharmony_ci struct loc_s *newp = libdw_alloc (attr->cu->dbg, 232da0c48c4Sopenharmony_ci struct loc_s, sizeof (struct loc_s), 233da0c48c4Sopenharmony_ci 1); 234da0c48c4Sopenharmony_ci newp->addr = attr->valp; 235da0c48c4Sopenharmony_ci newp->loc = result; 236da0c48c4Sopenharmony_ci newp->nloc = 1; 237da0c48c4Sopenharmony_ci 238da0c48c4Sopenharmony_ci found = tsearch (newp, &attr->cu->locs, loc_compare); 239da0c48c4Sopenharmony_ci } 240da0c48c4Sopenharmony_ci 241da0c48c4Sopenharmony_ci assert ((*found)->nloc == 1); 242da0c48c4Sopenharmony_ci 243da0c48c4Sopenharmony_ci if (llbuf != NULL) 244da0c48c4Sopenharmony_ci { 245da0c48c4Sopenharmony_ci *llbuf = (*found)->loc; 246da0c48c4Sopenharmony_ci *listlen = 1; 247da0c48c4Sopenharmony_ci } 248da0c48c4Sopenharmony_ci 249da0c48c4Sopenharmony_ci return 0; 250da0c48c4Sopenharmony_ci} 251da0c48c4Sopenharmony_ci 252da0c48c4Sopenharmony_ciint 253da0c48c4Sopenharmony_ciinternal_function 254da0c48c4Sopenharmony_ci__libdw_intern_expression (Dwarf *dbg, bool other_byte_order, 255da0c48c4Sopenharmony_ci unsigned int address_size, unsigned int ref_size, 256da0c48c4Sopenharmony_ci void **cache, const Dwarf_Block *block, 257da0c48c4Sopenharmony_ci bool cfap, bool valuep, 258da0c48c4Sopenharmony_ci Dwarf_Op **llbuf, size_t *listlen, int sec_index) 259da0c48c4Sopenharmony_ci{ 260da0c48c4Sopenharmony_ci /* Empty location expressions don't have any ops to intern. */ 261da0c48c4Sopenharmony_ci if (block->length == 0) 262da0c48c4Sopenharmony_ci { 263da0c48c4Sopenharmony_ci *listlen = 0; 264da0c48c4Sopenharmony_ci return 0; 265da0c48c4Sopenharmony_ci } 266da0c48c4Sopenharmony_ci 267da0c48c4Sopenharmony_ci /* Check whether we already looked at this list. */ 268da0c48c4Sopenharmony_ci struct loc_s fake = { .addr = block->data }; 269da0c48c4Sopenharmony_ci struct loc_s **found = tfind (&fake, cache, loc_compare); 270da0c48c4Sopenharmony_ci if (found != NULL) 271da0c48c4Sopenharmony_ci { 272da0c48c4Sopenharmony_ci /* We already saw it. */ 273da0c48c4Sopenharmony_ci *llbuf = (*found)->loc; 274da0c48c4Sopenharmony_ci *listlen = (*found)->nloc; 275da0c48c4Sopenharmony_ci 276da0c48c4Sopenharmony_ci if (valuep) 277da0c48c4Sopenharmony_ci { 278da0c48c4Sopenharmony_ci assert (*listlen > 1); 279da0c48c4Sopenharmony_ci assert ((*llbuf)[*listlen - 1].atom == DW_OP_stack_value); 280da0c48c4Sopenharmony_ci } 281da0c48c4Sopenharmony_ci 282da0c48c4Sopenharmony_ci return 0; 283da0c48c4Sopenharmony_ci } 284da0c48c4Sopenharmony_ci 285da0c48c4Sopenharmony_ci const unsigned char *data = block->data; 286da0c48c4Sopenharmony_ci const unsigned char *const end_data = data + block->length; 287da0c48c4Sopenharmony_ci 288da0c48c4Sopenharmony_ci const struct { bool other_byte_order; } bo = { other_byte_order }; 289da0c48c4Sopenharmony_ci 290da0c48c4Sopenharmony_ci struct loclist *loclist = NULL; 291da0c48c4Sopenharmony_ci unsigned int n = 0; 292da0c48c4Sopenharmony_ci 293da0c48c4Sopenharmony_ci /* Stack allocate at most this many locs. */ 294da0c48c4Sopenharmony_ci#define MAX_STACK_LOCS 256 295da0c48c4Sopenharmony_ci struct loclist stack_locs[MAX_STACK_LOCS]; 296da0c48c4Sopenharmony_ci#define NEW_LOC() ({ struct loclist *ll; \ 297da0c48c4Sopenharmony_ci ll = (likely (n < MAX_STACK_LOCS) \ 298da0c48c4Sopenharmony_ci ? &stack_locs[n] \ 299da0c48c4Sopenharmony_ci : malloc (sizeof (struct loclist))); \ 300da0c48c4Sopenharmony_ci if (unlikely (ll == NULL)) \ 301da0c48c4Sopenharmony_ci goto nomem; \ 302da0c48c4Sopenharmony_ci n++; \ 303da0c48c4Sopenharmony_ci ll->next = loclist; \ 304da0c48c4Sopenharmony_ci loclist = ll; \ 305da0c48c4Sopenharmony_ci ll; }) 306da0c48c4Sopenharmony_ci 307da0c48c4Sopenharmony_ci if (cfap) 308da0c48c4Sopenharmony_ci { 309da0c48c4Sopenharmony_ci /* Synthesize the operation to push the CFA before the expression. */ 310da0c48c4Sopenharmony_ci struct loclist *newloc = NEW_LOC (); 311da0c48c4Sopenharmony_ci newloc->atom = DW_OP_call_frame_cfa; 312da0c48c4Sopenharmony_ci newloc->number = 0; 313da0c48c4Sopenharmony_ci newloc->number2 = 0; 314da0c48c4Sopenharmony_ci newloc->offset = -1; 315da0c48c4Sopenharmony_ci } 316da0c48c4Sopenharmony_ci 317da0c48c4Sopenharmony_ci /* Decode the opcodes. It is possible in some situations to have a 318da0c48c4Sopenharmony_ci block of size zero. */ 319da0c48c4Sopenharmony_ci while (data < end_data) 320da0c48c4Sopenharmony_ci { 321da0c48c4Sopenharmony_ci struct loclist *newloc; 322da0c48c4Sopenharmony_ci newloc = NEW_LOC (); 323da0c48c4Sopenharmony_ci newloc->number = 0; 324da0c48c4Sopenharmony_ci newloc->number2 = 0; 325da0c48c4Sopenharmony_ci newloc->offset = data - block->data; 326da0c48c4Sopenharmony_ci 327da0c48c4Sopenharmony_ci switch ((newloc->atom = *data++)) 328da0c48c4Sopenharmony_ci { 329da0c48c4Sopenharmony_ci case DW_OP_addr: 330da0c48c4Sopenharmony_ci /* Address, depends on address size of CU. */ 331da0c48c4Sopenharmony_ci if (dbg == NULL) 332da0c48c4Sopenharmony_ci { 333da0c48c4Sopenharmony_ci // XXX relocation? 334da0c48c4Sopenharmony_ci if (address_size == 4) 335da0c48c4Sopenharmony_ci { 336da0c48c4Sopenharmony_ci if (unlikely (data + 4 > end_data)) 337da0c48c4Sopenharmony_ci goto invalid; 338da0c48c4Sopenharmony_ci else 339da0c48c4Sopenharmony_ci newloc->number = read_4ubyte_unaligned_inc (&bo, data); 340da0c48c4Sopenharmony_ci } 341da0c48c4Sopenharmony_ci else 342da0c48c4Sopenharmony_ci { 343da0c48c4Sopenharmony_ci if (unlikely (data + 8 > end_data)) 344da0c48c4Sopenharmony_ci goto invalid; 345da0c48c4Sopenharmony_ci else 346da0c48c4Sopenharmony_ci newloc->number = read_8ubyte_unaligned_inc (&bo, data); 347da0c48c4Sopenharmony_ci } 348da0c48c4Sopenharmony_ci } 349da0c48c4Sopenharmony_ci else if (__libdw_read_address_inc (dbg, sec_index, &data, 350da0c48c4Sopenharmony_ci address_size, &newloc->number)) 351da0c48c4Sopenharmony_ci goto invalid; 352da0c48c4Sopenharmony_ci break; 353da0c48c4Sopenharmony_ci 354da0c48c4Sopenharmony_ci case DW_OP_call_ref: 355da0c48c4Sopenharmony_ci case DW_OP_GNU_variable_value: 356da0c48c4Sopenharmony_ci /* DW_FORM_ref_addr, depends on offset size of CU. */ 357da0c48c4Sopenharmony_ci if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data, 358da0c48c4Sopenharmony_ci ref_size, 359da0c48c4Sopenharmony_ci &newloc->number, 360da0c48c4Sopenharmony_ci IDX_debug_info, 0)) 361da0c48c4Sopenharmony_ci goto invalid; 362da0c48c4Sopenharmony_ci break; 363da0c48c4Sopenharmony_ci 364da0c48c4Sopenharmony_ci case DW_OP_deref: 365da0c48c4Sopenharmony_ci case DW_OP_dup: 366da0c48c4Sopenharmony_ci case DW_OP_drop: 367da0c48c4Sopenharmony_ci case DW_OP_over: 368da0c48c4Sopenharmony_ci case DW_OP_swap: 369da0c48c4Sopenharmony_ci case DW_OP_rot: 370da0c48c4Sopenharmony_ci case DW_OP_xderef: 371da0c48c4Sopenharmony_ci case DW_OP_abs: 372da0c48c4Sopenharmony_ci case DW_OP_and: 373da0c48c4Sopenharmony_ci case DW_OP_div: 374da0c48c4Sopenharmony_ci case DW_OP_minus: 375da0c48c4Sopenharmony_ci case DW_OP_mod: 376da0c48c4Sopenharmony_ci case DW_OP_mul: 377da0c48c4Sopenharmony_ci case DW_OP_neg: 378da0c48c4Sopenharmony_ci case DW_OP_not: 379da0c48c4Sopenharmony_ci case DW_OP_or: 380da0c48c4Sopenharmony_ci case DW_OP_plus: 381da0c48c4Sopenharmony_ci case DW_OP_shl: 382da0c48c4Sopenharmony_ci case DW_OP_shr: 383da0c48c4Sopenharmony_ci case DW_OP_shra: 384da0c48c4Sopenharmony_ci case DW_OP_xor: 385da0c48c4Sopenharmony_ci case DW_OP_eq: 386da0c48c4Sopenharmony_ci case DW_OP_ge: 387da0c48c4Sopenharmony_ci case DW_OP_gt: 388da0c48c4Sopenharmony_ci case DW_OP_le: 389da0c48c4Sopenharmony_ci case DW_OP_lt: 390da0c48c4Sopenharmony_ci case DW_OP_ne: 391da0c48c4Sopenharmony_ci case DW_OP_lit0 ... DW_OP_lit31: 392da0c48c4Sopenharmony_ci case DW_OP_reg0 ... DW_OP_reg31: 393da0c48c4Sopenharmony_ci case DW_OP_nop: 394da0c48c4Sopenharmony_ci case DW_OP_push_object_address: 395da0c48c4Sopenharmony_ci case DW_OP_call_frame_cfa: 396da0c48c4Sopenharmony_ci case DW_OP_form_tls_address: 397da0c48c4Sopenharmony_ci case DW_OP_GNU_push_tls_address: 398da0c48c4Sopenharmony_ci case DW_OP_stack_value: 399da0c48c4Sopenharmony_ci /* No operand. */ 400da0c48c4Sopenharmony_ci break; 401da0c48c4Sopenharmony_ci 402da0c48c4Sopenharmony_ci case DW_OP_const1u: 403da0c48c4Sopenharmony_ci case DW_OP_pick: 404da0c48c4Sopenharmony_ci case DW_OP_deref_size: 405da0c48c4Sopenharmony_ci case DW_OP_xderef_size: 406da0c48c4Sopenharmony_ci if (unlikely (data >= end_data)) 407da0c48c4Sopenharmony_ci { 408da0c48c4Sopenharmony_ci invalid: 409da0c48c4Sopenharmony_ci __libdw_seterrno (DWARF_E_INVALID_DWARF); 410da0c48c4Sopenharmony_ci returnmem: 411da0c48c4Sopenharmony_ci /* Free any dynamically allocated loclists, if any. */ 412da0c48c4Sopenharmony_ci while (n > MAX_STACK_LOCS) 413da0c48c4Sopenharmony_ci { 414da0c48c4Sopenharmony_ci struct loclist *loc = loclist; 415da0c48c4Sopenharmony_ci loclist = loc->next; 416da0c48c4Sopenharmony_ci free (loc); 417da0c48c4Sopenharmony_ci n--; 418da0c48c4Sopenharmony_ci } 419da0c48c4Sopenharmony_ci return -1; 420da0c48c4Sopenharmony_ci } 421da0c48c4Sopenharmony_ci 422da0c48c4Sopenharmony_ci newloc->number = *data++; 423da0c48c4Sopenharmony_ci break; 424da0c48c4Sopenharmony_ci 425da0c48c4Sopenharmony_ci case DW_OP_const1s: 426da0c48c4Sopenharmony_ci if (unlikely (data >= end_data)) 427da0c48c4Sopenharmony_ci goto invalid; 428da0c48c4Sopenharmony_ci 429da0c48c4Sopenharmony_ci newloc->number = *((int8_t *) data); 430da0c48c4Sopenharmony_ci ++data; 431da0c48c4Sopenharmony_ci break; 432da0c48c4Sopenharmony_ci 433da0c48c4Sopenharmony_ci case DW_OP_const2u: 434da0c48c4Sopenharmony_ci if (unlikely (data + 2 > end_data)) 435da0c48c4Sopenharmony_ci goto invalid; 436da0c48c4Sopenharmony_ci 437da0c48c4Sopenharmony_ci newloc->number = read_2ubyte_unaligned_inc (&bo, data); 438da0c48c4Sopenharmony_ci break; 439da0c48c4Sopenharmony_ci 440da0c48c4Sopenharmony_ci case DW_OP_const2s: 441da0c48c4Sopenharmony_ci case DW_OP_skip: 442da0c48c4Sopenharmony_ci case DW_OP_bra: 443da0c48c4Sopenharmony_ci case DW_OP_call2: 444da0c48c4Sopenharmony_ci if (unlikely (data + 2 > end_data)) 445da0c48c4Sopenharmony_ci goto invalid; 446da0c48c4Sopenharmony_ci 447da0c48c4Sopenharmony_ci newloc->number = read_2sbyte_unaligned_inc (&bo, data); 448da0c48c4Sopenharmony_ci break; 449da0c48c4Sopenharmony_ci 450da0c48c4Sopenharmony_ci case DW_OP_const4u: 451da0c48c4Sopenharmony_ci if (unlikely (data + 4 > end_data)) 452da0c48c4Sopenharmony_ci goto invalid; 453da0c48c4Sopenharmony_ci 454da0c48c4Sopenharmony_ci newloc->number = read_4ubyte_unaligned_inc (&bo, data); 455da0c48c4Sopenharmony_ci break; 456da0c48c4Sopenharmony_ci 457da0c48c4Sopenharmony_ci case DW_OP_const4s: 458da0c48c4Sopenharmony_ci case DW_OP_call4: 459da0c48c4Sopenharmony_ci case DW_OP_GNU_parameter_ref: 460da0c48c4Sopenharmony_ci if (unlikely (data + 4 > end_data)) 461da0c48c4Sopenharmony_ci goto invalid; 462da0c48c4Sopenharmony_ci 463da0c48c4Sopenharmony_ci newloc->number = read_4sbyte_unaligned_inc (&bo, data); 464da0c48c4Sopenharmony_ci break; 465da0c48c4Sopenharmony_ci 466da0c48c4Sopenharmony_ci case DW_OP_const8u: 467da0c48c4Sopenharmony_ci if (unlikely (data + 8 > end_data)) 468da0c48c4Sopenharmony_ci goto invalid; 469da0c48c4Sopenharmony_ci 470da0c48c4Sopenharmony_ci newloc->number = read_8ubyte_unaligned_inc (&bo, data); 471da0c48c4Sopenharmony_ci break; 472da0c48c4Sopenharmony_ci 473da0c48c4Sopenharmony_ci case DW_OP_const8s: 474da0c48c4Sopenharmony_ci if (unlikely (data + 8 > end_data)) 475da0c48c4Sopenharmony_ci goto invalid; 476da0c48c4Sopenharmony_ci 477da0c48c4Sopenharmony_ci newloc->number = read_8sbyte_unaligned_inc (&bo, data); 478da0c48c4Sopenharmony_ci break; 479da0c48c4Sopenharmony_ci 480da0c48c4Sopenharmony_ci case DW_OP_constu: 481da0c48c4Sopenharmony_ci case DW_OP_plus_uconst: 482da0c48c4Sopenharmony_ci case DW_OP_regx: 483da0c48c4Sopenharmony_ci case DW_OP_piece: 484da0c48c4Sopenharmony_ci case DW_OP_convert: 485da0c48c4Sopenharmony_ci case DW_OP_GNU_convert: 486da0c48c4Sopenharmony_ci case DW_OP_reinterpret: 487da0c48c4Sopenharmony_ci case DW_OP_GNU_reinterpret: 488da0c48c4Sopenharmony_ci case DW_OP_addrx: 489da0c48c4Sopenharmony_ci case DW_OP_GNU_addr_index: 490da0c48c4Sopenharmony_ci case DW_OP_constx: 491da0c48c4Sopenharmony_ci case DW_OP_GNU_const_index: 492da0c48c4Sopenharmony_ci get_uleb128 (newloc->number, data, end_data); 493da0c48c4Sopenharmony_ci break; 494da0c48c4Sopenharmony_ci 495da0c48c4Sopenharmony_ci case DW_OP_consts: 496da0c48c4Sopenharmony_ci case DW_OP_breg0 ... DW_OP_breg31: 497da0c48c4Sopenharmony_ci case DW_OP_fbreg: 498da0c48c4Sopenharmony_ci get_sleb128 (newloc->number, data, end_data); 499da0c48c4Sopenharmony_ci break; 500da0c48c4Sopenharmony_ci 501da0c48c4Sopenharmony_ci case DW_OP_bregx: 502da0c48c4Sopenharmony_ci get_uleb128 (newloc->number, data, end_data); 503da0c48c4Sopenharmony_ci if (unlikely (data >= end_data)) 504da0c48c4Sopenharmony_ci goto invalid; 505da0c48c4Sopenharmony_ci get_sleb128 (newloc->number2, data, end_data); 506da0c48c4Sopenharmony_ci break; 507da0c48c4Sopenharmony_ci 508da0c48c4Sopenharmony_ci case DW_OP_bit_piece: 509da0c48c4Sopenharmony_ci case DW_OP_regval_type: 510da0c48c4Sopenharmony_ci case DW_OP_GNU_regval_type: 511da0c48c4Sopenharmony_ci get_uleb128 (newloc->number, data, end_data); 512da0c48c4Sopenharmony_ci if (unlikely (data >= end_data)) 513da0c48c4Sopenharmony_ci goto invalid; 514da0c48c4Sopenharmony_ci get_uleb128 (newloc->number2, data, end_data); 515da0c48c4Sopenharmony_ci break; 516da0c48c4Sopenharmony_ci 517da0c48c4Sopenharmony_ci case DW_OP_implicit_value: 518da0c48c4Sopenharmony_ci case DW_OP_entry_value: 519da0c48c4Sopenharmony_ci case DW_OP_GNU_entry_value: 520da0c48c4Sopenharmony_ci /* This cannot be used in a CFI expression. */ 521da0c48c4Sopenharmony_ci if (unlikely (dbg == NULL)) 522da0c48c4Sopenharmony_ci goto invalid; 523da0c48c4Sopenharmony_ci 524da0c48c4Sopenharmony_ci /* start of block inc. len. */ 525da0c48c4Sopenharmony_ci newloc->number2 = (Dwarf_Word) (uintptr_t) data; 526da0c48c4Sopenharmony_ci get_uleb128 (newloc->number, data, end_data); /* Block length. */ 527da0c48c4Sopenharmony_ci if (unlikely ((Dwarf_Word) (end_data - data) < newloc->number)) 528da0c48c4Sopenharmony_ci goto invalid; 529da0c48c4Sopenharmony_ci data += newloc->number; /* Skip the block. */ 530da0c48c4Sopenharmony_ci break; 531da0c48c4Sopenharmony_ci 532da0c48c4Sopenharmony_ci case DW_OP_implicit_pointer: 533da0c48c4Sopenharmony_ci case DW_OP_GNU_implicit_pointer: 534da0c48c4Sopenharmony_ci /* DW_FORM_ref_addr, depends on offset size of CU. */ 535da0c48c4Sopenharmony_ci if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data, 536da0c48c4Sopenharmony_ci ref_size, 537da0c48c4Sopenharmony_ci &newloc->number, 538da0c48c4Sopenharmony_ci IDX_debug_info, 0)) 539da0c48c4Sopenharmony_ci goto invalid; 540da0c48c4Sopenharmony_ci if (unlikely (data >= end_data)) 541da0c48c4Sopenharmony_ci goto invalid; 542da0c48c4Sopenharmony_ci get_uleb128 (newloc->number2, data, end_data); /* Byte offset. */ 543da0c48c4Sopenharmony_ci break; 544da0c48c4Sopenharmony_ci 545da0c48c4Sopenharmony_ci case DW_OP_deref_type: 546da0c48c4Sopenharmony_ci case DW_OP_GNU_deref_type: 547da0c48c4Sopenharmony_ci case DW_OP_xderef_type: 548da0c48c4Sopenharmony_ci if (unlikely (data + 1 >= end_data)) 549da0c48c4Sopenharmony_ci goto invalid; 550da0c48c4Sopenharmony_ci newloc->number = *data++; 551da0c48c4Sopenharmony_ci get_uleb128 (newloc->number2, data, end_data); 552da0c48c4Sopenharmony_ci break; 553da0c48c4Sopenharmony_ci 554da0c48c4Sopenharmony_ci case DW_OP_const_type: 555da0c48c4Sopenharmony_ci case DW_OP_GNU_const_type: 556da0c48c4Sopenharmony_ci { 557da0c48c4Sopenharmony_ci size_t size; 558da0c48c4Sopenharmony_ci get_uleb128 (newloc->number, data, end_data); 559da0c48c4Sopenharmony_ci if (unlikely (data >= end_data)) 560da0c48c4Sopenharmony_ci goto invalid; 561da0c48c4Sopenharmony_ci 562da0c48c4Sopenharmony_ci /* start of block inc. len. */ 563da0c48c4Sopenharmony_ci newloc->number2 = (Dwarf_Word) (uintptr_t) data; 564da0c48c4Sopenharmony_ci size = *data++; 565da0c48c4Sopenharmony_ci if (unlikely ((Dwarf_Word) (end_data - data) < size)) 566da0c48c4Sopenharmony_ci goto invalid; 567da0c48c4Sopenharmony_ci data += size; /* Skip the block. */ 568da0c48c4Sopenharmony_ci } 569da0c48c4Sopenharmony_ci break; 570da0c48c4Sopenharmony_ci 571da0c48c4Sopenharmony_ci default: 572da0c48c4Sopenharmony_ci goto invalid; 573da0c48c4Sopenharmony_ci } 574da0c48c4Sopenharmony_ci } 575da0c48c4Sopenharmony_ci 576da0c48c4Sopenharmony_ci if (unlikely (n == 0)) 577da0c48c4Sopenharmony_ci { 578da0c48c4Sopenharmony_ci /* This is not allowed. 579da0c48c4Sopenharmony_ci It would mean an empty location expression, which we handled 580da0c48c4Sopenharmony_ci already as a special case above. */ 581da0c48c4Sopenharmony_ci goto invalid; 582da0c48c4Sopenharmony_ci } 583da0c48c4Sopenharmony_ci 584da0c48c4Sopenharmony_ci if (valuep) 585da0c48c4Sopenharmony_ci { 586da0c48c4Sopenharmony_ci struct loclist *newloc = NEW_LOC (); 587da0c48c4Sopenharmony_ci newloc->atom = DW_OP_stack_value; 588da0c48c4Sopenharmony_ci newloc->number = 0; 589da0c48c4Sopenharmony_ci newloc->number2 = 0; 590da0c48c4Sopenharmony_ci newloc->offset = data - block->data; 591da0c48c4Sopenharmony_ci } 592da0c48c4Sopenharmony_ci 593da0c48c4Sopenharmony_ci /* Allocate the array. */ 594da0c48c4Sopenharmony_ci Dwarf_Op *result; 595da0c48c4Sopenharmony_ci if (dbg != NULL) 596da0c48c4Sopenharmony_ci result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n); 597da0c48c4Sopenharmony_ci else 598da0c48c4Sopenharmony_ci { 599da0c48c4Sopenharmony_ci result = malloc (sizeof *result * n); 600da0c48c4Sopenharmony_ci if (result == NULL) 601da0c48c4Sopenharmony_ci { 602da0c48c4Sopenharmony_ci nomem: 603da0c48c4Sopenharmony_ci __libdw_seterrno (DWARF_E_NOMEM); 604da0c48c4Sopenharmony_ci goto returnmem; 605da0c48c4Sopenharmony_ci } 606da0c48c4Sopenharmony_ci } 607da0c48c4Sopenharmony_ci 608da0c48c4Sopenharmony_ci /* Store the result. */ 609da0c48c4Sopenharmony_ci *llbuf = result; 610da0c48c4Sopenharmony_ci *listlen = n; 611da0c48c4Sopenharmony_ci 612da0c48c4Sopenharmony_ci do 613da0c48c4Sopenharmony_ci { 614da0c48c4Sopenharmony_ci /* We populate the array from the back since the list is backwards. */ 615da0c48c4Sopenharmony_ci --n; 616da0c48c4Sopenharmony_ci result[n].atom = loclist->atom; 617da0c48c4Sopenharmony_ci result[n].number = loclist->number; 618da0c48c4Sopenharmony_ci result[n].number2 = loclist->number2; 619da0c48c4Sopenharmony_ci result[n].offset = loclist->offset; 620da0c48c4Sopenharmony_ci 621da0c48c4Sopenharmony_ci if (result[n].atom == DW_OP_implicit_value) 622da0c48c4Sopenharmony_ci { 623da0c48c4Sopenharmony_ci int store = store_implicit_value (dbg, cache, &result[n]); 624da0c48c4Sopenharmony_ci if (unlikely (store != 0)) 625da0c48c4Sopenharmony_ci { 626da0c48c4Sopenharmony_ci if (store < 0) 627da0c48c4Sopenharmony_ci goto invalid; 628da0c48c4Sopenharmony_ci else 629da0c48c4Sopenharmony_ci goto nomem; 630da0c48c4Sopenharmony_ci } 631da0c48c4Sopenharmony_ci } 632da0c48c4Sopenharmony_ci 633da0c48c4Sopenharmony_ci struct loclist *loc = loclist; 634da0c48c4Sopenharmony_ci loclist = loclist->next; 635da0c48c4Sopenharmony_ci if (unlikely (n + 1 > MAX_STACK_LOCS)) 636da0c48c4Sopenharmony_ci free (loc); 637da0c48c4Sopenharmony_ci } 638da0c48c4Sopenharmony_ci while (n > 0); 639da0c48c4Sopenharmony_ci 640da0c48c4Sopenharmony_ci /* Insert a record in the search tree so that we can find it again later. */ 641da0c48c4Sopenharmony_ci struct loc_s *newp; 642da0c48c4Sopenharmony_ci if (dbg != NULL) 643da0c48c4Sopenharmony_ci newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 1); 644da0c48c4Sopenharmony_ci else 645da0c48c4Sopenharmony_ci { 646da0c48c4Sopenharmony_ci newp = malloc (sizeof *newp); 647da0c48c4Sopenharmony_ci if (newp == NULL) 648da0c48c4Sopenharmony_ci { 649da0c48c4Sopenharmony_ci free (result); 650da0c48c4Sopenharmony_ci goto nomem; 651da0c48c4Sopenharmony_ci } 652da0c48c4Sopenharmony_ci } 653da0c48c4Sopenharmony_ci 654da0c48c4Sopenharmony_ci newp->addr = block->data; 655da0c48c4Sopenharmony_ci newp->loc = result; 656da0c48c4Sopenharmony_ci newp->nloc = *listlen; 657da0c48c4Sopenharmony_ci (void) tsearch (newp, cache, loc_compare); 658da0c48c4Sopenharmony_ci 659da0c48c4Sopenharmony_ci /* We did it. */ 660da0c48c4Sopenharmony_ci return 0; 661da0c48c4Sopenharmony_ci} 662da0c48c4Sopenharmony_ci 663da0c48c4Sopenharmony_cistatic int 664da0c48c4Sopenharmony_cigetlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, 665da0c48c4Sopenharmony_ci Dwarf_Op **llbuf, size_t *listlen, int sec_index) 666da0c48c4Sopenharmony_ci{ 667da0c48c4Sopenharmony_ci /* Empty location expressions don't have any ops to intern. 668da0c48c4Sopenharmony_ci Note that synthetic empty_cu doesn't have an associated DWARF dbg. */ 669da0c48c4Sopenharmony_ci if (block->length == 0) 670da0c48c4Sopenharmony_ci { 671da0c48c4Sopenharmony_ci *listlen = 0; 672da0c48c4Sopenharmony_ci return 0; 673da0c48c4Sopenharmony_ci } 674da0c48c4Sopenharmony_ci 675da0c48c4Sopenharmony_ci return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order, 676da0c48c4Sopenharmony_ci cu->address_size, (cu->version == 2 677da0c48c4Sopenharmony_ci ? cu->address_size 678da0c48c4Sopenharmony_ci : cu->offset_size), 679da0c48c4Sopenharmony_ci &cu->locs, block, 680da0c48c4Sopenharmony_ci false, false, 681da0c48c4Sopenharmony_ci llbuf, listlen, sec_index); 682da0c48c4Sopenharmony_ci} 683da0c48c4Sopenharmony_ci 684da0c48c4Sopenharmony_ciint 685da0c48c4Sopenharmony_cidwarf_getlocation (Dwarf_Attribute *attr, Dwarf_Op **llbuf, size_t *listlen) 686da0c48c4Sopenharmony_ci{ 687da0c48c4Sopenharmony_ci if (! attr_ok (attr)) 688da0c48c4Sopenharmony_ci return -1; 689da0c48c4Sopenharmony_ci 690da0c48c4Sopenharmony_ci int result = is_constant_offset (attr, llbuf, listlen); 691da0c48c4Sopenharmony_ci if (result != 1) 692da0c48c4Sopenharmony_ci return result; /* Either success 0, or -1 to indicate error. */ 693da0c48c4Sopenharmony_ci 694da0c48c4Sopenharmony_ci /* If it has a block form, it's a single location expression. 695da0c48c4Sopenharmony_ci Except for DW_FORM_data16, which is a 128bit constant. */ 696da0c48c4Sopenharmony_ci if (attr->form == DW_FORM_data16) 697da0c48c4Sopenharmony_ci { 698da0c48c4Sopenharmony_ci __libdw_seterrno (DWARF_E_NO_BLOCK); 699da0c48c4Sopenharmony_ci return -1; 700da0c48c4Sopenharmony_ci } 701da0c48c4Sopenharmony_ci Dwarf_Block block; 702da0c48c4Sopenharmony_ci if (INTUSE(dwarf_formblock) (attr, &block) != 0) 703da0c48c4Sopenharmony_ci return -1; 704da0c48c4Sopenharmony_ci 705da0c48c4Sopenharmony_ci return getlocation (attr->cu, &block, llbuf, listlen, cu_sec_idx (attr->cu)); 706da0c48c4Sopenharmony_ci} 707da0c48c4Sopenharmony_ci 708da0c48c4Sopenharmony_ciDwarf_Addr 709da0c48c4Sopenharmony_ci__libdw_cu_base_address (Dwarf_CU *cu) 710da0c48c4Sopenharmony_ci{ 711da0c48c4Sopenharmony_ci if (cu->base_address == (Dwarf_Addr) -1) 712da0c48c4Sopenharmony_ci { 713da0c48c4Sopenharmony_ci Dwarf_Addr base; 714da0c48c4Sopenharmony_ci 715da0c48c4Sopenharmony_ci /* Fetch the CU's base address. */ 716da0c48c4Sopenharmony_ci Dwarf_Die cudie = CUDIE (cu); 717da0c48c4Sopenharmony_ci 718da0c48c4Sopenharmony_ci /* Find the base address of the compilation unit. It will 719da0c48c4Sopenharmony_ci normally be specified by DW_AT_low_pc. In DWARF-3 draft 4, 720da0c48c4Sopenharmony_ci the base address could be overridden by DW_AT_entry_pc. It's 721da0c48c4Sopenharmony_ci been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc 722da0c48c4Sopenharmony_ci for compilation units with discontinuous ranges. */ 723da0c48c4Sopenharmony_ci Dwarf_Attribute attr_mem; 724da0c48c4Sopenharmony_ci if (INTUSE(dwarf_lowpc) (&cudie, &base) != 0 725da0c48c4Sopenharmony_ci && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie, 726da0c48c4Sopenharmony_ci DW_AT_entry_pc, 727da0c48c4Sopenharmony_ci &attr_mem), 728da0c48c4Sopenharmony_ci &base) != 0) 729da0c48c4Sopenharmony_ci { 730da0c48c4Sopenharmony_ci /* The compiler provided no base address when it should 731da0c48c4Sopenharmony_ci have. Buggy GCC does this when it used absolute 732da0c48c4Sopenharmony_ci addresses in the location list and no DW_AT_ranges. */ 733da0c48c4Sopenharmony_ci base = 0; 734da0c48c4Sopenharmony_ci } 735da0c48c4Sopenharmony_ci cu->base_address = base; 736da0c48c4Sopenharmony_ci } 737da0c48c4Sopenharmony_ci 738da0c48c4Sopenharmony_ci return cu->base_address; 739da0c48c4Sopenharmony_ci} 740da0c48c4Sopenharmony_ci 741da0c48c4Sopenharmony_cistatic int 742da0c48c4Sopenharmony_ciinitial_offset (Dwarf_Attribute *attr, ptrdiff_t *offset) 743da0c48c4Sopenharmony_ci{ 744da0c48c4Sopenharmony_ci size_t secidx = (attr->cu->version < 5 745da0c48c4Sopenharmony_ci ? IDX_debug_loc : IDX_debug_loclists); 746da0c48c4Sopenharmony_ci 747da0c48c4Sopenharmony_ci Dwarf_Word start_offset; 748da0c48c4Sopenharmony_ci if (attr->form == DW_FORM_loclistx) 749da0c48c4Sopenharmony_ci { 750da0c48c4Sopenharmony_ci Dwarf_Word idx; 751da0c48c4Sopenharmony_ci Dwarf_CU *cu = attr->cu; 752da0c48c4Sopenharmony_ci const unsigned char *datap = attr->valp; 753da0c48c4Sopenharmony_ci const unsigned char *endp = cu->endp; 754da0c48c4Sopenharmony_ci if (datap >= endp) 755da0c48c4Sopenharmony_ci { 756da0c48c4Sopenharmony_ci __libdw_seterrno (DWARF_E_INVALID_DWARF); 757da0c48c4Sopenharmony_ci return -1; 758da0c48c4Sopenharmony_ci } 759da0c48c4Sopenharmony_ci get_uleb128 (idx, datap, endp); 760da0c48c4Sopenharmony_ci 761da0c48c4Sopenharmony_ci Elf_Data *data = cu->dbg->sectiondata[secidx]; 762da0c48c4Sopenharmony_ci if (data == NULL && cu->unit_type == DW_UT_split_compile) 763da0c48c4Sopenharmony_ci { 764da0c48c4Sopenharmony_ci cu = __libdw_find_split_unit (cu); 765da0c48c4Sopenharmony_ci if (cu != NULL) 766da0c48c4Sopenharmony_ci data = cu->dbg->sectiondata[secidx]; 767da0c48c4Sopenharmony_ci } 768da0c48c4Sopenharmony_ci 769da0c48c4Sopenharmony_ci if (data == NULL) 770da0c48c4Sopenharmony_ci { 771da0c48c4Sopenharmony_ci __libdw_seterrno (secidx == IDX_debug_loc 772da0c48c4Sopenharmony_ci ? DWARF_E_NO_DEBUG_LOC 773da0c48c4Sopenharmony_ci : DWARF_E_NO_DEBUG_LOCLISTS); 774da0c48c4Sopenharmony_ci return -1; 775da0c48c4Sopenharmony_ci } 776da0c48c4Sopenharmony_ci 777da0c48c4Sopenharmony_ci Dwarf_Off loc_base_off = __libdw_cu_locs_base (cu); 778da0c48c4Sopenharmony_ci 779da0c48c4Sopenharmony_ci /* The section should at least contain room for one offset. */ 780da0c48c4Sopenharmony_ci size_t sec_size = cu->dbg->sectiondata[secidx]->d_size; 781da0c48c4Sopenharmony_ci size_t offset_size = cu->offset_size; 782da0c48c4Sopenharmony_ci if (offset_size > sec_size) 783da0c48c4Sopenharmony_ci { 784da0c48c4Sopenharmony_ci invalid_offset: 785da0c48c4Sopenharmony_ci __libdw_seterrno (DWARF_E_INVALID_OFFSET); 786da0c48c4Sopenharmony_ci return -1; 787da0c48c4Sopenharmony_ci } 788da0c48c4Sopenharmony_ci 789da0c48c4Sopenharmony_ci /* And the base offset should be at least inside the section. */ 790da0c48c4Sopenharmony_ci if (loc_base_off > (sec_size - offset_size)) 791da0c48c4Sopenharmony_ci goto invalid_offset; 792da0c48c4Sopenharmony_ci 793da0c48c4Sopenharmony_ci size_t max_idx = (sec_size - offset_size - loc_base_off) / offset_size; 794da0c48c4Sopenharmony_ci if (idx > max_idx) 795da0c48c4Sopenharmony_ci goto invalid_offset; 796da0c48c4Sopenharmony_ci 797da0c48c4Sopenharmony_ci datap = (cu->dbg->sectiondata[secidx]->d_buf 798da0c48c4Sopenharmony_ci + loc_base_off + (idx * offset_size)); 799da0c48c4Sopenharmony_ci if (offset_size == 4) 800da0c48c4Sopenharmony_ci start_offset = read_4ubyte_unaligned (cu->dbg, datap); 801da0c48c4Sopenharmony_ci else 802da0c48c4Sopenharmony_ci start_offset = read_8ubyte_unaligned (cu->dbg, datap); 803da0c48c4Sopenharmony_ci 804da0c48c4Sopenharmony_ci start_offset += loc_base_off; 805da0c48c4Sopenharmony_ci } 806da0c48c4Sopenharmony_ci else 807da0c48c4Sopenharmony_ci { 808da0c48c4Sopenharmony_ci if (__libdw_formptr (attr, secidx, 809da0c48c4Sopenharmony_ci (secidx == IDX_debug_loc 810da0c48c4Sopenharmony_ci ? DWARF_E_NO_DEBUG_LOC 811da0c48c4Sopenharmony_ci : DWARF_E_NO_DEBUG_LOCLISTS), 812da0c48c4Sopenharmony_ci NULL, &start_offset) == NULL) 813da0c48c4Sopenharmony_ci return -1; 814da0c48c4Sopenharmony_ci } 815da0c48c4Sopenharmony_ci 816da0c48c4Sopenharmony_ci *offset = start_offset; 817da0c48c4Sopenharmony_ci return 0; 818da0c48c4Sopenharmony_ci} 819da0c48c4Sopenharmony_ci 820da0c48c4Sopenharmony_cistatic ptrdiff_t 821da0c48c4Sopenharmony_cigetlocations_addr (Dwarf_Attribute *attr, ptrdiff_t offset, 822da0c48c4Sopenharmony_ci Dwarf_Addr *basep, Dwarf_Addr *startp, Dwarf_Addr *endp, 823da0c48c4Sopenharmony_ci Dwarf_Addr address, const Elf_Data *locs, Dwarf_Op **expr, 824da0c48c4Sopenharmony_ci size_t *exprlen) 825da0c48c4Sopenharmony_ci{ 826da0c48c4Sopenharmony_ci Dwarf_CU *cu = attr->cu; 827da0c48c4Sopenharmony_ci Dwarf *dbg = cu->dbg; 828da0c48c4Sopenharmony_ci size_t secidx = cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists; 829da0c48c4Sopenharmony_ci const unsigned char *readp = locs->d_buf + offset; 830da0c48c4Sopenharmony_ci const unsigned char *readendp = locs->d_buf + locs->d_size; 831da0c48c4Sopenharmony_ci 832da0c48c4Sopenharmony_ci Dwarf_Addr begin; 833da0c48c4Sopenharmony_ci Dwarf_Addr end; 834da0c48c4Sopenharmony_ci 835da0c48c4Sopenharmony_ci next: 836da0c48c4Sopenharmony_ci switch (__libdw_read_begin_end_pair_inc (cu, secidx, 837da0c48c4Sopenharmony_ci &readp, readendp, 838da0c48c4Sopenharmony_ci cu->address_size, 839da0c48c4Sopenharmony_ci &begin, &end, basep)) 840da0c48c4Sopenharmony_ci { 841da0c48c4Sopenharmony_ci case 0: /* got location range. */ 842da0c48c4Sopenharmony_ci break; 843da0c48c4Sopenharmony_ci case 1: /* base address setup. */ 844da0c48c4Sopenharmony_ci goto next; 845da0c48c4Sopenharmony_ci case 2: /* end of loclist */ 846da0c48c4Sopenharmony_ci return 0; 847da0c48c4Sopenharmony_ci default: /* error */ 848da0c48c4Sopenharmony_ci return -1; 849da0c48c4Sopenharmony_ci } 850da0c48c4Sopenharmony_ci 851da0c48c4Sopenharmony_ci /* We have a location expression. */ 852da0c48c4Sopenharmony_ci Dwarf_Block block; 853da0c48c4Sopenharmony_ci if (secidx == IDX_debug_loc) 854da0c48c4Sopenharmony_ci { 855da0c48c4Sopenharmony_ci if (readendp - readp < 2) 856da0c48c4Sopenharmony_ci { 857da0c48c4Sopenharmony_ci invalid: 858da0c48c4Sopenharmony_ci __libdw_seterrno (DWARF_E_INVALID_DWARF); 859da0c48c4Sopenharmony_ci return -1; 860da0c48c4Sopenharmony_ci } 861da0c48c4Sopenharmony_ci block.length = read_2ubyte_unaligned_inc (dbg, readp); 862da0c48c4Sopenharmony_ci } 863da0c48c4Sopenharmony_ci else 864da0c48c4Sopenharmony_ci { 865da0c48c4Sopenharmony_ci if (readendp - readp < 1) 866da0c48c4Sopenharmony_ci goto invalid; 867da0c48c4Sopenharmony_ci get_uleb128 (block.length, readp, readendp); 868da0c48c4Sopenharmony_ci } 869da0c48c4Sopenharmony_ci block.data = (unsigned char *) readp; 870da0c48c4Sopenharmony_ci if (readendp - readp < (ptrdiff_t) block.length) 871da0c48c4Sopenharmony_ci goto invalid; 872da0c48c4Sopenharmony_ci readp += block.length; 873da0c48c4Sopenharmony_ci 874da0c48c4Sopenharmony_ci /* Note these addresses include any base (if necessary) already. */ 875da0c48c4Sopenharmony_ci *startp = begin; 876da0c48c4Sopenharmony_ci *endp = end; 877da0c48c4Sopenharmony_ci 878da0c48c4Sopenharmony_ci /* If address is minus one we want them all, otherwise only matching. */ 879da0c48c4Sopenharmony_ci if (address != (Dwarf_Word) -1 && (address < *startp || address >= *endp)) 880da0c48c4Sopenharmony_ci goto next; 881da0c48c4Sopenharmony_ci 882da0c48c4Sopenharmony_ci if (getlocation (cu, &block, expr, exprlen, secidx) != 0) 883da0c48c4Sopenharmony_ci return -1; 884da0c48c4Sopenharmony_ci 885da0c48c4Sopenharmony_ci return readp - (unsigned char *) locs->d_buf; 886da0c48c4Sopenharmony_ci} 887da0c48c4Sopenharmony_ci 888da0c48c4Sopenharmony_ciint 889da0c48c4Sopenharmony_cidwarf_getlocation_addr (Dwarf_Attribute *attr, Dwarf_Addr address, 890da0c48c4Sopenharmony_ci Dwarf_Op **llbufs, size_t *listlens, size_t maxlocs) 891da0c48c4Sopenharmony_ci{ 892da0c48c4Sopenharmony_ci if (! attr_ok (attr)) 893da0c48c4Sopenharmony_ci return -1; 894da0c48c4Sopenharmony_ci 895da0c48c4Sopenharmony_ci if (llbufs == NULL) 896da0c48c4Sopenharmony_ci maxlocs = SIZE_MAX; 897da0c48c4Sopenharmony_ci 898da0c48c4Sopenharmony_ci /* If it has a block form, it's a single location expression. 899da0c48c4Sopenharmony_ci Except for DW_FORM_data16, which is a 128bit constant. */ 900da0c48c4Sopenharmony_ci Dwarf_Block block; 901da0c48c4Sopenharmony_ci if (attr->form != DW_FORM_data16 902da0c48c4Sopenharmony_ci && INTUSE(dwarf_formblock) (attr, &block) == 0) 903da0c48c4Sopenharmony_ci { 904da0c48c4Sopenharmony_ci if (maxlocs == 0) 905da0c48c4Sopenharmony_ci return 0; 906da0c48c4Sopenharmony_ci if (llbufs != NULL && 907da0c48c4Sopenharmony_ci getlocation (attr->cu, &block, &llbufs[0], &listlens[0], 908da0c48c4Sopenharmony_ci cu_sec_idx (attr->cu)) != 0) 909da0c48c4Sopenharmony_ci return -1; 910da0c48c4Sopenharmony_ci return listlens[0] == 0 ? 0 : 1; 911da0c48c4Sopenharmony_ci } 912da0c48c4Sopenharmony_ci 913da0c48c4Sopenharmony_ci if (attr->form != DW_FORM_data16) 914da0c48c4Sopenharmony_ci { 915da0c48c4Sopenharmony_ci int error = INTUSE(dwarf_errno) (); 916da0c48c4Sopenharmony_ci if (unlikely (error != DWARF_E_NO_BLOCK)) 917da0c48c4Sopenharmony_ci { 918da0c48c4Sopenharmony_ci __libdw_seterrno (error); 919da0c48c4Sopenharmony_ci return -1; 920da0c48c4Sopenharmony_ci } 921da0c48c4Sopenharmony_ci } 922da0c48c4Sopenharmony_ci 923da0c48c4Sopenharmony_ci /* If is_constant_offset is successful, we are done with 1 result. */ 924da0c48c4Sopenharmony_ci int result = is_constant_offset (attr, llbufs, listlens); 925da0c48c4Sopenharmony_ci if (result != 1) 926da0c48c4Sopenharmony_ci return result ?: 1; 927da0c48c4Sopenharmony_ci 928da0c48c4Sopenharmony_ci Dwarf_Addr base, start, end; 929da0c48c4Sopenharmony_ci Dwarf_Op *expr; 930da0c48c4Sopenharmony_ci size_t expr_len; 931da0c48c4Sopenharmony_ci ptrdiff_t off = 0; 932da0c48c4Sopenharmony_ci size_t got = 0; 933da0c48c4Sopenharmony_ci 934da0c48c4Sopenharmony_ci /* This is a true loclistptr, fetch the initial base address and offset. */ 935da0c48c4Sopenharmony_ci base = __libdw_cu_base_address (attr->cu); 936da0c48c4Sopenharmony_ci if (base == (Dwarf_Addr) -1) 937da0c48c4Sopenharmony_ci return -1; 938da0c48c4Sopenharmony_ci 939da0c48c4Sopenharmony_ci if (initial_offset (attr, &off) != 0) 940da0c48c4Sopenharmony_ci return -1; 941da0c48c4Sopenharmony_ci 942da0c48c4Sopenharmony_ci size_t secidx = attr->cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists; 943da0c48c4Sopenharmony_ci const Elf_Data *d = attr->cu->dbg->sectiondata[secidx]; 944da0c48c4Sopenharmony_ci 945da0c48c4Sopenharmony_ci while (got < maxlocs 946da0c48c4Sopenharmony_ci && (off = getlocations_addr (attr, off, &base, &start, &end, 947da0c48c4Sopenharmony_ci address, d, &expr, &expr_len)) > 0) 948da0c48c4Sopenharmony_ci { 949da0c48c4Sopenharmony_ci /* This one matches the address. */ 950da0c48c4Sopenharmony_ci if (llbufs != NULL) 951da0c48c4Sopenharmony_ci { 952da0c48c4Sopenharmony_ci llbufs[got] = expr; 953da0c48c4Sopenharmony_ci listlens[got] = expr_len; 954da0c48c4Sopenharmony_ci } 955da0c48c4Sopenharmony_ci ++got; 956da0c48c4Sopenharmony_ci } 957da0c48c4Sopenharmony_ci 958da0c48c4Sopenharmony_ci /* We might stop early, so off can be zero or positive on success. */ 959da0c48c4Sopenharmony_ci if (off < 0) 960da0c48c4Sopenharmony_ci return -1; 961da0c48c4Sopenharmony_ci 962da0c48c4Sopenharmony_ci return got; 963da0c48c4Sopenharmony_ci} 964da0c48c4Sopenharmony_ci 965da0c48c4Sopenharmony_ciptrdiff_t 966da0c48c4Sopenharmony_cidwarf_getlocations (Dwarf_Attribute *attr, ptrdiff_t offset, Dwarf_Addr *basep, 967da0c48c4Sopenharmony_ci Dwarf_Addr *startp, Dwarf_Addr *endp, Dwarf_Op **expr, 968da0c48c4Sopenharmony_ci size_t *exprlen) 969da0c48c4Sopenharmony_ci{ 970da0c48c4Sopenharmony_ci if (! attr_ok (attr)) 971da0c48c4Sopenharmony_ci return -1; 972da0c48c4Sopenharmony_ci 973da0c48c4Sopenharmony_ci /* 1 is an invalid offset, meaning no more locations. */ 974da0c48c4Sopenharmony_ci if (offset == 1) 975da0c48c4Sopenharmony_ci return 0; 976da0c48c4Sopenharmony_ci 977da0c48c4Sopenharmony_ci if (offset == 0) 978da0c48c4Sopenharmony_ci { 979da0c48c4Sopenharmony_ci /* If it has a block form, it's a single location expression. 980da0c48c4Sopenharmony_ci Except for DW_FORM_data16, which is a 128bit constant. */ 981da0c48c4Sopenharmony_ci Dwarf_Block block; 982da0c48c4Sopenharmony_ci if (attr->form != DW_FORM_data16 983da0c48c4Sopenharmony_ci && INTUSE(dwarf_formblock) (attr, &block) == 0) 984da0c48c4Sopenharmony_ci { 985da0c48c4Sopenharmony_ci if (getlocation (attr->cu, &block, expr, exprlen, 986da0c48c4Sopenharmony_ci cu_sec_idx (attr->cu)) != 0) 987da0c48c4Sopenharmony_ci return -1; 988da0c48c4Sopenharmony_ci 989da0c48c4Sopenharmony_ci /* This is the one and only location covering everything. */ 990da0c48c4Sopenharmony_ci *startp = 0; 991da0c48c4Sopenharmony_ci *endp = -1; 992da0c48c4Sopenharmony_ci return 1; 993da0c48c4Sopenharmony_ci } 994da0c48c4Sopenharmony_ci 995da0c48c4Sopenharmony_ci if (attr->form != DW_FORM_data16) 996da0c48c4Sopenharmony_ci { 997da0c48c4Sopenharmony_ci int error = INTUSE(dwarf_errno) (); 998da0c48c4Sopenharmony_ci if (unlikely (error != DWARF_E_NO_BLOCK)) 999da0c48c4Sopenharmony_ci { 1000da0c48c4Sopenharmony_ci __libdw_seterrno (error); 1001da0c48c4Sopenharmony_ci return -1; 1002da0c48c4Sopenharmony_ci } 1003da0c48c4Sopenharmony_ci } 1004da0c48c4Sopenharmony_ci 1005da0c48c4Sopenharmony_ci int result = is_constant_offset (attr, expr, exprlen); 1006da0c48c4Sopenharmony_ci if (result != 1) 1007da0c48c4Sopenharmony_ci { 1008da0c48c4Sopenharmony_ci if (result == 0) 1009da0c48c4Sopenharmony_ci { 1010da0c48c4Sopenharmony_ci /* This is the one and only location covering everything. */ 1011da0c48c4Sopenharmony_ci *startp = 0; 1012da0c48c4Sopenharmony_ci *endp = -1; 1013da0c48c4Sopenharmony_ci return 1; 1014da0c48c4Sopenharmony_ci } 1015da0c48c4Sopenharmony_ci return result; /* Something bad, dwarf_errno has been set. */ 1016da0c48c4Sopenharmony_ci } 1017da0c48c4Sopenharmony_ci 1018da0c48c4Sopenharmony_ci /* We must be looking at a true loclistptr, fetch the initial 1019da0c48c4Sopenharmony_ci base address and offset. */ 1020da0c48c4Sopenharmony_ci *basep = __libdw_cu_base_address (attr->cu); 1021da0c48c4Sopenharmony_ci if (*basep == (Dwarf_Addr) -1) 1022da0c48c4Sopenharmony_ci return -1; 1023da0c48c4Sopenharmony_ci 1024da0c48c4Sopenharmony_ci if (initial_offset (attr, &offset) != 0) 1025da0c48c4Sopenharmony_ci return -1; 1026da0c48c4Sopenharmony_ci } 1027da0c48c4Sopenharmony_ci 1028da0c48c4Sopenharmony_ci size_t secidx = attr->cu->version < 5 ? IDX_debug_loc : IDX_debug_loclists; 1029da0c48c4Sopenharmony_ci const Elf_Data *d = attr->cu->dbg->sectiondata[secidx]; 1030da0c48c4Sopenharmony_ci 1031da0c48c4Sopenharmony_ci return getlocations_addr (attr, offset, basep, startp, endp, 1032da0c48c4Sopenharmony_ci (Dwarf_Word) -1, d, expr, exprlen); 1033da0c48c4Sopenharmony_ci} 1034