int dwarf_formblock (Dwarf_Attribute *attr, Dwarf_Block *return_block) { if (attr == NULL) return -1; const unsigned char *datap = attr->valp; const unsigned char *endp = attr->cu->endp; switch (attr->form) { case DW_FORM_block1: if (unlikely (endp - datap < 1)) goto invalid; return_block->length = *(uint8_t *) attr->valp; return_block->data = attr->valp + 1; break; case DW_FORM_block2: if (unlikely (endp - datap < 2)) goto invalid; return_block->length = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); return_block->data = attr->valp + 2; break; case DW_FORM_block4: if (unlikely (endp - datap < 4)) goto invalid; return_block->length = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); return_block->data = attr->valp + 4; break; case DW_FORM_block: case DW_FORM_exprloc: if (unlikely (endp - datap < 1)) goto invalid; get_uleb128 (return_block->length, datap, endp); return_block->data = (unsigned char *) datap; break; default: __libdw_seterrno (DWARF_E_NO_BLOCK); return -1; } if (unlikely (return_block->length > (size_t) (endp - return_block->data))) { /* Block does not fit. */ invalid: __libdw_seterrno (DWARF_E_INVALID_DWARF); return -1; } return 0; }
static int get_offsets (Dwarf *dbg) { size_t allocated = 0; size_t cnt = 0; struct pubnames_s *mem = NULL; const size_t entsize = sizeof (struct pubnames_s); unsigned char *const startp = dbg->sectiondata[IDX_debug_pubnames]->d_buf; unsigned char *readp = startp; unsigned char *endp = readp + dbg->sectiondata[IDX_debug_pubnames]->d_size; while (readp + 14 < endp) { /* If necessary, allocate more entries. */ if (cnt >= allocated) { allocated = MAX (10, 2 * allocated); struct pubnames_s *newmem = (struct pubnames_s *) realloc (mem, allocated * entsize); if (newmem == NULL) { __libdw_seterrno (DWARF_E_NOMEM); err_return: free (mem); return -1; } mem = newmem; } /* Read the set header. */ int len_bytes = 4; Dwarf_Off len = read_4ubyte_unaligned_inc (dbg, readp); if (len == DWARF3_LENGTH_64_BIT) { len = read_8ubyte_unaligned_inc (dbg, readp); len_bytes = 8; } else if (unlikely (len >= DWARF3_LENGTH_MIN_ESCAPE_CODE && len <= DWARF3_LENGTH_MAX_ESCAPE_CODE)) { invalid_dwarf: __libdw_seterrno (DWARF_E_INVALID_DWARF); goto err_return; } /* Now we know the offset of the first offset/name pair. */ mem[cnt].set_start = readp + 2 + 2 * len_bytes - startp; mem[cnt].address_len = len_bytes; if (mem[cnt].set_start >= dbg->sectiondata[IDX_debug_pubnames]->d_size) /* Something wrong, the first entry is beyond the end of the section. */ break; /* Read the version. It better be two for now. */ uint16_t version = read_2ubyte_unaligned (dbg, readp); if (unlikely (version != 2)) { __libdw_seterrno (DWARF_E_INVALID_VERSION); goto err_return; } /* Get the CU offset. */ if (len_bytes == 4) mem[cnt].cu_offset = read_4ubyte_unaligned (dbg, readp + 2); else mem[cnt].cu_offset = read_8ubyte_unaligned (dbg, readp + 2); /* Determine the size of the CU header. */ if (unlikely (dbg->sectiondata[IDX_debug_info] == NULL || dbg->sectiondata[IDX_debug_info]->d_buf == NULL || (mem[cnt].cu_offset + 3 >= dbg->sectiondata[IDX_debug_info]->d_size))) goto invalid_dwarf; unsigned char *infop = ((unsigned char *) dbg->sectiondata[IDX_debug_info]->d_buf + mem[cnt].cu_offset); if (read_4ubyte_unaligned_noncvt (infop) == DWARF3_LENGTH_64_BIT) mem[cnt].cu_header_size = 23; else mem[cnt].cu_header_size = 11; ++cnt; /* Advance to the next set. */ readp += len; } if (mem == NULL) { __libdw_seterrno (DWARF_E_NO_ENTRY); return -1; } dbg->pubnames_sets = (struct pubnames_s *) realloc (mem, cnt * entsize); dbg->pubnames_nsets = cnt; return 0; }
int internal_function __libdw_formref (Dwarf_Attribute *attr, Dwarf_Off *return_offset) { const unsigned char *datap = attr->valp; const unsigned char *endp = attr->cu->endp; if (attr->valp == NULL) { __libdw_seterrno (DWARF_E_INVALID_REFERENCE); return -1; } switch (attr->form) { case DW_FORM_ref1: if (datap + 1 > endp) { invalid: __libdw_seterrno (DWARF_E_INVALID_DWARF); return -1; } *return_offset = *attr->valp; break; case DW_FORM_ref2: if (datap + 2 > endp) goto invalid; *return_offset = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); break; case DW_FORM_ref4: if (datap + 4 > endp) goto invalid; *return_offset = read_4ubyte_unaligned (attr->cu->dbg, attr->valp); break; case DW_FORM_ref8: if (datap + 8 > endp) goto invalid; *return_offset = read_8ubyte_unaligned (attr->cu->dbg, attr->valp); break; case DW_FORM_ref_udata: if (datap + 1 > endp) goto invalid; get_uleb128 (*return_offset, datap, endp); break; case DW_FORM_ref_addr: case DW_FORM_ref_sig8: case DW_FORM_GNU_ref_alt: /* These aren't handled by dwarf_formref, only by dwarf_formref_die. */ __libdw_seterrno (DWARF_E_INVALID_REFERENCE); return -1; default: __libdw_seterrno (DWARF_E_NO_REFERENCE); return -1; } return 0; }
size_t internal_function __libdw_form_val_compute_len (Dwarf *dbg, struct Dwarf_CU *cu, unsigned int form, const unsigned char *valp) { const unsigned char *saved; Dwarf_Word u128; size_t result; /* NB: This doesn't cover constant form lengths, which are already handled by the inlined __libdw_form_val_len. */ switch (form) { case DW_FORM_addr: result = cu->address_size; break; case DW_FORM_ref_addr: result = cu->version == 2 ? cu->address_size : cu->offset_size; break; case DW_FORM_strp: case DW_FORM_sec_offset: case DW_FORM_GNU_ref_alt: case DW_FORM_GNU_strp_alt: result = cu->offset_size; break; case DW_FORM_block1: result = *valp + 1; break; case DW_FORM_block2: result = read_2ubyte_unaligned (dbg, valp) + 2; break; case DW_FORM_block4: result = read_4ubyte_unaligned (dbg, valp) + 4; break; case DW_FORM_block: case DW_FORM_exprloc: saved = valp; get_uleb128 (u128, valp); result = u128 + (valp - saved); break; case DW_FORM_string: result = strlen ((char *) valp) + 1; break; case DW_FORM_sdata: case DW_FORM_udata: case DW_FORM_ref_udata: saved = valp; get_uleb128 (u128, valp); result = valp - saved; break; case DW_FORM_indirect: saved = valp; get_uleb128 (u128, valp); // XXX Is this really correct? result = __libdw_form_val_len (dbg, cu, u128, valp); if (result != (size_t) -1) result += valp - saved; break; default: __libdw_seterrno (DWARF_E_INVALID_DWARF); result = (size_t) -1l; break; } return result; }