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
This commit is contained in:
Ian Lance Taylor 2013-11-28 16:19:57 +00:00 committed by Ian Lance Taylor
parent f5c8b24c73
commit b8ddd61b74
3 changed files with 212 additions and 160 deletions

View File

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

View File

@ -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);

View File

@ -1235,6 +1235,161 @@ add_unit_ranges (struct backtrace_state *state, uintptr_t base_address,
return 1;
}
/* 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
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)
{
while (unit_buf->left > 0)
{
uint64_t code;
const struct abbrev *abbrev;
uint64_t lowpc;
int have_lowpc;
uint64_t highpc;
int have_highpc;
int highpc_is_relative;
uint64_t ranges;
int have_ranges;
size_t i;
code = read_uleb128 (unit_buf);
if (code == 0)
return 1;
abbrev = lookup_abbrev (&u->abbrevs, code, error_callback, data);
if (abbrev == NULL)
return 0;
lowpc = 0;
have_lowpc = 0;
highpc = 0;
have_highpc = 0;
highpc_is_relative = 0;
ranges = 0;
have_ranges = 0;
for (i = 0; i < abbrev->num_attrs; ++i)
{
struct attr_val val;
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)
{
case DW_AT_low_pc:
if (val.encoding == ATTR_VAL_ADDRESS)
{
lowpc = val.u.uint;
have_lowpc = 1;
}
break;
case DW_AT_high_pc:
if (val.encoding == ATTR_VAL_ADDRESS)
{
highpc = val.u.uint;
have_highpc = 1;
}
else if (val.encoding == ATTR_VAL_UINT)
{
highpc = val.u.uint;
have_highpc = 1;
highpc_is_relative = 1;
}
break;
case DW_AT_ranges:
if (val.encoding == ATTR_VAL_UINT
|| val.encoding == ATTR_VAL_REF_SECTION)
{
ranges = val.u.uint;
have_ranges = 1;
}
break;
case DW_AT_stmt_list:
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 (abbrev->tag == DW_TAG_compile_unit
&& val.encoding == ATTR_VAL_STRING)
u->filename = val.u.string;
break;
case DW_AT_comp_dir:
if (abbrev->tag == DW_TAG_compile_unit
&& val.encoding == ATTR_VAL_STRING)
u->comp_dir = val.u.string;
break;
default:
break;
}
}
if (abbrev->tag == DW_TAG_compile_unit
|| abbrev->tag == DW_TAG_subprogram)
{
if (have_ranges)
{
if (!add_unit_ranges (state, base_address, u, ranges, lowpc,
is_bigendian, dwarf_ranges,
dwarf_ranges_size, error_callback,
data, addrs))
return 0;
}
else if (have_lowpc && have_highpc)
{
struct unit_addrs a;
if (highpc_is_relative)
highpc += lowpc;
a.low = lowpc;
a.high = highpc;
a.u = u;
if (!add_unit_addr (state, base_address, a, error_callback, data,
addrs))
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;
}
if (abbrev->has_children)
{
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. */
@ -1276,24 +1431,8 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
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;
uint64_t lowpc;
int have_lowpc;
uint64_t highpc;
int have_highpc;
int highpc_is_relative;
uint64_t ranges;
int have_ranges;
uint64_t lineoff;
int have_lineoff;
const char *filename;
const char *comp_dir;
struct unit *u;
if (info.reported_underflow)
goto fail;
@ -1328,156 +1467,45 @@ build_address_map (struct backtrace_state *state, uintptr_t base_address,
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.
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);
abbrev = lookup_abbrev (&abbrevs, code, error_callback, data);
if (abbrev == NULL)
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);
lowpc = 0;
have_lowpc = 0;
highpc = 0;
have_highpc = 0;
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)
/* 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))
{
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;
switch (abbrev->attrs[i].name)
{
case DW_AT_low_pc:
if (val.encoding == ATTR_VAL_ADDRESS)
{
lowpc = val.u.uint;
have_lowpc = 1;
}
break;
case DW_AT_high_pc:
if (val.encoding == ATTR_VAL_ADDRESS)
{
highpc = val.u.uint;
have_highpc = 1;
}
else if (val.encoding == ATTR_VAL_UINT)
{
highpc = val.u.uint;
have_highpc = 1;
highpc_is_relative = 1;
}
break;
case DW_AT_ranges:
if (val.encoding == ATTR_VAL_UINT
|| val.encoding == ATTR_VAL_REF_SECTION)
{
ranges = val.u.uint;
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;
}
break;
case DW_AT_name:
if (val.encoding == ATTR_VAL_STRING)
filename = val.u.string;
break;
case DW_AT_comp_dir:
if (val.encoding == ATTR_VAL_STRING)
comp_dir = val.u.string;
break;
default:
break;
}
free_abbrevs (state, &u->abbrevs, error_callback, data);
backtrace_free (state, u, sizeof *u, error_callback, data);
goto fail;
}
if (unit_buf.reported_underflow)
goto fail;
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 (!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;
}
}
else
{
if (highpc_is_relative)
highpc += lowpc;
a.low = lowpc;
a.high = highpc;
a.u = u;
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;
}
}
}
else
{
free_abbrevs (state, &abbrevs, error_callback, data);
memset (&abbrevs, 0, sizeof abbrevs);
free_abbrevs (state, &u->abbrevs, error_callback, data);
backtrace_free (state, u, sizeof *u, error_callback, data);
goto fail;
}
}
if (info.reported_underflow)