Hi, this handles DW_FORM_GNU_ref_alt which references the .debug_info section in the .gnu_debugaltlink file.
OK for trunk? Thanks, - Tom On 11-12-18 11:14, Tom de Vries wrote: > 2018-12-10 Tom de Vries <tdevr...@suse.de> > > * dwarf.c (enum attr_val_encoding): Add ATTR_VAL_REF_ALT_INFO. > (struct unit): Add low and high fields. > (struct unit_vector): New type. > (struct dwarf_data): Add units and units_counts fields. > (read_attribute): Handle DW_FORM_GNU_ref_alt using > ATTR_VAL_REF_ALT_INFO. > (find_unit): New function. > (find_address_ranges): Add and handle unit_tag parameter. > (build_address_map): Add and handle units_vec parameter. > (read_referenced_name_1): Handle DW_FORM_GNU_ref_alt. > (build_dwarf_data): Pass units_vec to build_address_map. Store > resulting > units vector. > --- > libbacktrace/dwarf.c | 101 > ++++++++++++++++++++++++++++++++++++++++++++++----- > 1 file changed, 91 insertions(+), 10 deletions(-) > > diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c > index 99e5f4c3f51..9a0b93120c8 100644 > --- a/libbacktrace/dwarf.c > +++ b/libbacktrace/dwarf.c > @@ -143,6 +143,8 @@ enum attr_val_encoding > ATTR_VAL_REF_UNIT, > /* An offset to other data within the .dwarf_info section. */ > ATTR_VAL_REF_INFO, > + /* An offset to other data within the alt .dwarf_info section. */ > + ATTR_VAL_REF_ALT_INFO, > /* An offset to data in some other section. */ > ATTR_VAL_REF_SECTION, > /* A type signature. */ > @@ -281,6 +283,10 @@ struct unit > /* The offset of UNIT_DATA from the start of the information for > this compilation unit. */ > size_t unit_data_offset; > + /* Start of the compilation unit. */ > + size_t low; > + /* End of the compilation unit. */ > + size_t high; > /* DWARF version. */ > int version; > /* Whether unit is DWARF64. */ > @@ -339,6 +345,14 @@ struct unit_addrs_vector > 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. */ > > struct dwarf_data > @@ -353,6 +367,10 @@ struct dwarf_data > struct unit_addrs *addrs; > /* Number of address ranges in list. */ > 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. */ > const unsigned char *dwarf_info; > size_t dwarf_info_size; > @@ -840,7 +858,7 @@ read_attribute (enum dwarf_form form, struct dwarf_buf > *buf, > val->encoding = ATTR_VAL_NONE; > return 1; > } > - val->encoding = ATTR_VAL_REF_SECTION; > + val->encoding = ATTR_VAL_REF_ALT_INFO; > return 1; > case DW_FORM_GNU_strp_alt: > { > @@ -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 uintptr_t *key = (const uintptr_t *) vkey; > + const struct unit *entry = *((const struct unit *const *) ventry); > + uintptr_t offset; > + > + offset = *key; > + if (offset < entry->low) > + return -1; > + else if (offset >= entry->high) > + return 1; > + else > + return 0; > +} > + > +/* Find a unit in PU containing OFFSET. */ > + > +static struct unit * > +find_unit (struct unit **pu, size_t units_count, size_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 > smallest one sort last. */ > > @@ -1299,7 +1345,7 @@ find_address_ranges (struct backtrace_state *state, > uintptr_t base_address, > int is_bigendian, backtrace_error_callback error_callback, > void *data, struct unit *u, > struct unit_addrs_vector *addrs, > - struct dwarf_data *altlink) > + struct dwarf_data *altlink, enum dwarf_tag *unit_tag) > { > while (unit_buf->left > 0) > { > @@ -1322,6 +1368,9 @@ find_address_ranges (struct backtrace_state *state, > uintptr_t base_address, > if (abbrev == NULL) > return 0; > > + if (unit_tag != NULL) > + *unit_tag = abbrev->tag; > + > lowpc = 0; > have_lowpc = 0; > highpc = 0; > @@ -1434,7 +1483,7 @@ find_address_ranges (struct backtrace_state *state, > uintptr_t base_address, > dwarf_str, dwarf_str_size, > dwarf_ranges, dwarf_ranges_size, > is_bigendian, error_callback, data, > - u, addrs, altlink)) > + u, addrs, altlink, NULL)) > return 0; > } > } > @@ -1454,6 +1503,7 @@ build_address_map (struct backtrace_state *state, > uintptr_t base_address, > const unsigned char *dwarf_str, size_t dwarf_str_size, > int is_bigendian, backtrace_error_callback error_callback, > void *data, struct unit_addrs_vector *addrs, > + struct unit_vector *unit_vec, > struct dwarf_data *altlink) > { > struct dwarf_buf info; > @@ -1462,9 +1512,12 @@ build_address_map (struct backtrace_state *state, > uintptr_t base_address, > size_t i; > struct unit **pu; > size_t prev_addrs_count; > + size_t unit_offset = 0; > > memset (&addrs->vec, 0, sizeof addrs->vec); > + memset (&unit_vec->vec, 0, sizeof unit_vec->vec); > addrs->count = 0; > + unit_vec->count = 0; > prev_addrs_count = 0; > > /* Read through the .debug_info section. FIXME: Should we use the > @@ -1493,6 +1546,7 @@ build_address_map (struct backtrace_state *state, > uintptr_t base_address, > uint64_t abbrev_offset; > int addrsize; > struct unit *u; > + enum dwarf_tag unit_tag; > > if (info.reported_underflow) > goto fail; > @@ -1535,6 +1589,9 @@ build_address_map (struct backtrace_state *state, > uintptr_t base_address, > > addrsize = read_byte (&unit_buf); > > + u->low = unit_offset; > + unit_offset += len + (is_dwarf64 ? 12 : 4); > + u->high = unit_offset; > u->unit_data = unit_buf.buf; > u->unit_data_len = unit_buf.left; > u->unit_data_offset = unit_buf.buf - unit_data_start; > @@ -1556,13 +1613,13 @@ build_address_map (struct backtrace_state *state, > uintptr_t base_address, > dwarf_str, dwarf_str_size, > dwarf_ranges, dwarf_ranges_size, > is_bigendian, error_callback, data, > - u, addrs, altlink)) > + u, addrs, altlink, &unit_tag)) > goto fail; > > if (unit_buf.reported_underflow) > goto fail; > > - if (addrs->count == prev_addrs_count) > + if (unit_tag != DW_TAG_partial_unit && addrs->count == > prev_addrs_count) > { > --units_count; > units.size -= sizeof (u); > @@ -1576,11 +1633,8 @@ build_address_map (struct backtrace_state *state, > uintptr_t base_address, > if (info.reported_underflow) > goto fail; > > - // We only kept the list of units to free them on failure. On > - // success the units are retained, pointed to by the entries in > - // addrs. > - backtrace_vector_free (state, &units, error_callback, data); > - > + unit_vec->vec = units; > + unit_vec->count = units_count; > return 1; > > fail: > @@ -2144,6 +2198,22 @@ read_referenced_name_1 (struct dwarf_data *ddata, > struct unit *u, > || val->encoding == ATTR_VAL_REF_UNIT) > return read_referenced_name (ddata, u, val->u.uint, error_callback, > data); > > + if (val->encoding == ATTR_VAL_REF_ALT_INFO) > + { > + struct unit *alt_unit > + = find_unit (ddata->altlink->units, ddata->altlink->units_count, > + val->u.uint); > + if (alt_unit == NULL) > + { > + error_callback (data, > + "Could not find unit for DW_FORM_GNU_ref_alt", 0); > + return NULL; > + } > + uint64_t unit_offset = val->u.uint - alt_unit->low; > + return read_referenced_name (ddata->altlink, alt_unit, unit_offset, > + error_callback, data); > + } > + > return NULL; > } > > @@ -3028,21 +3098,30 @@ build_dwarf_data (struct backtrace_state *state, > struct unit_addrs_vector addrs_vec; > struct unit_addrs *addrs; > size_t addrs_count; > + struct unit_vector units_vec; > + struct unit **units; > + size_t units_count; > struct dwarf_data *fdata; > > if (!build_address_map (state, base_address, dwarf_info, dwarf_info_size, > dwarf_abbrev, dwarf_abbrev_size, dwarf_ranges, > dwarf_ranges_size, dwarf_str, dwarf_str_size, > is_bigendian, error_callback, data, &addrs_vec, > + &units_vec, > altlink)) > return NULL; > > if (!backtrace_vector_release (state, &addrs_vec.vec, error_callback, > data)) > return NULL; > + if (!backtrace_vector_release (state, &units_vec.vec, error_callback, > data)) > + return NULL; > addrs = (struct unit_addrs *) addrs_vec.vec.base; > + units = (struct unit **) units_vec.vec.base; > addrs_count = addrs_vec.count; > + units_count = units_vec.count; > backtrace_qsort (addrs, addrs_count, sizeof (struct unit_addrs), > unit_addrs_compare); > + /* No qsort for units required, already sorted. */ > > fdata = ((struct dwarf_data *) > backtrace_alloc (state, sizeof (struct dwarf_data), > @@ -3055,6 +3134,8 @@ build_dwarf_data (struct backtrace_state *state, > fdata->base_address = base_address; > fdata->addrs = addrs; > fdata->addrs_count = addrs_count; > + fdata->units = units; > + fdata->units_count = units_count; > fdata->dwarf_info = dwarf_info; > fdata->dwarf_info_size = dwarf_info_size; > fdata->dwarf_line = dwarf_line; >