summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-11-28 16:19:57 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-11-28 16:19:57 +0000
commit881a0840d023530498ca70fd85ecf69d7c89f441 (patch)
tree2ae4d566474dc53783ba4c92cf34eaa4638d28e4
parentc6a711c35b88fbed90b943a038e320e90f31eb35 (diff)
downloadgcc-881a0840d023530498ca70fd85ecf69d7c89f441.tar.gz
* dwarf.c (find_address_ranges): New static function, broken out
of build_address_map. (build_address_map): Call it. * btest.c (check): Check for missing filename or function, rather than crashing. (f3): Check that enough frames were returned. git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@205490 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--libbacktrace/ChangeLog9
-rw-r--r--libbacktrace/btest.c15
-rw-r--r--libbacktrace/dwarf.c340
3 files changed, 208 insertions, 156 deletions
diff --git a/libbacktrace/ChangeLog b/libbacktrace/ChangeLog
index 79ac1178f80..3b86043fbfb 100644
--- a/libbacktrace/ChangeLog
+++ b/libbacktrace/ChangeLog
@@ -1,3 +1,12 @@
+2013-11-27 Ian Lance Taylor <iant@google.com>
+
+ * dwarf.c (find_address_ranges): New static function, broken out
+ of build_address_map.
+ (build_address_map): Call it.
+ * btest.c (check): Check for missing filename or function, rather
+ than crashing.
+ (f3): Check that enough frames were returned.
+
2013-11-19 Jakub Jelinek <jakub@redhat.com>
* backtrace.h (backtrace_syminfo_callback): Add symsize argument.
diff --git a/libbacktrace/btest.c b/libbacktrace/btest.c
index 22b08e05030..17fea3061f5 100644
--- a/libbacktrace/btest.c
+++ b/libbacktrace/btest.c
@@ -129,6 +129,13 @@ check (const char *name, int index, const struct info *all, int want_lineno,
{
if (*failed)
return;
+ if (all[index].filename == NULL || all[index].function == NULL)
+ {
+ fprintf (stderr, "%s: [%d]: missing file name or function name\n",
+ name, index);
+ *failed = 1;
+ return;
+ }
if (strcmp (base (all[index].filename), "btest.c") != 0)
{
fprintf (stderr, "%s: [%d]: got %s expected test.c\n", name, index,
@@ -310,6 +317,14 @@ f3 (int f1line, int f2line)
data.failed = 1;
}
+ if (data.index < 3)
+ {
+ fprintf (stderr,
+ "test1: not enough frames; got %zu, expected at least 3\n",
+ data.index);
+ data.failed = 1;
+ }
+
check ("test1", 0, all, f3line, "f3", &data.failed);
check ("test1", 1, all, f2line, "f2", &data.failed);
check ("test1", 2, all, f1line, "test1", &data.failed);
diff --git a/libbacktrace/dwarf.c b/libbacktrace/dwarf.c
index 0aba2d3f574..f9c3b3723e7 100644
--- a/libbacktrace/dwarf.c
+++ b/libbacktrace/dwarf.c
@@ -1235,54 +1235,24 @@ add_unit_ranges (struct backtrace_state *state, uintptr_t base_address,
return 1;
}
-/* Build a mapping from address ranges to the compilation units where
- the line number information for that range can be found. Returns 1
- on success, 0 on failure. */
+/* Find the address range covered by a compilation unit, reading from
+ UNIT_BUF and adding values to U. Returns 1 if all data could be
+ read, 0 if there is some error. */
static int
-build_address_map (struct backtrace_state *state, uintptr_t base_address,
- const unsigned char *dwarf_info, size_t dwarf_info_size,
- const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size,
- const unsigned char *dwarf_ranges, size_t dwarf_ranges_size,
- 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)
+find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
+ struct dwarf_buf *unit_buf,
+ const unsigned char *dwarf_str, size_t dwarf_str_size,
+ const unsigned char *dwarf_ranges,
+ size_t dwarf_ranges_size,
+ int is_bigendian, backtrace_error_callback error_callback,
+ void *data, struct unit *u,
+ struct unit_addrs_vector *addrs)
{
- struct dwarf_buf info;
- struct abbrevs abbrevs;
-
- memset (&addrs->vec, 0, sizeof addrs->vec);
- addrs->count = 0;
-
- /* Read through the .debug_info section. FIXME: Should we use the
- .debug_aranges section? gdb and addr2line don't use it, but I'm
- not sure why. */
-
- info.name = ".debug_info";
- info.start = dwarf_info;
- info.buf = dwarf_info;
- info.left = dwarf_info_size;
- info.is_bigendian = is_bigendian;
- info.error_callback = error_callback;
- info.data = data;
- info.reported_underflow = 0;
-
- memset (&abbrevs, 0, sizeof abbrevs);
- while (info.left > 0)
+ while (unit_buf->left > 0)
{
- const unsigned char *unit_data_start;
- uint64_t len;
- int is_dwarf64;
- struct dwarf_buf unit_buf;
- int version;
- uint64_t abbrev_offset;
- const struct abbrev *abbrev;
- int addrsize;
- const unsigned char *unit_data;
- size_t unit_data_len;
- size_t unit_data_offset;
uint64_t code;
- size_t i;
+ const struct abbrev *abbrev;
uint64_t lowpc;
int have_lowpc;
uint64_t highpc;
@@ -1290,57 +1260,15 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
int highpc_is_relative;
uint64_t ranges;
int have_ranges;
- uint64_t lineoff;
- int have_lineoff;
- const char *filename;
- const char *comp_dir;
-
- if (info.reported_underflow)
- goto fail;
-
- unit_data_start = info.buf;
-
- is_dwarf64 = 0;
- len = read_uint32 (&info);
- if (len == 0xffffffff)
- {
- len = read_uint64 (&info);
- is_dwarf64 = 1;
- }
-
- unit_buf = info;
- unit_buf.left = len;
-
- if (!advance (&info, len))
- goto fail;
-
- version = read_uint16 (&unit_buf);
- if (version < 2 || version > 4)
- {
- dwarf_buf_error (&unit_buf, "unrecognized DWARF version");
- goto fail;
- }
-
- abbrev_offset = read_offset (&unit_buf, is_dwarf64);
- if (!read_abbrevs (state, abbrev_offset, dwarf_abbrev, dwarf_abbrev_size,
- is_bigendian, error_callback, data, &abbrevs))
- goto fail;
-
- addrsize = read_byte (&unit_buf);
-
- unit_data = unit_buf.buf;
- unit_data_len = unit_buf.left;
- unit_data_offset = unit_buf.buf - unit_data_start;
+ size_t i;
- /* We only look at the first attribute in the compilation unit.
- In practice this will be a DW_TAG_compile_unit which will
- tell us the PC range and where to find the line number
- information. */
+ code = read_uleb128 (unit_buf);
+ if (code == 0)
+ return 1;
- code = read_uleb128 (&unit_buf);
- abbrev = lookup_abbrev (&abbrevs, code, error_callback, data);
+ abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data);
if (abbrev == NULL)
- goto fail;
+ return 0;
lowpc = 0;
have_lowpc = 0;
@@ -1349,18 +1277,14 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
highpc_is_relative = 0;
ranges = 0;
have_ranges = 0;
- lineoff = 0;
- have_lineoff = 0;
- filename = NULL;
- comp_dir = NULL;
for (i = 0; i < abbrev->num_attrs; ++i)
{
struct attr_val val;
- if (!read_attribute (abbrev->attrs[i].form, &unit_buf, is_dwarf64,
- version, addrsize, dwarf_str, dwarf_str_size,
- &val))
- goto fail;
+ if (!read_attribute (abbrev->attrs[i].form, unit_buf,
+ u->is_dwarf64, u->version, u->addrsize,
+ dwarf_str, dwarf_str_size, &val))
+ return 0;
switch (abbrev->attrs[i].name)
{
@@ -1371,6 +1295,7 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
have_lowpc = 1;
}
break;
+
case DW_AT_high_pc:
if (val.encoding == ATTR_VAL_ADDRESS)
{
@@ -1384,6 +1309,7 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
highpc_is_relative = 1;
}
break;
+
case DW_AT_ranges:
if (val.encoding == ATTR_VAL_UINT
|| val.encoding == ATTR_VAL_REF_SECTION)
@@ -1392,73 +1318,46 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
have_ranges = 1;
}
break;
+
case DW_AT_stmt_list:
- if (val.encoding == ATTR_VAL_UINT
- || val.encoding == ATTR_VAL_REF_SECTION)
- {
- lineoff = val.u.uint;
- have_lineoff = 1;
- }
+ if (abbrev->tag == DW_TAG_compile_unit
+ && (val.encoding == ATTR_VAL_UINT
+ || val.encoding == ATTR_VAL_REF_SECTION))
+ u->lineoff = val.u.uint;
break;
+
case DW_AT_name:
- if (val.encoding == ATTR_VAL_STRING)
- filename = val.u.string;
+ if (abbrev->tag == DW_TAG_compile_unit
+ && val.encoding == ATTR_VAL_STRING)
+ u->filename = val.u.string;
break;
+
case DW_AT_comp_dir:
- if (val.encoding == ATTR_VAL_STRING)
- comp_dir = val.u.string;
+ if (abbrev->tag == DW_TAG_compile_unit
+ && val.encoding == ATTR_VAL_STRING)
+ u->comp_dir = val.u.string;
break;
+
default:
break;
}
}
- if (unit_buf.reported_underflow)
- goto fail;
-
- if (((have_lowpc && have_highpc) || have_ranges) && have_lineoff)
+ if (abbrev->tag == DW_TAG_compile_unit
+ || abbrev->tag == DW_TAG_subprogram)
{
- struct unit *u;
- struct unit_addrs a;
-
- u = ((struct unit *)
- backtrace_alloc (state, sizeof *u, error_callback, data));
- if (u == NULL)
- goto fail;
- u->unit_data = unit_data;
- u->unit_data_len = unit_data_len;
- u->unit_data_offset = unit_data_offset;
- u->version = version;
- u->is_dwarf64 = is_dwarf64;
- u->addrsize = addrsize;
- u->filename = filename;
- u->comp_dir = comp_dir;
- u->abs_filename = NULL;
- u->lineoff = lineoff;
- u->abbrevs = abbrevs;
- memset (&abbrevs, 0, sizeof abbrevs);
-
- /* The actual line number mappings will be read as
- needed. */
- u->lines = NULL;
- u->lines_count = 0;
- u->function_addrs = NULL;
- u->function_addrs_count = 0;
-
if (have_ranges)
{
if (!add_unit_ranges (state, base_address, u, ranges, lowpc,
is_bigendian, dwarf_ranges,
- dwarf_ranges_size, error_callback, data,
- addrs))
- {
- free_abbrevs (state, &u->abbrevs, error_callback, data);
- backtrace_free (state, u, sizeof *u, error_callback, data);
- goto fail;
- }
+ dwarf_ranges_size, error_callback,
+ data, addrs))
+ return 0;
}
- else
+ else if (have_lowpc && have_highpc)
{
+ struct unit_addrs a;
+
if (highpc_is_relative)
highpc += lowpc;
a.low = lowpc;
@@ -1467,17 +1366,146 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
if (!add_unit_addr (state, base_address, a, error_callback, data,
addrs))
- {
- free_abbrevs (state, &u->abbrevs, error_callback, data);
- backtrace_free (state, u, sizeof *u, error_callback, data);
- goto fail;
- }
+ return 0;
}
+
+ /* If we found the PC range in the DW_TAG_compile_unit, we
+ can stop now. */
+ if (abbrev->tag == DW_TAG_compile_unit
+ && (have_ranges || (have_lowpc && have_highpc)))
+ return 1;
}
- else
+
+ if (abbrev->has_children)
{
- free_abbrevs (state, &abbrevs, error_callback, data);
- memset (&abbrevs, 0, sizeof abbrevs);
+ if (!find_address_ranges (state, base_address, unit_buf,
+ dwarf_str, dwarf_str_size,
+ dwarf_ranges, dwarf_ranges_size,
+ is_bigendian, error_callback, data,
+ u, addrs))
+ return 0;
+ }
+ }
+
+ return 1;
+}
+
+/* Build a mapping from address ranges to the compilation units where
+ the line number information for that range can be found. Returns 1
+ on success, 0 on failure. */
+
+static int
+build_address_map (struct backtrace_state *state, uintptr_t base_address,
+ const unsigned char *dwarf_info, size_t dwarf_info_size,
+ const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size,
+ const unsigned char *dwarf_ranges, size_t dwarf_ranges_size,
+ 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 dwarf_buf info;
+ struct abbrevs abbrevs;
+
+ memset (&addrs->vec, 0, sizeof addrs->vec);
+ addrs->count = 0;
+
+ /* Read through the .debug_info section. FIXME: Should we use the
+ .debug_aranges section? gdb and addr2line don't use it, but I'm
+ not sure why. */
+
+ info.name = ".debug_info";
+ info.start = dwarf_info;
+ info.buf = dwarf_info;
+ info.left = dwarf_info_size;
+ info.is_bigendian = is_bigendian;
+ info.error_callback = error_callback;
+ info.data = data;
+ info.reported_underflow = 0;
+
+ memset (&abbrevs, 0, sizeof abbrevs);
+ while (info.left > 0)
+ {
+ const unsigned char *unit_data_start;
+ uint64_t len;
+ int is_dwarf64;
+ struct dwarf_buf unit_buf;
+ int version;
+ uint64_t abbrev_offset;
+ int addrsize;
+ struct unit *u;
+
+ if (info.reported_underflow)
+ goto fail;
+
+ unit_data_start = info.buf;
+
+ is_dwarf64 = 0;
+ len = read_uint32 (&info);
+ if (len == 0xffffffff)
+ {
+ len = read_uint64 (&info);
+ is_dwarf64 = 1;
+ }
+
+ unit_buf = info;
+ unit_buf.left = len;
+
+ if (!advance (&info, len))
+ goto fail;
+
+ version = read_uint16 (&unit_buf);
+ if (version < 2 || version > 4)
+ {
+ dwarf_buf_error (&unit_buf, "unrecognized DWARF version");
+ goto fail;
+ }
+
+ abbrev_offset = read_offset (&unit_buf, is_dwarf64);
+ if (!read_abbrevs (state, abbrev_offset, dwarf_abbrev, dwarf_abbrev_size,
+ is_bigendian, error_callback, data, &abbrevs))
+ goto fail;
+
+ addrsize = read_byte (&unit_buf);
+
+ u = ((struct unit *)
+ backtrace_alloc (state, sizeof *u, error_callback, data));
+ if (u == NULL)
+ goto fail;
+ u->unit_data = unit_buf.buf;
+ u->unit_data_len = unit_buf.left;
+ u->unit_data_offset = unit_buf.buf - unit_data_start;
+ u->version = version;
+ u->is_dwarf64 = is_dwarf64;
+ u->addrsize = addrsize;
+ u->filename = NULL;
+ u->comp_dir = NULL;
+ u->abs_filename = NULL;
+ u->lineoff = 0;
+ u->abbrevs = abbrevs;
+ memset (&abbrevs, 0, sizeof abbrevs);
+
+ /* The actual line number mappings will be read as needed. */
+ u->lines = NULL;
+ u->lines_count = 0;
+ u->function_addrs = NULL;
+ u->function_addrs_count = 0;
+
+ if (!find_address_ranges (state, base_address, &unit_buf,
+ dwarf_str, dwarf_str_size,
+ dwarf_ranges, dwarf_ranges_size,
+ is_bigendian, error_callback, data,
+ u, addrs))
+ {
+ free_abbrevs (state, &u->abbrevs, error_callback, data);
+ backtrace_free (state, u, sizeof *u, error_callback, data);
+ goto fail;
+ }
+
+ if (unit_buf.reported_underflow)
+ {
+ free_abbrevs (state, &u->abbrevs, error_callback, data);
+ backtrace_free (state, u, sizeof *u, error_callback, data);
+ goto fail;
}
}
if (info.reported_underflow)