libdrgn: stack_trace: get DW_AT_frame_base from containing DW_TAG_subprogram DIE

When looking up a local variable, we pass the function scope DIE to the
DWARF expression evaluator, which uses it to look up DW_AT_frame_base
for DW_OP_fbreg. However, for inline frames, the function scope DIE is
the DW_TAG_inlined_subroutine DIE, which doesn't have a
DW_AT_frame_base; we're supposed to get it from the containing
DW_TAG_subprogram DIE. Fix drgn_stack_frame_find_object() to always pass
the containing DW_TAG_subprogram DIE. This fixes some cases where local
variables are reported as absent even though they are available.

Signed-off-by: Omar Sandoval <osandov@osandov.com>
This commit is contained in:
Omar Sandoval 2024-05-02 00:22:48 -07:00
parent 52e7ecf380
commit 64a317a022

View File

@ -486,11 +486,23 @@ not_found:;
// different platform than the program.
if (!drgn_platforms_equal(&file->platform, &trace->prog->platform))
regs = NULL;
Dwarf_Die function_die = frame->scopes[frame->function_scope];
// If this is an inline frame, then DW_AT_frame_base is in the
// containing DW_TAG_subprogram DIE.
size_t subprogram_frame_i = frame_i;
Dwarf_Die *function_die;
for (;;) {
struct drgn_stack_frame *subprogram_frame =
&trace->frames[subprogram_frame_i];
function_die =
&subprogram_frame->scopes[subprogram_frame->function_scope];
if (dwarf_tag(function_die) == DW_TAG_subprogram)
break;
subprogram_frame_i++;
}
return drgn_object_from_dwarf(&trace->prog->dbinfo, file, &die,
dwarf_tag(&die) == DW_TAG_enumerator ?
&type_die : NULL,
&function_die, regs, ret);
function_die, regs, ret);
}
LIBDRGN_PUBLIC bool drgn_stack_frame_register(struct drgn_stack_trace *trace,