[patch] addr2line -i function nesting problem
James E Wilson
wilson@specifix.com
Tue Sep 20 20:34:00 GMT 2005
The new addr2line -i option is getting confused about function nesting
when given a complex example. The case where it fails looks something
like this.
1: function foo
2: lexical block
3: inline function bar
2: lexical block
3: lexical block
4: inline function baz
We construct the function table in scan_unit_for_symbols. We end up
with a table like this
1: function foo
3: inline function bar
4: inline function baz
Then in the function lookup_symbol_in_function_table, we set the
caller_func field which determines function nesting. Since bar has a
nesting level less than baz, the code assumes that bar must have called
baz. However, from the full nesting tree above, we can see that this is
not the case. This results in incorrect addr2line -i output.
I see two possible solutions for this problem.
1) We can add lexical blocks to the function table to maintain the
proper nesting tree.
2) We can keep a stack of in scope function while reading the dwarf
debug info, and use that to set the caller_func field.
Option 2 seemed like the better option to me, so I wrote a patch to do
that. This avoids cluttering the function table with entries that
aren't functions.
This patch works correctly for my testcase. Unfortunately, this is a
74MB compressed tar file, and I also don't know if I can publicly
redistribute it. I don't have any convenient small testcase.
I've tested this with a ia64-linux make check. There were no
regressions.
Since this is a non-trivial patch, I'll wait in case someone wants to
comment.
--
Jim Wilson, GNU Tools Support, http://www.specifix.com
-------------- next part --------------
2005-09-20 James E. Wilson <wilson@specifix.com>
* dwarf2.c (struct funcinfo): Delete nesting_level field.
(lookup_address_in_function_table): Delete code to set funcinfo
caller_func field. Delete local curr_func.
(scan_unit_for_symbols): New locals nested_funcs, nested_funcs_size.
Delete code setting funcinfo nesting_level field. Add code to set
funcinfo caller_func field.
Index: dwarf2.c
===================================================================
RCS file: /cvs/src/src/bfd/dwarf2.c,v
retrieving revision 1.80
diff -p -p -r1.80 dwarf2.c
*** dwarf2.c 20 Sep 2005 18:13:32 -0000 1.80
--- dwarf2.c 20 Sep 2005 19:48:39 -0000
*************** struct funcinfo
*** 722,728 ****
char *file; /* Source location file name */
int line; /* Source location line number */
int tag;
- int nesting_level;
char *name;
struct arange arange;
asection *sec; /* Where the symbol is defined */
--- 722,727 ----
*************** lookup_address_in_function_table (struct
*** 1431,1458 ****
if (best_fit)
{
- struct funcinfo* curr_func = best_fit;
-
*functionname_ptr = best_fit->name;
*function_ptr = best_fit;
-
- /* If we found a match and it is a function that was inlined,
- traverse the function list looking for the function at the
- next higher scope and save a pointer to it for future use.
- Note that because of the way the DWARF info is generated, and
- the way we build the function list, the first function at the
- next higher level is the one we want. */
-
- for (each_func = best_fit -> prev_func;
- each_func && (curr_func->tag == DW_TAG_inlined_subroutine);
- each_func = each_func->prev_func)
- {
- if (each_func->nesting_level < curr_func->nesting_level)
- {
- curr_func->caller_func = each_func;
- curr_func = each_func;
- }
- }
return TRUE;
}
else
--- 1430,1437 ----
*************** scan_unit_for_symbols (struct comp_unit
*** 1645,1650 ****
--- 1624,1639 ----
bfd *abfd = unit->abfd;
bfd_byte *info_ptr = unit->first_child_die_ptr;
int nesting_level = 1;
+ struct funcinfo **nested_funcs;
+ int nested_funcs_size;
+
+ /* Maintain a stack of in-scope functions and inlined functions, which we
+ can use to set the caller_func field. */
+ nested_funcs_size = 32;
+ nested_funcs = bfd_malloc (nested_funcs_size * sizeof (struct funcinfo *));
+ if (nested_funcs == NULL)
+ return FALSE;
+ nested_funcs[nesting_level] = 0;
while (nesting_level)
{
*************** scan_unit_for_symbols (struct comp_unit
*** 1671,1676 ****
--- 1660,1666 ----
(*_bfd_error_handler) (_("Dwarf Error: Could not find abbrev number %u."),
abbrev_number);
bfd_set_error (bfd_error_bad_value);
+ free (nested_funcs);
return FALSE;
}
*************** scan_unit_for_symbols (struct comp_unit
*** 1682,1690 ****
bfd_size_type amt = sizeof (struct funcinfo);
func = bfd_zalloc (abfd, amt);
func->tag = abbrev->tag;
- func->nesting_level = nesting_level;
func->prev_func = unit->function_table;
unit->function_table = func;
}
else
{
--- 1672,1688 ----
bfd_size_type amt = sizeof (struct funcinfo);
func = bfd_zalloc (abfd, amt);
func->tag = abbrev->tag;
func->prev_func = unit->function_table;
unit->function_table = func;
+
+ if (func->tag == DW_TAG_inlined_subroutine)
+ for (i = nesting_level - 1; i >= 1; i--)
+ if (nested_funcs[i])
+ {
+ func->caller_func = nested_funcs[i];
+ break;
+ }
+ nested_funcs[nesting_level] = func;
}
else
{
*************** scan_unit_for_symbols (struct comp_unit
*** 1698,1703 ****
--- 1696,1704 ----
var->prev_var = unit->variable_table;
unit->variable_table = var;
}
+
+ /* No inline function in scope at this nesting level. */
+ nested_funcs[nesting_level] = 0;
}
for (i = 0; i < abbrev->num_attrs; ++i)
*************** scan_unit_for_symbols (struct comp_unit
*** 1818,1826 ****
}
if (abbrev->has_children)
! nesting_level++;
}
return TRUE;
}
--- 1819,1847 ----
}
if (abbrev->has_children)
! {
! nesting_level++;
!
! if (nesting_level >= nested_funcs_size)
! {
! struct funcinfo **tmp;
!
! nested_funcs_size *= 2;
! tmp = bfd_realloc (nested_funcs,
! (nested_funcs_size
! * sizeof (struct funcinfo *)));
! if (tmp == NULL)
! {
! free (nested_funcs);
! return FALSE;
! }
! nested_funcs = tmp;
! }
! nested_funcs[nesting_level] = 0;
! }
}
+ free (nested_funcs);
return TRUE;
}
More information about the Binutils
mailing list