Commit 9d576782 by Tom de Vries Committed by Tom de Vries

[libbacktrace] Add find_unit

Add a function that finds the unit given an offset into .debug_info.

2019-01-17  Tom de Vries  <tdevries@suse.de>

	* dwarf.c (struct unit): Add low_offset and high_offset fields.
	(struct unit_vector): New type.
	(struct dwarf_data): Add units and units_counts fields.
	(find_unit): New function.
	(find_address_ranges): Add and handle unit_tag parameter.
	(build_address_map): Add and handle units_vec parameter.
	(build_dwarf_data): Pass units_vec to build_address_map.  Store resulting
	units vector.

From-SVN: r268030
parent 674931d2
2019-01-17 Tom de Vries <tdevries@suse.de> 2019-01-17 Tom de Vries <tdevries@suse.de>
* dwarf.c (struct unit): Add low_offset and high_offset fields.
(struct unit_vector): New type.
(struct dwarf_data): Add units and units_counts fields.
(find_unit): New function.
(find_address_ranges): Add and handle unit_tag parameter.
(build_address_map): Add and handle units_vec parameter.
(build_dwarf_data): Pass units_vec to build_address_map. Store resulting
units vector.
2019-01-17 Tom de Vries <tdevries@suse.de>
PR libbacktrace/82857 PR libbacktrace/82857
* dwarf.c (read_attribute): Handle DW_FORM_GNU_strp_alt * dwarf.c (read_attribute): Handle DW_FORM_GNU_strp_alt
using altlink. using altlink.
......
...@@ -281,6 +281,12 @@ struct unit ...@@ -281,6 +281,12 @@ struct unit
/* The offset of UNIT_DATA from the start of the information for /* The offset of UNIT_DATA from the start of the information for
this compilation unit. */ this compilation unit. */
size_t unit_data_offset; size_t unit_data_offset;
/* Offset of the start of the compilation unit from the start of the
.debug_info section. */
off_t low_offset;
/* Offset of the end of the compilation unit from the start of the
.debug_info section. */
off_t high_offset;
/* DWARF version. */ /* DWARF version. */
int version; int version;
/* Whether unit is DWARF64. */ /* Whether unit is DWARF64. */
...@@ -339,6 +345,14 @@ struct unit_addrs_vector ...@@ -339,6 +345,14 @@ struct unit_addrs_vector
size_t count; size_t count;
}; };
/* A growable vector of compilation unit pointer. */
struct unit_vector
{
struct backtrace_vector vec;
size_t count;
};
/* The information we need to map a PC to a file and line. */ /* The information we need to map a PC to a file and line. */
struct dwarf_data struct dwarf_data
...@@ -353,6 +367,10 @@ struct dwarf_data ...@@ -353,6 +367,10 @@ struct dwarf_data
struct unit_addrs *addrs; struct unit_addrs *addrs;
/* Number of address ranges in list. */ /* Number of address ranges in list. */
size_t addrs_count; size_t addrs_count;
/* A sorted list of units. */
struct unit **units;
/* Number of units in the list. */
size_t units_count;
/* The unparsed .debug_info section. */ /* The unparsed .debug_info section. */
const unsigned char *dwarf_info; const unsigned char *dwarf_info;
size_t dwarf_info_size; size_t dwarf_info_size;
...@@ -866,6 +884,34 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf, ...@@ -866,6 +884,34 @@ read_attribute (enum dwarf_form form, struct dwarf_buf *buf,
} }
} }
/* Compare a unit offset against a unit for bsearch. */
static int
units_search (const void *vkey, const void *ventry)
{
const off_t *key = (const off_t *) vkey;
const struct unit *entry = *((const struct unit *const *) ventry);
off_t offset;
offset = *key;
if (offset < entry->low_offset)
return -1;
else if (offset >= entry->high_offset)
return 1;
else
return 0;
}
/* Find a unit in PU containing OFFSET. */
static struct unit *
find_unit (struct unit **pu, size_t units_count, off_t offset)
{
struct unit **u;
u = bsearch (&offset, pu, units_count, sizeof (struct unit *), units_search);
return u == NULL ? NULL : *u;
}
/* Compare function_addrs for qsort. When ranges are nested, make the /* Compare function_addrs for qsort. When ranges are nested, make the
smallest one sort last. */ smallest one sort last. */
...@@ -1298,7 +1344,8 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address, ...@@ -1298,7 +1344,8 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
size_t dwarf_ranges_size, size_t dwarf_ranges_size,
int is_bigendian, struct dwarf_data *altlink, int is_bigendian, struct dwarf_data *altlink,
backtrace_error_callback error_callback, void *data, backtrace_error_callback error_callback, void *data,
struct unit *u, struct unit_addrs_vector *addrs) struct unit *u, struct unit_addrs_vector *addrs,
enum dwarf_tag *unit_tag)
{ {
while (unit_buf->left > 0) while (unit_buf->left > 0)
{ {
...@@ -1321,6 +1368,9 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address, ...@@ -1321,6 +1368,9 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
if (abbrev == NULL) if (abbrev == NULL)
return 0; return 0;
if (unit_tag != NULL)
*unit_tag = abbrev->tag;
lowpc = 0; lowpc = 0;
have_lowpc = 0; have_lowpc = 0;
highpc = 0; highpc = 0;
...@@ -1433,7 +1483,7 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address, ...@@ -1433,7 +1483,7 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
dwarf_str, dwarf_str_size, dwarf_str, dwarf_str_size,
dwarf_ranges, dwarf_ranges_size, dwarf_ranges, dwarf_ranges_size,
is_bigendian, altlink, error_callback, data, is_bigendian, altlink, error_callback, data,
u, addrs)) u, addrs, NULL))
return 0; return 0;
} }
} }
...@@ -1453,7 +1503,8 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, ...@@ -1453,7 +1503,8 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
const unsigned char *dwarf_str, size_t dwarf_str_size, const unsigned char *dwarf_str, size_t dwarf_str_size,
int is_bigendian, struct dwarf_data *altlink, int is_bigendian, struct dwarf_data *altlink,
backtrace_error_callback error_callback, void *data, backtrace_error_callback error_callback, void *data,
struct unit_addrs_vector *addrs) struct unit_addrs_vector *addrs,
struct unit_vector *unit_vec)
{ {
struct dwarf_buf info; struct dwarf_buf info;
struct backtrace_vector units; struct backtrace_vector units;
...@@ -1461,9 +1512,12 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, ...@@ -1461,9 +1512,12 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
size_t i; size_t i;
struct unit **pu; struct unit **pu;
size_t prev_addrs_count; size_t prev_addrs_count;
off_t unit_offset = 0;
memset (&addrs->vec, 0, sizeof addrs->vec); memset (&addrs->vec, 0, sizeof addrs->vec);
memset (&unit_vec->vec, 0, sizeof unit_vec->vec);
addrs->count = 0; addrs->count = 0;
unit_vec->count = 0;
prev_addrs_count = 0; prev_addrs_count = 0;
/* Read through the .debug_info section. FIXME: Should we use the /* Read through the .debug_info section. FIXME: Should we use the
...@@ -1492,6 +1546,7 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, ...@@ -1492,6 +1546,7 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
uint64_t abbrev_offset; uint64_t abbrev_offset;
int addrsize; int addrsize;
struct unit *u; struct unit *u;
enum dwarf_tag unit_tag;
if (info.reported_underflow) if (info.reported_underflow)
goto fail; goto fail;
...@@ -1534,6 +1589,9 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, ...@@ -1534,6 +1589,9 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
addrsize = read_byte (&unit_buf); addrsize = read_byte (&unit_buf);
u->low_offset = unit_offset;
unit_offset += len + (is_dwarf64 ? 12 : 4);
u->high_offset = unit_offset;
u->unit_data = unit_buf.buf; u->unit_data = unit_buf.buf;
u->unit_data_len = unit_buf.left; u->unit_data_len = unit_buf.left;
u->unit_data_offset = unit_buf.buf - unit_data_start; u->unit_data_offset = unit_buf.buf - unit_data_start;
...@@ -1555,13 +1613,13 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, ...@@ -1555,13 +1613,13 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
dwarf_str, dwarf_str_size, dwarf_str, dwarf_str_size,
dwarf_ranges, dwarf_ranges_size, dwarf_ranges, dwarf_ranges_size,
is_bigendian, altlink, error_callback, data, is_bigendian, altlink, error_callback, data,
u, addrs)) u, addrs, &unit_tag))
goto fail; goto fail;
if (unit_buf.reported_underflow) if (unit_buf.reported_underflow)
goto fail; goto fail;
if (addrs->count > prev_addrs_count) if (addrs->count > prev_addrs_count || unit_tag == DW_TAG_partial_unit)
prev_addrs_count = addrs->count; prev_addrs_count = addrs->count;
else else
{ {
...@@ -1576,11 +1634,8 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, ...@@ -1576,11 +1634,8 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
if (info.reported_underflow) if (info.reported_underflow)
goto fail; goto fail;
// We only kept the list of units to free them on failure. On unit_vec->vec = units;
// success the units are retained, pointed to by the entries in unit_vec->count = units_count;
// addrs.
backtrace_vector_free (state, &units, error_callback, data);
return 1; return 1;
fail: fail:
...@@ -3031,21 +3086,29 @@ build_dwarf_data (struct backtrace_state *state, ...@@ -3031,21 +3086,29 @@ build_dwarf_data (struct backtrace_state *state,
struct unit_addrs_vector addrs_vec; struct unit_addrs_vector addrs_vec;
struct unit_addrs *addrs; struct unit_addrs *addrs;
size_t addrs_count; size_t addrs_count;
struct unit_vector units_vec;
struct unit **units;
size_t units_count;
struct dwarf_data *fdata; struct dwarf_data *fdata;
if (!build_address_map (state, base_address, dwarf_info, dwarf_info_size, if (!build_address_map (state, base_address, dwarf_info, dwarf_info_size,
dwarf_abbrev, dwarf_abbrev_size, dwarf_ranges, dwarf_abbrev, dwarf_abbrev_size, dwarf_ranges,
dwarf_ranges_size, dwarf_str, dwarf_str_size, dwarf_ranges_size, dwarf_str, dwarf_str_size,
is_bigendian, altlink, error_callback, data, is_bigendian, altlink, error_callback, data,
&addrs_vec)) &addrs_vec, &units_vec))
return NULL; return NULL;
if (!backtrace_vector_release (state, &addrs_vec.vec, error_callback, data)) if (!backtrace_vector_release (state, &addrs_vec.vec, error_callback, data))
return NULL; return NULL;
if (!backtrace_vector_release (state, &units_vec.vec, error_callback, data))
return NULL;
addrs = (struct unit_addrs *) addrs_vec.vec.base; addrs = (struct unit_addrs *) addrs_vec.vec.base;
units = (struct unit **) units_vec.vec.base;
addrs_count = addrs_vec.count; addrs_count = addrs_vec.count;
units_count = units_vec.count;
backtrace_qsort (addrs, addrs_count, sizeof (struct unit_addrs), backtrace_qsort (addrs, addrs_count, sizeof (struct unit_addrs),
unit_addrs_compare); unit_addrs_compare);
/* No qsort for units required, already sorted. */
fdata = ((struct dwarf_data *) fdata = ((struct dwarf_data *)
backtrace_alloc (state, sizeof (struct dwarf_data), backtrace_alloc (state, sizeof (struct dwarf_data),
...@@ -3058,6 +3121,8 @@ build_dwarf_data (struct backtrace_state *state, ...@@ -3058,6 +3121,8 @@ build_dwarf_data (struct backtrace_state *state,
fdata->base_address = base_address; fdata->base_address = base_address;
fdata->addrs = addrs; fdata->addrs = addrs;
fdata->addrs_count = addrs_count; fdata->addrs_count = addrs_count;
fdata->units = units;
fdata->units_count = units_count;
fdata->dwarf_info = dwarf_info; fdata->dwarf_info = dwarf_info;
fdata->dwarf_info_size = dwarf_info_size; fdata->dwarf_info_size = dwarf_info_size;
fdata->dwarf_line = dwarf_line; fdata->dwarf_line = dwarf_line;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment