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 dwarf_formudata (Dwarf_Attribute *attr, Dwarf_Word *return_uval) { if (attr == NULL) return -1; const unsigned char *datap = attr->valp; const unsigned char *endp = attr->cu->endp; switch (attr->form) { case DW_FORM_data1: if (datap + 1 > endp) { invalid: __libdw_seterrno (DWARF_E_INVALID_DWARF); return -1; } *return_uval = *attr->valp; break; case DW_FORM_data2: if (datap + 2 > endp) goto invalid; *return_uval = read_2ubyte_unaligned (attr->cu->dbg, attr->valp); break; case DW_FORM_data4: case DW_FORM_data8: case DW_FORM_sec_offset: /* Before DWARF4 data4 and data8 are pure constants unless the attribute also allows offsets (*ptr classes), since DWARF4 they are always just constants (start_scope is special though, since it only could express a rangelist since DWARF4). */ if (attr->form == DW_FORM_sec_offset || (attr->cu->version < 4 && attr->code != DW_AT_start_scope)) { switch (attr->code) { case DW_AT_data_member_location: case DW_AT_frame_base: case DW_AT_location: case DW_AT_return_addr: case DW_AT_segment: case DW_AT_static_link: case DW_AT_string_length: case DW_AT_use_location: case DW_AT_vtable_elem_location: /* loclistptr */ if (__libdw_formptr (attr, IDX_debug_loc, DWARF_E_NO_LOCLIST, NULL, return_uval) == NULL) return -1; break; case DW_AT_macro_info: /* macptr into .debug_macinfo */ if (__libdw_formptr (attr, IDX_debug_macinfo, DWARF_E_NO_ENTRY, NULL, return_uval) == NULL) return -1; break; case DW_AT_GNU_macros: /* macptr into .debug_macro */ if (__libdw_formptr (attr, IDX_debug_macro, DWARF_E_NO_ENTRY, NULL, return_uval) == NULL) return -1; break; case DW_AT_ranges: case DW_AT_start_scope: /* rangelistptr */ if (__libdw_formptr (attr, IDX_debug_ranges, DWARF_E_NO_DEBUG_RANGES, NULL, return_uval) == NULL) return -1; break; case DW_AT_stmt_list: /* lineptr */ if (__libdw_formptr (attr, IDX_debug_line, DWARF_E_NO_DEBUG_LINE, NULL, return_uval) == NULL) return -1; break; default: /* sec_offset can only be used by one of the above attrs. */ if (attr->form == DW_FORM_sec_offset) { __libdw_seterrno (DWARF_E_INVALID_DWARF); return -1; } /* Not one of the special attributes, just a constant. */ if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu), attr->valp, attr->form == DW_FORM_data4 ? 4 : 8, return_uval)) return -1; break; } } else { /* We are dealing with a constant data4 or data8. */ if (__libdw_read_address (attr->cu->dbg, cu_sec_idx (attr->cu), attr->valp, attr->form == DW_FORM_data4 ? 4 : 8, return_uval)) return -1; } break; case DW_FORM_sdata: if (datap + 1 > endp) goto invalid; get_sleb128 (*return_uval, datap, endp); break; case DW_FORM_udata: if (datap + 1 > endp) goto invalid; get_uleb128 (*return_uval, datap, endp); break; default: __libdw_seterrno (DWARF_E_NO_CONSTANT); return -1; } 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; }