[libbacktrace] Add find_unit
authorTom de Vries <tdevries@suse.de>
Thu, 17 Jan 2019 13:42:09 +0000 (13:42 +0000)
committerTom de Vries <vries@gcc.gnu.org>
Thu, 17 Jan 2019 13:42:09 +0000 (13:42 +0000)
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

libbacktrace/ChangeLog
libbacktrace/dwarf.c

index 458f16c98704a6d6ec8746e474dd5c4b7ee74751..1fd307bf5128100e655dbfa155113483d8e7cfc5 100644 (file)
@@ -1,3 +1,14 @@
+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
index 45691b4ba6987eddd597c94bb25070f7e561c0ef..6f56c46774b7ef3920eec89258cfbf4fe4bc56be 100644 (file)
@@ -281,6 +281,12 @@ struct unit
   /* The offset of UNIT_DATA from the start of the information for
      this compilation unit.  */
   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.  */
   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;
@@ -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
    smallest one sort last.  */
 
@@ -1298,7 +1344,8 @@ find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
                     size_t dwarf_ranges_size,
                     int is_bigendian, struct dwarf_data *altlink,
                     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)
     {
@@ -1321,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;
@@ -1433,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, altlink, error_callback, data,
-                                   u, addrs))
+                                   u, addrs, NULL))
            return 0;
        }
     }
@@ -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,
                   int is_bigendian, struct dwarf_data *altlink,
                   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 backtrace_vector units;
@@ -1461,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;
+  off_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
@@ -1492,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;
@@ -1534,6 +1589,9 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
 
       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_len = unit_buf.left;
       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,
                                dwarf_str, dwarf_str_size,
                                dwarf_ranges, dwarf_ranges_size,
                                is_bigendian, altlink, error_callback, data,
-                               u, addrs))
+                               u, addrs, &unit_tag))
        goto fail;
 
       if (unit_buf.reported_underflow)
        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;
       else
        {
@@ -1576,11 +1634,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:
@@ -3031,21 +3086,29 @@ 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, altlink, error_callback, data,
-                         &addrs_vec))
+                         &addrs_vec, &units_vec))
     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),
@@ -3058,6 +3121,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;