Commit b8ddd61b by Ian Lance Taylor Committed by Ian Lance Taylor

dwarf.c (find_address_ranges): New static function, broken out of build_address_map.

	* 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.

From-SVN: r205490
parent f5c8b24c
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> 2013-11-19 Jakub Jelinek <jakub@redhat.com>
* backtrace.h (backtrace_syminfo_callback): Add symsize argument. * backtrace.h (backtrace_syminfo_callback): Add symsize argument.
......
...@@ -129,6 +129,13 @@ check (const char *name, int index, const struct info *all, int want_lineno, ...@@ -129,6 +129,13 @@ check (const char *name, int index, const struct info *all, int want_lineno,
{ {
if (*failed) if (*failed)
return; 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) if (strcmp (base (all[index].filename), "btest.c") != 0)
{ {
fprintf (stderr, "%s: [%d]: got %s expected test.c\n", name, index, fprintf (stderr, "%s: [%d]: got %s expected test.c\n", name, index,
...@@ -310,6 +317,14 @@ f3 (int f1line, int f2line) ...@@ -310,6 +317,14 @@ f3 (int f1line, int f2line)
data.failed = 1; 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", 0, all, f3line, "f3", &data.failed);
check ("test1", 1, all, f2line, "f2", &data.failed); check ("test1", 1, all, f2line, "f2", &data.failed);
check ("test1", 2, all, f1line, "test1", &data.failed); check ("test1", 2, all, f1line, "test1", &data.failed);
......
...@@ -1235,54 +1235,24 @@ add_unit_ranges (struct backtrace_state *state, uintptr_t base_address, ...@@ -1235,54 +1235,24 @@ add_unit_ranges (struct backtrace_state *state, uintptr_t base_address,
return 1; return 1;
} }
/* Build a mapping from address ranges to the compilation units where /* Find the address range covered by a compilation unit, reading from
the line number information for that range can be found. Returns 1 UNIT_BUF and adding values to U. Returns 1 if all data could be
on success, 0 on failure. */ read, 0 if there is some error. */
static int static int
build_address_map (struct backtrace_state *state, uintptr_t base_address, find_address_ranges (struct backtrace_state *state, uintptr_t base_address,
const unsigned char *dwarf_info, size_t dwarf_info_size, struct dwarf_buf *unit_buf,
const unsigned char *dwarf_abbrev, size_t dwarf_abbrev_size, const unsigned char *dwarf_str, size_t dwarf_str_size,
const unsigned char *dwarf_ranges, size_t dwarf_ranges_size, const unsigned char *dwarf_ranges,
const unsigned char *dwarf_str, size_t dwarf_str_size, size_t dwarf_ranges_size,
int is_bigendian, backtrace_error_callback error_callback, int is_bigendian, backtrace_error_callback error_callback,
void *data, struct unit_addrs_vector *addrs) void *data, struct unit *u,
struct unit_addrs_vector *addrs)
{ {
struct dwarf_buf info; while (unit_buf->left > 0)
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;
const struct abbrev *abbrev;
int addrsize;
const unsigned char *unit_data;
size_t unit_data_len;
size_t unit_data_offset;
uint64_t code; uint64_t code;
size_t i; const struct abbrev *abbrev;
uint64_t lowpc; uint64_t lowpc;
int have_lowpc; int have_lowpc;
uint64_t highpc; uint64_t highpc;
...@@ -1290,57 +1260,15 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, ...@@ -1290,57 +1260,15 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
int highpc_is_relative; int highpc_is_relative;
uint64_t ranges; uint64_t ranges;
int have_ranges; int have_ranges;
uint64_t lineoff; size_t i;
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;
/* We only look at the first attribute in the compilation unit. code = read_uleb128 (unit_buf);
In practice this will be a DW_TAG_compile_unit which will if (code == 0)
tell us the PC range and where to find the line number return 1;
information. */
code = read_uleb128 (&unit_buf); abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data);
abbrev = lookup_abbrev (&abbrevs, code, error_callback, data);
if (abbrev == NULL) if (abbrev == NULL)
goto fail; return 0;
lowpc = 0; lowpc = 0;
have_lowpc = 0; have_lowpc = 0;
...@@ -1349,18 +1277,14 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, ...@@ -1349,18 +1277,14 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
highpc_is_relative = 0; highpc_is_relative = 0;
ranges = 0; ranges = 0;
have_ranges = 0; have_ranges = 0;
lineoff = 0;
have_lineoff = 0;
filename = NULL;
comp_dir = NULL;
for (i = 0; i < abbrev->num_attrs; ++i) for (i = 0; i < abbrev->num_attrs; ++i)
{ {
struct attr_val val; struct attr_val val;
if (!read_attribute (abbrev->attrs[i].form, &unit_buf, is_dwarf64, if (!read_attribute (abbrev->attrs[i].form, unit_buf,
version, addrsize, dwarf_str, dwarf_str_size, u->is_dwarf64, u->version, u->addrsize,
&val)) dwarf_str, dwarf_str_size, &val))
goto fail; return 0;
switch (abbrev->attrs[i].name) switch (abbrev->attrs[i].name)
{ {
...@@ -1371,6 +1295,7 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, ...@@ -1371,6 +1295,7 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
have_lowpc = 1; have_lowpc = 1;
} }
break; break;
case DW_AT_high_pc: case DW_AT_high_pc:
if (val.encoding == ATTR_VAL_ADDRESS) if (val.encoding == ATTR_VAL_ADDRESS)
{ {
...@@ -1384,6 +1309,7 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, ...@@ -1384,6 +1309,7 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
highpc_is_relative = 1; highpc_is_relative = 1;
} }
break; break;
case DW_AT_ranges: case DW_AT_ranges:
if (val.encoding == ATTR_VAL_UINT if (val.encoding == ATTR_VAL_UINT
|| val.encoding == ATTR_VAL_REF_SECTION) || val.encoding == ATTR_VAL_REF_SECTION)
...@@ -1392,73 +1318,46 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, ...@@ -1392,73 +1318,46 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
have_ranges = 1; have_ranges = 1;
} }
break; break;
case DW_AT_stmt_list: case DW_AT_stmt_list:
if (val.encoding == ATTR_VAL_UINT if (abbrev->tag == DW_TAG_compile_unit
|| val.encoding == ATTR_VAL_REF_SECTION) && (val.encoding == ATTR_VAL_UINT
{ || val.encoding == ATTR_VAL_REF_SECTION))
lineoff = val.u.uint; u->lineoff = val.u.uint;
have_lineoff = 1;
}
break; break;
case DW_AT_name: case DW_AT_name:
if (val.encoding == ATTR_VAL_STRING) if (abbrev->tag == DW_TAG_compile_unit
filename = val.u.string; && val.encoding == ATTR_VAL_STRING)
u->filename = val.u.string;
break; break;
case DW_AT_comp_dir: case DW_AT_comp_dir:
if (val.encoding == ATTR_VAL_STRING) if (abbrev->tag == DW_TAG_compile_unit
comp_dir = val.u.string; && val.encoding == ATTR_VAL_STRING)
u->comp_dir = val.u.string;
break; break;
default: default:
break; break;
} }
} }
if (unit_buf.reported_underflow) if (abbrev->tag == DW_TAG_compile_unit
goto fail; || abbrev->tag == DW_TAG_subprogram)
if (((have_lowpc && have_highpc) || have_ranges) && have_lineoff)
{ {
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 (have_ranges)
{ {
if (!add_unit_ranges (state, base_address, u, ranges, lowpc, if (!add_unit_ranges (state, base_address, u, ranges, lowpc,
is_bigendian, dwarf_ranges, is_bigendian, dwarf_ranges,
dwarf_ranges_size, error_callback, data, dwarf_ranges_size, error_callback,
addrs)) data, addrs))
{ return 0;
free_abbrevs (state, &u->abbrevs, error_callback, data);
backtrace_free (state, u, sizeof *u, error_callback, data);
goto fail;
}
} }
else else if (have_lowpc && have_highpc)
{ {
struct unit_addrs a;
if (highpc_is_relative) if (highpc_is_relative)
highpc += lowpc; highpc += lowpc;
a.low = lowpc; a.low = lowpc;
...@@ -1467,17 +1366,146 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address, ...@@ -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, if (!add_unit_addr (state, base_address, a, error_callback, data,
addrs)) addrs))
{ return 0;
free_abbrevs (state, &u->abbrevs, error_callback, data);
backtrace_free (state, u, sizeof *u, error_callback, data);
goto fail;
}
} }
/* 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); if (!find_address_ranges (state, base_address, unit_buf,
memset (&abbrevs, 0, sizeof abbrevs); 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) if (info.reported_underflow)
......
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