break;
case DW_FORM_block4:
- if (__libdw_read_length (attr->cu->dbg, IDX_debug_info, attr->valp,
- 4, &return_block->length))
- return -1;
+ return_block->length = read_4ubyte_unaligned (attr->cu->dbg, attr->valp);
return_block->data = attr->valp + 4;
break;
break;
case DW_FORM_ref4:
+ *return_offset = read_4ubyte_unaligned (attr->cu->dbg, attr->valp);
+ break;
+
case DW_FORM_ref8:
- if (__libdw_read_offset (attr->cu->dbg, IDX_debug_info, attr->valp,
- attr->form == DW_FORM_ref4 ? 4 : 8,
- return_offset))
- return -1;
+ *return_offset = read_8ubyte_unaligned (attr->cu->dbg, attr->valp);
break;
case DW_FORM_ref_udata:
? attr->cu->address_size
: attr->cu->offset_size);
- if (__libdw_read_address (attr->cu->dbg,
- IDX_debug_info, attr->valp,
- ref_size, &offset))
+ if (__libdw_read_offset (attr->cu->dbg,
+ IDX_debug_info, attr->valp,
+ ref_size, &offset, IDX_debug_info))
return NULL;
}
else
if (unlikely (attrp->form != DW_FORM_strp)
|| dbg->sectiondata[IDX_debug_str] == NULL)
{
- invalid_error:
__libdw_seterrno (DWARF_E_NO_STRING);
return NULL;
}
uint64_t off;
if (__libdw_read_offset (dbg, IDX_debug_info, attrp->valp,
- attrp->cu->offset_size, &off))
+ attrp->cu->offset_size, &off, IDX_debug_str))
return NULL;
- if (off >= dbg->sectiondata[IDX_debug_str]->d_size)
- goto invalid_error;
-
return (const char *) dbg->sectiondata[IDX_debug_str]->d_buf + off;
}
INTDEF(dwarf_formstring)
case DW_FORM_data4:
case DW_FORM_data8:
- if (__libdw_read_offset (attr->cu->dbg, IDX_debug_info, attr->valp,
- attr->form == DW_FORM_data4 ? 4 : 8,
- return_uval))
+ if (__libdw_read_address (attr->cu->dbg, IDX_debug_info, attr->valp,
+ attr->form == DW_FORM_data4 ? 4 : 8,
+ return_uval))
return -1;
break;
Dwarf_Word offset;
if (__libdw_read_offset_inc (dbg,
IDX_debug_aranges, (unsigned char **)&readp,
- length_bytes, &offset))
+ length_bytes, &offset, IDX_debug_info))
return -1;
- /* Sanity-check the offset. */
- if (offset + 4 > dbg->sectiondata[IDX_debug_info]->d_size)
- goto invalid;
-
unsigned int address_size = *readp++;
if (address_size != 4 && address_size != 8)
goto invalid;
if (__libdw_read_address_inc (dbg, IDX_debug_aranges,
(unsigned char **)&readp,
- address_size, &range_address)
- || __libdw_read_length_inc (dbg, IDX_debug_aranges,
- (unsigned char **)&readp,
- address_size, &range_length))
+ address_size, &range_address))
return -1;
+ if (address_size == 4)
+ range_length = read_4ubyte_unaligned_inc (dbg, readp);
+ else
+ range_length = read_8ubyte_unaligned_inc (dbg, readp);
+
/* Two zero values mark the end. */
if (range_address == 0 && range_length == 0)
break;
Dwarf_Addr begin;
Dwarf_Addr end;
- Dwarf_Addr escape = ADDR_ESCAPE (attr->cu->address_size);
-
- if (__libdw_read_address_inc (attr->cu->dbg,
- IDX_debug_line, &readp,
- attr->cu->address_size, &begin)
- || __libdw_read_address_inc (attr->cu->dbg,
- IDX_debug_line, &readp,
- attr->cu->address_size, &end))
- goto invalid;
-
- if (begin == escape)
- {
- base = end;
- if (unlikely (base == escape))
- goto invalid;
- continue;
- }
- if (begin == 0 && end == 0) /* End of list entry. */
+ int status
+ = __libdw_read_begin_end_pair_inc (attr->cu->dbg, IDX_debug_loc,
+ &readp, attr->cu->address_size,
+ &begin, &end, &base);
+ if (status == 2) /* End of list entry. */
break;
+ else if (status == 1) /* Base address selected. */
+ continue;
+ else if (status < 0)
+ return status;
if ((unsigned char *) d->d_buf + d->d_size - readp < 2)
goto invalid;
if (llbufs != NULL
&& unlikely (getlocation (attr->cu, &block,
&llbufs[got], &listlens[got],
- IDX_debug_line) != 0))
+ IDX_debug_loc) != 0))
return -1;
++got;
}
}
/* Get the CU offset. */
- if (__libdw_read_address (dbg, IDX_debug_pubnames, readp + 2, len_bytes,
- &mem[cnt].cu_offset))
+ if (__libdw_read_offset (dbg, IDX_debug_pubnames, readp + 2, len_bytes,
+ &mem[cnt].cu_offset, IDX_debug_info))
/* Error has been already set in reader. */
goto err_return;
/* 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)))
+ || dbg->sectiondata[IDX_debug_info]->d_buf == NULL))
goto invalid_dwarf;
unsigned char *infop
while (1)
{
/* READP points to the next offset/name pair. */
- if (__libdw_read_address_inc (dbg, IDX_debug_pubnames, &readp,
- dbg->pubnames_sets[cnt].address_len,
- &gl.die_offset))
- return -1l;
+ if (dbg->pubnames_sets[cnt].address_len == 4)
+ gl.die_offset = read_4ubyte_unaligned_inc (dbg, readp);
+ else
+ gl.die_offset = read_8ubyte_unaligned_inc (dbg, readp);
/* If the offset is zero we reached the end of the set. */
if (gl.die_offset == 0)
/* This points into the .debug_info section to the beginning of the
CU entry. */
- unsigned char *data = (unsigned char *) dwarf->sectiondata[IDX_debug_info]->d_buf;
+ unsigned char *data = dwarf->sectiondata[IDX_debug_info]->d_buf;
unsigned char *bytes = data + off;
/* The format of the CU header is described in dwarf2p1 7.5.1:
depends on whether this is a 32-bit or 64-bit DWARF definition. */
uint64_t abbrev_offset;
if (__libdw_read_offset_inc (dwarf, IDX_debug_info, &bytes,
- offset_size, &abbrev_offset))
+ offset_size, &abbrev_offset, IDX_debug_abbrev))
return -1;
if (abbrev_offsetp != NULL)
#include <dwarf.h>
#include <assert.h>
+/* Read up begin/end pair and increment read pointer.
+ - If it's normal range record, set up `*beginp' and `*endp' and return 0.
+ - If it's base address selection record, set up `*basep' and return 1.
+ - If it's end of rangelist, don't set anything and return 2
+ - If an error occurs, don't set anything and return -1. */
+internal_function int
+__libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
+ unsigned char **addr, int width,
+ Dwarf_Addr *beginp, Dwarf_Addr *endp,
+ Dwarf_Addr *basep)
+{
+ Dwarf_Addr escape
+ = width == 8 ? (Elf64_Addr) -1 : (Elf64_Addr) (Elf32_Addr) -1;
+ Dwarf_Addr begin, end;
+
+ bool begin_relocated
+ = !READ_AND_RELOCATE (__libdw_relocate_address, begin);
+ bool end_relocated
+ = !READ_AND_RELOCATE (__libdw_relocate_address, end);
+
+ /* Unrelocated escape for begin means base address selection. */
+ if (begin == escape && !begin_relocated)
+ {
+ if (unlikely (end == escape))
+ {
+ __libdw_seterrno (DWARF_E_INVALID_DWARF);
+ return -1;
+ }
+
+ if (basep != NULL)
+ *basep = end;
+ return 1;
+ }
+
+ /* Unrelocated pair of zeroes means end of range list. */
+ if (begin == 0 && end == 0 && !begin_relocated && !end_relocated)
+ return 2;
+
+ /* Don't check for begin_relocated == end_relocated. Serve the data
+ to the client even though it may be buggy. */
+ *beginp = begin;
+ *endp = end;
+
+ return 0;
+}
ptrdiff_t
dwarf_ranges (Dwarf_Die *die, ptrdiff_t offset, Dwarf_Addr *basep,
Dwarf_Addr begin;
Dwarf_Addr end;
- if (__libdw_read_address_inc (die->cu->dbg,
- IDX_debug_ranges, &readp,
- die->cu->address_size, &begin)
- || __libdw_read_address_inc (die->cu->dbg,
- IDX_debug_ranges, &readp,
- die->cu->address_size, &end))
- return -1l;
-
- if (begin == ADDR_ESCAPE (die->cu->address_size))
+
+ switch (__libdw_read_begin_end_pair_inc (die->cu->dbg, IDX_debug_ranges,
+ &readp, die->cu->address_size,
+ &begin, &end, basep))
{
- *basep = end;
+ case 0:
+ break;
+ case 1:
goto next;
+ case 2:
+ return 0;
+ default:
+ return -1l;
}
- if (begin == 0 && end == 0) /* End of list entry. */
- return 0;
-
/* We have an address range entry. */
*startp = *basep + begin;
*endp = *basep + end;
/* Reader hooks. */
-static inline int
+static inline bool
__libdw_in_section (Dwarf *dbg, int sec_index,
unsigned char *addr, int width)
{
|| (void *)addr + width > data->d_buf + data->d_size)
{
__libdw_seterrno (DWARF_E_INVALID_OFFSET);
- return 1;
+ return false;
}
- return 0;
+ return true;
}
+/* Relocation hooks return -1 on error, 0 if there is no relocation
+ and 1 if a relocation was present.*/
int __libdw_relocate_address (Dwarf *dbg,
int sec_index, uintptr_t addr,
int width, Dwarf_Addr *val)
int width, Dwarf_Off *val)
internal_function;
-int __libdw_relocate_length (Dwarf *dbg,
- int sec_index, uintptr_t addr,
- int width, Dwarf_Addr *val)
- internal_function;
-
-#define READ_AND_RELOCATE(RELOC_HOOK) \
- { \
- int status; \
- if ((status = __libdw_in_section (dbg, sec_index, *addr, width))) \
- return status; \
+#define READ_AND_RELOCATE(RELOC_HOOK, VAL) \
+ ({ \
+ if (!__libdw_in_section (dbg, sec_index, *addr, width)) \
+ return -1; \
\
- uintptr_t addr0 = (uintptr_t)*addr; \
- __typeof (*ret) val; \
+ uintptr_t addr0 = (uintptr_t) *addr; \
\
if (width == 4) \
- val = read_4ubyte_unaligned_inc (dbg, *addr); \
+ VAL = read_4ubyte_unaligned_inc (dbg, *addr); \
else \
{ \
assert (width == 8); \
- val = read_8ubyte_unaligned_inc (dbg, *addr); \
+ VAL = read_8ubyte_unaligned_inc (dbg, *addr); \
} \
\
- if ((status = RELOC_HOOK (dbg, sec_index, addr0, width, &val))) \
+ int status = RELOC_HOOK (dbg, sec_index, addr0, width, &VAL); \
+ if (status == -1) \
return status; \
- \
- *ret = val; \
- return 0; \
- }
+ status; \
+ })
static inline int
__libdw_read_address_inc (Dwarf *dbg,
int sec_index, unsigned char **addr,
int width, Dwarf_Addr *ret)
{
- READ_AND_RELOCATE (__libdw_relocate_address)
+ Dwarf_Addr val;
+ READ_AND_RELOCATE (__libdw_relocate_address, val);
+ *ret = val;
+ return 0;
}
static inline int
__libdw_read_offset_inc (Dwarf *dbg,
int sec_index, unsigned char **addr,
- int width, Dwarf_Off *ret)
+ int width, Dwarf_Off *ret, int sec_ret)
{
- READ_AND_RELOCATE (__libdw_relocate_offset)
-}
+ Dwarf_Off val;
+ READ_AND_RELOCATE (__libdw_relocate_offset, val);
-static inline int
-__libdw_read_length_inc (Dwarf *dbg,
- int sec_index, unsigned char **addr,
- int width, Dwarf_Addr *ret)
-{
- READ_AND_RELOCATE (__libdw_relocate_length)
+ Elf_Data *data = dbg->sectiondata[sec_ret];
+ if (!__libdw_in_section (dbg, sec_ret, data->d_buf + val, width))
+ return -1;
+
+ *ret = val;
+ return 0;
}
-#undef READ_AND_RELOCATE
+/* Read up begin/end pair and increment read pointer.
+ - If it's normal range record, set up `*beginp' and `*endp' and return 0.
+ - If it's base address selection record, set up `*basep' and return 1.
+ - If it's end of rangelist, don't set anything and return 2
+ - If an error occurs, don't set anything and return <0. */
+int
+__libdw_read_begin_end_pair_inc (Dwarf *dbg, int sec_index,
+ unsigned char **addr, int width,
+ Dwarf_Addr *beginp, Dwarf_Addr *endp,
+ Dwarf_Addr *basep)
+ internal_function;
static inline int
__libdw_read_address (Dwarf *dbg,
static inline int
__libdw_read_offset (Dwarf *dbg,
int sec_index, const unsigned char *addr,
- int width, Dwarf_Addr *ret)
+ int width, Dwarf_Off *ret, int sec_ret)
{
return __libdw_read_offset_inc (dbg, sec_index, (unsigned char **)&addr,
- width, ret);
+ width, ret, sec_ret);
}
-static inline int
-__libdw_read_length (Dwarf *dbg,
- int sec_index, const unsigned char *addr,
- int width, Dwarf_Word *ret)
-{
- return __libdw_read_length_inc (dbg, sec_index, (unsigned char **)&addr,
- width, ret);
-}
-
-#define ADDR_ESCAPE(width) \
- (width == 8 ? (Elf64_Addr)-1 : (Elf64_Addr)(Elf32_Addr)-1)
-
/* Aliases to avoid PLTs. */
{
return 0;
}
-
-internal_function int
-__libdw_relocate_length (Dwarf *dbg __attribute__ ((unused)),
- int sec_index __attribute__ ((unused)),
- uintptr_t addr __attribute__ ((unused)),
- int width __attribute__ ((unused)),
- Dwarf_Addr *val __attribute__ ((unused)))
-{
- return 0;
-}