Dwarf_Die * dwarf_cu_die (Dwarf_CU *cu, Dwarf_Die *result, Dwarf_Half *versionp, Dwarf_Off *abbrev_offsetp, uint8_t *address_sizep, uint8_t *offset_sizep, uint64_t *type_signaturep, Dwarf_Off *type_offsetp) { if (cu == NULL) return NULL; *result = CUDIE (cu); if (versionp != NULL) *versionp = cu->version; if (abbrev_offsetp != NULL) *abbrev_offsetp = cu->orig_abbrev_offset; if (address_sizep != NULL) *address_sizep = cu->address_size; if (offset_sizep != NULL) *offset_sizep = cu->offset_size; if (type_signaturep != NULL) *type_signaturep = cu->type_sig8; if (type_offsetp != NULL) *type_offsetp = cu->type_offset; return result; }
int dwarf_entry_breakpoints (Dwarf_Die *die, Dwarf_Addr **bkpts) { int nbkpts = 0; *bkpts = NULL; /* Fetch the CU's line records to look for this DIE's addresses. */ Dwarf_Die cudie = CUDIE (die->cu); Dwarf_Lines *lines; size_t nlines; if (INTUSE(dwarf_getsrclines) (&cudie, &lines, &nlines) < 0) { int error = INTUSE (dwarf_errno) (); if (error == 0) /* CU has no DW_AT_stmt_list. */ return entrypc_bkpt (die, bkpts, &nbkpts); __libdw_seterrno (error); return -1; } /* Search each contiguous address range for DWARF prologue_end markers. */ Dwarf_Addr base; Dwarf_Addr begin; Dwarf_Addr end; ptrdiff_t offset = INTUSE(dwarf_ranges) (die, 0, &base, &begin, &end); if (offset < 0) return -1; /* Most often there is a single contiguous PC range for the DIE. */ if (offset == 1) return search_range (begin, end, true, true, lines, nlines, bkpts, &nbkpts) ?: entrypc_bkpt (die, bkpts, &nbkpts); Dwarf_Addr lowpc = (Dwarf_Addr) -1l; Dwarf_Addr highpc = (Dwarf_Addr) -1l; while (offset > 0) { /* We have an address range entry. */ if (search_range (begin, end, true, false, lines, nlines, bkpts, &nbkpts) < 0) return -1; if (begin < lowpc) { lowpc = begin; highpc = end; } offset = INTUSE(dwarf_ranges) (die, offset, &base, &begin, &end); } /* If we didn't find any proper DWARF markers, then look in the lowest-addressed range for an ad hoc marker. Failing that, fall back to just using the entrypc value. */ return (nbkpts ?: (lowpc == (Dwarf_Addr) -1l ? 0 : search_range (lowpc, highpc, false, true, lines, nlines, bkpts, &nbkpts)) ?: entrypc_bkpt (die, bkpts, &nbkpts)); }
int dwarf_getlocation_implicit_value (Dwarf_Attribute *attr, const Dwarf_Op *op, Dwarf_Block *return_block) { if (attr == NULL) return -1; struct loc_block_s fake = { .addr = (void *) op }; struct loc_block_s **found = tfind (&fake, &attr->cu->locs, loc_compare); if (unlikely (found == NULL)) { __libdw_seterrno (DWARF_E_NO_BLOCK); return -1; } return_block->length = (*found)->length; return_block->data = (*found)->data; return 0; } /* DW_AT_data_member_location can be a constant as well as a loclistptr. Only data[48] indicate a loclistptr. */ static int check_constant_offset (Dwarf_Attribute *attr, Dwarf_Op **llbuf, size_t *listlen) { if (attr->code != DW_AT_data_member_location) return 1; switch (attr->form) { /* Punt for any non-constant form. */ default: return 1; case DW_FORM_data1: case DW_FORM_data2: case DW_FORM_data4: case DW_FORM_data8: case DW_FORM_sdata: case DW_FORM_udata: break; } /* Check whether we already cached this location. */ struct loc_s fake = { .addr = attr->valp }; struct loc_s **found = tfind (&fake, &attr->cu->locs, loc_compare); if (found == NULL) { Dwarf_Word offset; if (INTUSE(dwarf_formudata) (attr, &offset) != 0) return -1; Dwarf_Op *result = libdw_alloc (attr->cu->dbg, Dwarf_Op, sizeof (Dwarf_Op), 1); result->atom = DW_OP_plus_uconst; result->number = offset; result->number2 = 0; result->offset = 0; /* Insert a record in the search tree so we can find it again later. */ struct loc_s *newp = libdw_alloc (attr->cu->dbg, struct loc_s, sizeof (struct loc_s), 1); newp->addr = attr->valp; newp->loc = result; newp->nloc = 1; found = tsearch (newp, &attr->cu->locs, loc_compare); } assert ((*found)->nloc == 1); if (llbuf != NULL) { *llbuf = (*found)->loc; *listlen = 1; } return 0; } int internal_function __libdw_intern_expression (Dwarf *dbg, bool other_byte_order, unsigned int address_size, unsigned int ref_size, void **cache, const Dwarf_Block *block, bool cfap, bool valuep, Dwarf_Op **llbuf, size_t *listlen, int sec_index) { /* Empty location expressions don't have any ops to intern. */ if (block->length == 0) { *listlen = 0; return 0; } /* Check whether we already looked at this list. */ struct loc_s fake = { .addr = block->data }; struct loc_s **found = tfind (&fake, cache, loc_compare); if (found != NULL) { /* We already saw it. */ *llbuf = (*found)->loc; *listlen = (*found)->nloc; if (valuep) { assert (*listlen > 1); assert ((*llbuf)[*listlen - 1].atom == DW_OP_stack_value); } return 0; } const unsigned char *data = block->data; const unsigned char *const end_data = data + block->length; const struct { bool other_byte_order; } bo = { other_byte_order }; struct loclist *loclist = NULL; unsigned int n = 0; /* Stack allocate at most this many locs. */ #define MAX_STACK_LOCS 256 struct loclist stack_locs[MAX_STACK_LOCS]; #define NEW_LOC() ({ struct loclist *ll; \ ll = (likely (n < MAX_STACK_LOCS) \ ? &stack_locs[n] \ : malloc (sizeof (struct loclist))); \ if (unlikely (ll == NULL)) \ goto nomem; \ n++; \ ll->next = loclist; \ loclist = ll; \ ll; }) if (cfap) { /* Synthesize the operation to push the CFA before the expression. */ struct loclist *newloc = NEW_LOC (); newloc->atom = DW_OP_call_frame_cfa; newloc->number = 0; newloc->number2 = 0; newloc->offset = -1; } /* Decode the opcodes. It is possible in some situations to have a block of size zero. */ while (data < end_data) { struct loclist *newloc; newloc = NEW_LOC (); newloc->number = 0; newloc->number2 = 0; newloc->offset = data - block->data; switch ((newloc->atom = *data++)) { case DW_OP_addr: /* Address, depends on address size of CU. */ if (dbg == NULL) { // XXX relocation? if (address_size == 4) { if (unlikely (data + 4 > end_data)) goto invalid; else newloc->number = read_4ubyte_unaligned_inc (&bo, data); } else { if (unlikely (data + 8 > end_data)) goto invalid; else newloc->number = read_8ubyte_unaligned_inc (&bo, data); } } else if (__libdw_read_address_inc (dbg, sec_index, &data, address_size, &newloc->number)) goto invalid; break; case DW_OP_call_ref: /* DW_FORM_ref_addr, depends on offset size of CU. */ if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data, ref_size, &newloc->number, IDX_debug_info, 0)) goto invalid; break; case DW_OP_deref: case DW_OP_dup: case DW_OP_drop: case DW_OP_over: case DW_OP_swap: case DW_OP_rot: case DW_OP_xderef: case DW_OP_abs: case DW_OP_and: case DW_OP_div: case DW_OP_minus: case DW_OP_mod: case DW_OP_mul: case DW_OP_neg: case DW_OP_not: case DW_OP_or: case DW_OP_plus: case DW_OP_shl: case DW_OP_shr: case DW_OP_shra: case DW_OP_xor: case DW_OP_eq: case DW_OP_ge: case DW_OP_gt: case DW_OP_le: case DW_OP_lt: case DW_OP_ne: case DW_OP_lit0 ... DW_OP_lit31: case DW_OP_reg0 ... DW_OP_reg31: case DW_OP_nop: case DW_OP_push_object_address: case DW_OP_call_frame_cfa: case DW_OP_form_tls_address: case DW_OP_GNU_push_tls_address: case DW_OP_stack_value: /* No operand. */ break; case DW_OP_const1u: case DW_OP_pick: case DW_OP_deref_size: case DW_OP_xderef_size: if (unlikely (data >= end_data)) { invalid: __libdw_seterrno (DWARF_E_INVALID_DWARF); returnmem: /* Free any dynamicly allocated loclists, if any. */ while (n > MAX_STACK_LOCS) { struct loclist *loc = loclist; loclist = loc->next; free (loc); n--; } return -1; } newloc->number = *data++; break; case DW_OP_const1s: if (unlikely (data >= end_data)) goto invalid; newloc->number = *((int8_t *) data); ++data; break; case DW_OP_const2u: if (unlikely (data + 2 > end_data)) goto invalid; newloc->number = read_2ubyte_unaligned_inc (&bo, data); break; case DW_OP_const2s: case DW_OP_skip: case DW_OP_bra: case DW_OP_call2: if (unlikely (data + 2 > end_data)) goto invalid; newloc->number = read_2sbyte_unaligned_inc (&bo, data); break; case DW_OP_const4u: if (unlikely (data + 4 > end_data)) goto invalid; newloc->number = read_4ubyte_unaligned_inc (&bo, data); break; case DW_OP_const4s: case DW_OP_call4: case DW_OP_GNU_parameter_ref: if (unlikely (data + 4 > end_data)) goto invalid; newloc->number = read_4sbyte_unaligned_inc (&bo, data); break; case DW_OP_const8u: if (unlikely (data + 8 > end_data)) goto invalid; newloc->number = read_8ubyte_unaligned_inc (&bo, data); break; case DW_OP_const8s: if (unlikely (data + 8 > end_data)) goto invalid; newloc->number = read_8sbyte_unaligned_inc (&bo, data); break; case DW_OP_constu: case DW_OP_plus_uconst: case DW_OP_regx: case DW_OP_piece: case DW_OP_GNU_convert: case DW_OP_GNU_reinterpret: get_uleb128 (newloc->number, data, end_data); break; case DW_OP_consts: case DW_OP_breg0 ... DW_OP_breg31: case DW_OP_fbreg: get_sleb128 (newloc->number, data, end_data); break; case DW_OP_bregx: get_uleb128 (newloc->number, data, end_data); if (unlikely (data >= end_data)) goto invalid; get_sleb128 (newloc->number2, data, end_data); break; case DW_OP_bit_piece: case DW_OP_GNU_regval_type: get_uleb128 (newloc->number, data, end_data); if (unlikely (data >= end_data)) goto invalid; get_uleb128 (newloc->number2, data, end_data); break; case DW_OP_implicit_value: case DW_OP_GNU_entry_value: /* This cannot be used in a CFI expression. */ if (unlikely (dbg == NULL)) goto invalid; /* start of block inc. len. */ newloc->number2 = (Dwarf_Word) (uintptr_t) data; get_uleb128 (newloc->number, data, end_data); /* Block length. */ if (unlikely ((Dwarf_Word) (end_data - data) < newloc->number)) goto invalid; data += newloc->number; /* Skip the block. */ break; case DW_OP_GNU_implicit_pointer: /* DW_FORM_ref_addr, depends on offset size of CU. */ if (dbg == NULL || __libdw_read_offset_inc (dbg, sec_index, &data, ref_size, &newloc->number, IDX_debug_info, 0)) goto invalid; if (unlikely (data >= end_data)) goto invalid; get_uleb128 (newloc->number2, data, end_data); /* Byte offset. */ break; case DW_OP_GNU_deref_type: if (unlikely (data + 1 >= end_data)) goto invalid; newloc->number = *data++; get_uleb128 (newloc->number2, data, end_data); break; case DW_OP_GNU_const_type: { size_t size; get_uleb128 (newloc->number, data, end_data); if (unlikely (data >= end_data)) goto invalid; /* start of block inc. len. */ newloc->number2 = (Dwarf_Word) (uintptr_t) data; size = *data++; if (unlikely ((Dwarf_Word) (end_data - data) < size)) goto invalid; data += size; /* Skip the block. */ } break; default: goto invalid; } } if (unlikely (n == 0)) { /* This is not allowed. It would mean an empty location expression, which we handled already as a special case above. */ goto invalid; } if (valuep) { struct loclist *newloc = NEW_LOC (); newloc->atom = DW_OP_stack_value; newloc->number = 0; newloc->number2 = 0; newloc->offset = data - block->data; } /* Allocate the array. */ Dwarf_Op *result; if (dbg != NULL) result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n); else { result = malloc (sizeof *result * n); if (result == NULL) { nomem: __libdw_seterrno (DWARF_E_NOMEM); goto returnmem; } } /* Store the result. */ *llbuf = result; *listlen = n; do { /* We populate the array from the back since the list is backwards. */ --n; result[n].atom = loclist->atom; result[n].number = loclist->number; result[n].number2 = loclist->number2; result[n].offset = loclist->offset; if (result[n].atom == DW_OP_implicit_value) store_implicit_value (dbg, cache, &result[n]); struct loclist *loc = loclist; loclist = loclist->next; if (unlikely (n + 1 > MAX_STACK_LOCS)) free (loc); } while (n > 0); /* Insert a record in the search tree so that we can find it again later. */ struct loc_s *newp; if (dbg != NULL) newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 1); else { newp = malloc (sizeof *newp); if (newp == NULL) { free (result); goto nomem; } } newp->addr = block->data; newp->loc = result; newp->nloc = *listlen; (void) tsearch (newp, cache, loc_compare); /* We did it. */ return 0; } static int getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, Dwarf_Op **llbuf, size_t *listlen, int sec_index) { /* Empty location expressions don't have any ops to intern. Note that synthetic empty_cu doesn't have an associated DWARF dbg. */ if (block->length == 0) { *listlen = 0; return 0; } return __libdw_intern_expression (cu->dbg, cu->dbg->other_byte_order, cu->address_size, (cu->version == 2 ? cu->address_size : cu->offset_size), &cu->locs, block, false, false, llbuf, listlen, sec_index); } int dwarf_getlocation (Dwarf_Attribute *attr, Dwarf_Op **llbuf, size_t *listlen) { if (! attr_ok (attr)) return -1; int result = check_constant_offset (attr, llbuf, listlen); if (result != 1) return result; /* If it has a block form, it's a single location expression. */ Dwarf_Block block; if (INTUSE(dwarf_formblock) (attr, &block) != 0) return -1; return getlocation (attr->cu, &block, llbuf, listlen, cu_sec_idx (attr->cu)); } static int attr_base_address (Dwarf_Attribute *attr, Dwarf_Addr *basep) { /* Fetch the CU's base address. */ Dwarf_Die cudie = CUDIE (attr->cu); /* Find the base address of the compilation unit. It will normally be specified by DW_AT_low_pc. In DWARF-3 draft 4, the base address could be overridden by DW_AT_entry_pc. It's been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc for compilation units with discontinuous ranges. */ Dwarf_Attribute attr_mem; if (unlikely (INTUSE(dwarf_lowpc) (&cudie, basep) != 0) && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie, DW_AT_entry_pc, &attr_mem), basep) != 0) { if (INTUSE(dwarf_errno) () != 0) return -1; /* The compiler provided no base address when it should have. Buggy GCC does this when it used absolute addresses in the location list and no DW_AT_ranges. */ *basep = 0; } return 0; }
static int getlocation (struct Dwarf_CU *cu, const Dwarf_Block *block, Dwarf_Op **llbuf, size_t *listlen) { Dwarf *dbg = cu->dbg; /* Check whether we already looked at this list. */ struct loc_s fake = { .addr = block->data }; struct loc_s **found = tfind (&fake, &cu->locs, loc_compare); if (found != NULL) { /* We already saw it. */ *llbuf = (*found)->loc; *listlen = (*found)->nloc; return 0; } const unsigned char *data = block->data; const unsigned char *const end_data = data + block->length; struct loclist *loclist = NULL; unsigned int n = 0; /* Decode the opcodes. It is possible in some situations to have a block of size zero. */ while (data < end_data) { struct loclist *newloc; newloc = (struct loclist *) alloca (sizeof (struct loclist)); newloc->number = 0; newloc->number2 = 0; newloc->offset = data - block->data; newloc->next = loclist; loclist = newloc; ++n; switch ((newloc->atom = *data++)) { case DW_OP_addr: /* Address, depends on address size of CU. */ if (cu->address_size == 4) { if (unlikely (data + 4 > end_data)) { invalid: __libdw_seterrno (DWARF_E_INVALID_DWARF); return -1; } newloc->number = read_4ubyte_unaligned_inc (dbg, data); } else { if (unlikely (data + 8 > end_data)) goto invalid; newloc->number = read_8ubyte_unaligned_inc (dbg, data); } break; case DW_OP_deref: case DW_OP_dup: case DW_OP_drop: case DW_OP_over: case DW_OP_swap: case DW_OP_rot: case DW_OP_xderef: case DW_OP_abs: case DW_OP_and: case DW_OP_div: case DW_OP_minus: case DW_OP_mod: case DW_OP_mul: case DW_OP_neg: case DW_OP_not: case DW_OP_or: case DW_OP_plus: case DW_OP_shl: case DW_OP_shr: case DW_OP_shra: case DW_OP_xor: case DW_OP_eq: case DW_OP_ge: case DW_OP_gt: case DW_OP_le: case DW_OP_lt: case DW_OP_ne: case DW_OP_lit0 ... DW_OP_lit31: case DW_OP_reg0 ... DW_OP_reg31: case DW_OP_nop: case DW_OP_push_object_address: case DW_OP_call_ref: /* No operand. */ break; case DW_OP_const1u: case DW_OP_pick: case DW_OP_deref_size: case DW_OP_xderef_size: if (unlikely (data >= end_data)) goto invalid; newloc->number = *data++; break; case DW_OP_const1s: if (unlikely (data >= end_data)) goto invalid; newloc->number = *((int8_t *) data); ++data; break; case DW_OP_const2u: if (unlikely (data + 2 > end_data)) goto invalid; newloc->number = read_2ubyte_unaligned_inc (dbg, data); break; case DW_OP_const2s: case DW_OP_skip: case DW_OP_bra: case DW_OP_call2: if (unlikely (data + 2 > end_data)) goto invalid; newloc->number = read_2sbyte_unaligned_inc (dbg, data); break; case DW_OP_const4u: if (unlikely (data + 4 > end_data)) goto invalid; newloc->number = read_4ubyte_unaligned_inc (dbg, data); break; case DW_OP_const4s: case DW_OP_call4: if (unlikely (data + 4 > end_data)) goto invalid; newloc->number = read_4sbyte_unaligned_inc (dbg, data); break; case DW_OP_const8u: if (unlikely (data + 8 > end_data)) goto invalid; newloc->number = read_8ubyte_unaligned_inc (dbg, data); break; case DW_OP_const8s: if (unlikely (data + 8 > end_data)) goto invalid; newloc->number = read_8sbyte_unaligned_inc (dbg, data); break; case DW_OP_constu: case DW_OP_plus_uconst: case DW_OP_regx: case DW_OP_piece: /* XXX Check size. */ get_uleb128 (newloc->number, data); break; case DW_OP_consts: case DW_OP_breg0 ... DW_OP_breg31: case DW_OP_fbreg: /* XXX Check size. */ get_sleb128 (newloc->number, data); break; case DW_OP_bregx: /* XXX Check size. */ get_uleb128 (newloc->number, data); get_sleb128 (newloc->number2, data); break; default: goto invalid; } } if (unlikely (n == 0)) { /* This is not allowed. XXX Is it? */ goto invalid; } /* Allocate the array. */ Dwarf_Op *result = libdw_alloc (dbg, Dwarf_Op, sizeof (Dwarf_Op), n); /* Store the result. */ *llbuf = result; *listlen = n; do { /* We populate the array from the back since the list is backwards. */ --n; result[n].atom = loclist->atom; result[n].number = loclist->number; result[n].number2 = loclist->number2; result[n].offset = loclist->offset; loclist = loclist->next; } while (n > 0); /* Insert a record in the search tree so that we can find it again later. */ struct loc_s *newp = libdw_alloc (dbg, struct loc_s, sizeof (struct loc_s), 1); newp->addr = block->data; newp->loc = result; newp->nloc = *listlen; (void) tsearch (newp, &cu->locs, loc_compare); /* We did it. */ return 0; } int dwarf_getlocation (attr, llbuf, listlen) Dwarf_Attribute *attr; Dwarf_Op **llbuf; size_t *listlen; { if (! attr_ok (attr)) return -1; /* If it has a block form, it's a single location expression. */ Dwarf_Block block; if (INTUSE(dwarf_formblock) (attr, &block) != 0) return -1; return getlocation (attr->cu, &block, llbuf, listlen); } int dwarf_getlocation_addr (attr, address, llbufs, listlens, maxlocs) Dwarf_Attribute *attr; Dwarf_Addr address; Dwarf_Op **llbufs; size_t *listlens; size_t maxlocs; { if (! attr_ok (attr)) return -1; if (llbufs == NULL) maxlocs = SIZE_MAX; /* If it has a block form, it's a single location expression. */ Dwarf_Block block; if (INTUSE(dwarf_formblock) (attr, &block) == 0) { if (maxlocs == 0) return 0; if (llbufs != NULL && getlocation (attr->cu, &block, &llbufs[0], &listlens[0]) != 0) return -1; return listlens[0] == 0 ? 0 : 1; } int error = INTUSE(dwarf_errno) (); if (unlikely (error != DWARF_E_NO_BLOCK)) { __libdw_seterrno (error); return -1; } /* Must have the form data4 or data8 which act as an offset. */ Dwarf_Word offset; if (unlikely (INTUSE(dwarf_formudata) (attr, &offset) != 0)) return -1; const Elf_Data *d = attr->cu->dbg->sectiondata[IDX_debug_loc]; if (unlikely (d == NULL)) { __libdw_seterrno (DWARF_E_NO_LOCLIST); return -1; } Dwarf_Addr base = (Dwarf_Addr) -1; unsigned char *readp = d->d_buf + offset; size_t got = 0; while (got < maxlocs) { if ((unsigned char *) d->d_buf + d->d_size - readp < attr->cu->address_size * 2) { invalid: __libdw_seterrno (DWARF_E_INVALID_DWARF); return -1; } Dwarf_Addr begin; Dwarf_Addr end; if (attr->cu->address_size == 8) { begin = read_8ubyte_unaligned_inc (attr->cu->dbg, readp); end = read_8ubyte_unaligned_inc (attr->cu->dbg, readp); if (begin == (Elf64_Addr) -1l) /* Base address entry. */ { base = end; if (unlikely (base == (Dwarf_Addr) -1)) goto invalid; continue; } } else { begin = read_4ubyte_unaligned_inc (attr->cu->dbg, readp); end = read_4ubyte_unaligned_inc (attr->cu->dbg, readp); if (begin == (Elf32_Addr) -1) /* Base address entry. */ { base = end; continue; } } if (begin == 0 && end == 0) /* End of list entry. */ break; if ((unsigned char *) d->d_buf + d->d_size - readp < 2) goto invalid; /* We have a location expression. */ block.length = read_2ubyte_unaligned_inc (attr->cu->dbg, readp); block.data = readp; if ((unsigned char *) d->d_buf + d->d_size - readp < (ptrdiff_t) block.length) goto invalid; readp += block.length; if (base == (Dwarf_Addr) -1) { /* Fetch the CU's base address. */ Dwarf_Die cudie = CUDIE (attr->cu); /* Find the base address of the compilation unit. It will normally be specified by DW_AT_low_pc. In DWARF-3 draft 4, the base address could be overridden by DW_AT_entry_pc. It's been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc for compilation units with discontinuous ranges. */ Dwarf_Attribute attr_mem; if (unlikely (INTUSE(dwarf_lowpc) (&cudie, &base) != 0) && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie, DW_AT_entry_pc, &attr_mem), &base) != 0) { if (INTUSE(dwarf_errno) () != 0) return -1; /* The compiler provided no base address when it should have. Buggy GCC does this when it used absolute addresses in the location list and no DW_AT_ranges. */ base = 0; } } if (address >= base + begin && address < base + end) { /* This one matches the address. */ if (llbufs != NULL && unlikely (getlocation (attr->cu, &block, &llbufs[got], &listlens[got]) != 0)) return -1; ++got; } } return got; }
/* Find the containing CU's files. */ static int getfiles (Dwarf_Die *die, Dwarf_Files **files) { return INTUSE(dwarf_getsrcfiles) (&CUDIE (die->cu), files, NULL); }
ptrdiff_t dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep, Dwarf_Addr *startp, Dwarf_Addr *endp) { if (die == NULL) return -1; if (offset == 0 /* Usually there is a single contiguous range. */ && INTUSE(dwarf_highpc) (die, endp) == 0 && INTUSE(dwarf_lowpc) (die, startp) == 0) /* A offset into .debug_ranges will never be 1, it must be at least a multiple of 4. So we can return 1 as a special case value to mark there are no ranges to look for on the next call. */ return 1; if (offset == 1) return 0; /* We have to look for a noncontiguous range. */ const Elf_Data *d = die->cu->dbg->sectiondata[IDX_debug_ranges]; if (d == NULL && offset != 0) { __libdw_seterrno (DWARF_E_NO_DEBUG_RANGES); return -1; } unsigned char *readp; unsigned char *readendp; if (offset == 0) { Dwarf_Attribute attr_mem; Dwarf_Attribute *attr = INTUSE(dwarf_attr) (die, DW_AT_ranges, &attr_mem); if (attr == NULL) /* No PC attributes in this DIE at all, so an empty range list. */ return 0; Dwarf_Word start_offset; if ((readp = __libdw_formptr (attr, IDX_debug_ranges, DWARF_E_NO_DEBUG_RANGES, &readendp, &start_offset)) == NULL) return -1; offset = start_offset; assert ((Dwarf_Word) offset == start_offset); /* Fetch the CU's base address. */ Dwarf_Die cudie = CUDIE (attr->cu); /* Find the base address of the compilation unit. It will normally be specified by DW_AT_low_pc. In DWARF-3 draft 4, the base address could be overridden by DW_AT_entry_pc. It's been removed, but GCC emits DW_AT_entry_pc and not DW_AT_lowpc for compilation units with discontinuous ranges. */ if (unlikely (INTUSE(dwarf_lowpc) (&cudie, basep) != 0) && INTUSE(dwarf_formaddr) (INTUSE(dwarf_attr) (&cudie, DW_AT_entry_pc, &attr_mem), basep) != 0) *basep = (Dwarf_Addr) -1; } else { if (__libdw_offset_in_section (die->cu->dbg, IDX_debug_ranges, offset, 1)) return -1l; readp = d->d_buf + offset; readendp = d->d_buf + d->d_size; } next: if (readendp - readp < die->cu->address_size * 2) goto invalid; Dwarf_Addr begin; Dwarf_Addr end; switch (__libdw_read_begin_end_pair_inc (die->cu->dbg, IDX_debug_ranges, &readp, die->cu->address_size, &begin, &end, basep)) { case 0: break; case 1: goto next; case 2: return 0; default: return -1l; } /* We have an address range entry. Check that we have a base. */ if (*basep == (Dwarf_Addr) -1) { if (INTUSE(dwarf_errno) () == 0) { invalid: __libdw_seterrno (DWARF_E_INVALID_DWARF); } return -1; } *startp = *basep + begin; *endp = *basep + end; return readp - (unsigned char *) d->d_buf; }
static int array_size (Dwarf_Die *die, Dwarf_Word *size, Dwarf_Attribute *attr_mem, Dwarf_Die *type_mem) { Dwarf_Word eltsize; if (INTUSE(dwarf_aggregate_size) (get_type (die, attr_mem, type_mem), &eltsize) != 0) return -1; /* An array can have DW_TAG_subrange_type or DW_TAG_enumeration_type children instead that give the size of each dimension. */ Dwarf_Die child; if (INTUSE(dwarf_child) (die, &child) != 0) return -1; bool any = false; Dwarf_Word total = 0; do { Dwarf_Word count; switch (INTUSE(dwarf_tag) (&child)) { case DW_TAG_subrange_type: /* This has either DW_AT_count or DW_AT_upper_bound. */ if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_count, attr_mem) != NULL) { if (INTUSE(dwarf_formudata) (attr_mem, &count) != 0) return -1; } else { Dwarf_Sword upper; Dwarf_Sword lower; if (INTUSE(dwarf_formsdata) (INTUSE(dwarf_attr_integrate) (&child, DW_AT_upper_bound, attr_mem), &upper) != 0) return -1; /* Having DW_AT_lower_bound is optional. */ if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_lower_bound, attr_mem) != NULL) { if (INTUSE(dwarf_formsdata) (attr_mem, &lower) != 0) return -1; } else { /* Determine default lower bound from language, as per "4.12 Subrange Type Entries". */ Dwarf_Die cu = CUDIE (die->cu); switch (INTUSE(dwarf_srclang) (&cu)) { case DW_LANG_C: case DW_LANG_C89: case DW_LANG_C99: case DW_LANG_C_plus_plus: case DW_LANG_ObjC: case DW_LANG_ObjC_plus_plus: case DW_LANG_Java: case DW_LANG_D: case DW_LANG_UPC: lower = 0; break; case DW_LANG_Ada83: case DW_LANG_Ada95: case DW_LANG_Cobol74: case DW_LANG_Cobol85: case DW_LANG_Fortran77: case DW_LANG_Fortran90: case DW_LANG_Fortran95: case DW_LANG_Pascal83: case DW_LANG_Modula2: case DW_LANG_PL1: lower = 1; break; default: return -1; } } if (unlikely (lower > upper)) return -1; count = upper - lower + 1; } break; case DW_TAG_enumeration_type: /* We have to find the DW_TAG_enumerator child with the highest value to know the array's element count. */ count = 0; Dwarf_Die enum_child; int has_children = INTUSE(dwarf_child) (die, &enum_child); if (has_children < 0) return -1; if (has_children > 0) do if (INTUSE(dwarf_tag) (&enum_child) == DW_TAG_enumerator) { Dwarf_Word value; if (INTUSE(dwarf_formudata) (INTUSE(dwarf_attr_integrate) (&enum_child, DW_AT_const_value, attr_mem), &value) != 0) return -1; if (value >= count) count = value + 1; } while (INTUSE(dwarf_siblingof) (&enum_child, &enum_child) > 0); break; default: continue; } /* This is a subrange_type or enumeration_type and we've set COUNT. Now determine the stride for this array dimension. */ Dwarf_Word stride = eltsize; if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_byte_stride, attr_mem) != NULL) { if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0) return -1; } else if (INTUSE(dwarf_attr_integrate) (&child, DW_AT_bit_stride, attr_mem) != NULL) { if (INTUSE(dwarf_formudata) (attr_mem, &stride) != 0) return -1; if (stride % 8) /* XXX maybe compute in bits? */ return -1; stride /= 8; } any = true; total += stride * count; } while (INTUSE(dwarf_siblingof) (&child, &child) == 0); if (!any) return -1; *size = total; return 0; }