[gdb/tdep] Add amd64/i386 epilogue override unwinders

For amd64 the current frame-unwinders are:
...
$ gdb -q -batch -ex "set arch i386:x86-64" -ex "maint info frame-unwinders"
The target architecture is set to "i386:x86-64".
dummy                   DUMMY_FRAME
dwarf2 tailcall         TAILCALL_FRAME
inline                  INLINE_FRAME
python                  NORMAL_FRAME
amd64 epilogue          NORMAL_FRAME
dwarf2                  NORMAL_FRAME
dwarf2 signal           SIGTRAMP_FRAME
amd64 sigtramp          SIGTRAMP_FRAME
amd64 prologue          NORMAL_FRAME
...

For a -g0 -fasynchronous-unwind-tables exec (without .debug_info but with
.eh_frame section), we'd like to start using the dwarf2 unwinder instead of
the "amd64 epilogue" unwinder, by returning true in
compunit_epilogue_unwind_valid for cust == nullptr.

But we'd run into the following problem for a -g0
-fno-asynchronous-unwind-tables (without .debug_info and .eh_frame section)
exec:
- the "amd64 epilogue" unwinder would not run
  (because compunit_epilogue_unwind_valid () == true)
- the dwarf2 unwinder would also not run
  (because there's no .eh_frame info).

Fix this by:
- renaming the "amd64 epilogue" unwinder to "amd64 epilogue override", and
- adding a fallback "amd64 epilogue" after the dwarf unwinders,
while making sure that only one of the two is active.  Likewise for i386.  NFC.

For amd64, this results in this change:
...
 $ gdb -q -batch -ex "set arch i386:x86-64" -ex "maint info frame-unwinders"
 The target architecture is set to "i386:x86-64".
 dummy                   DUMMY_FRAME
 dwarf2 tailcall         TAILCALL_FRAME
 inline                  INLINE_FRAME
 python                  NORMAL_FRAME
-amd64 epilogue          NORMAL_FRAME
+amd64 epilogue override NORMAL_FRAME
 dwarf2                  NORMAL_FRAME
 dwarf2 signal           SIGTRAMP_FRAME
+amd64 epilogue          NORMAL_FRAME
 amd64 sigtramp          SIGTRAMP_FRAME
 amd64 prologue          NORMAL_FRAME
...

And for i386:
...
 $ gdb -q -batch -ex "set arch i386" -ex "maint info frame-unwinders"
 The target architecture is set to "i386".
 dummy                   DUMMY_FRAME
 dwarf2 tailcall         TAILCALL_FRAME
 iline                  INLINE_FRAME
-i386 epilogue           NORMAL_FRAME
+i386 epilogue override  NORMAL_FRAME
 dwarf2                  NORMAL_FRAME
 dwarf2 signal           SIGTRAMP_FRAME
+i386 epilogue           NORMAL_FRAME
 i386 stack tramp        NORMAL_FRAME
 i386 sigtramp           SIGTRAMP_FRAME
 i386 prologue           NORMAL_FRAME
...
This commit is contained in:
Tom de Vries
2023-02-20 12:20:14 +01:00
parent 2f9f989c2b
commit 5aca7eaa2b
2 changed files with 103 additions and 14 deletions

View File

@ -2913,9 +2913,9 @@ amd64_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
} }
static int static int
amd64_epilogue_frame_sniffer (const struct frame_unwind *self, amd64_epilogue_frame_sniffer_1 (const struct frame_unwind *self,
frame_info_ptr this_frame, frame_info_ptr this_frame,
void **this_prologue_cache) void **this_prologue_cache, bool override_p)
{ {
struct gdbarch *gdbarch = get_frame_arch (this_frame); struct gdbarch *gdbarch = get_frame_arch (this_frame);
CORE_ADDR pc = get_frame_pc (this_frame); CORE_ADDR pc = get_frame_pc (this_frame);
@ -2924,14 +2924,45 @@ amd64_epilogue_frame_sniffer (const struct frame_unwind *self,
/* We're not in the inner frame, so assume we're not in an epilogue. */ /* We're not in the inner frame, so assume we're not in an epilogue. */
return 0; return 0;
if (compunit_epilogue_unwind_valid (find_pc_compunit_symtab (pc))) bool unwind_valid_p
/* Don't override the symtab unwinders. */ = compunit_epilogue_unwind_valid (find_pc_compunit_symtab (pc));
if (override_p)
{
if (unwind_valid_p)
/* Don't override the symtab unwinders, skip
"amd64 epilogue override". */
return 0; return 0;
}
else
{
if (!unwind_valid_p)
/* "amd64 epilogue override" unwinder already ran, skip
"amd64 epilogue". */
return 0;
}
/* Check whether we're in an epilogue. */ /* Check whether we're in an epilogue. */
return amd64_stack_frame_destroyed_p (gdbarch, pc); return amd64_stack_frame_destroyed_p (gdbarch, pc);
} }
static int
amd64_epilogue_override_frame_sniffer (const struct frame_unwind *self,
frame_info_ptr this_frame,
void **this_prologue_cache)
{
return amd64_epilogue_frame_sniffer_1 (self, this_frame, this_prologue_cache,
true);
}
static int
amd64_epilogue_frame_sniffer (const struct frame_unwind *self,
frame_info_ptr this_frame,
void **this_prologue_cache)
{
return amd64_epilogue_frame_sniffer_1 (self, this_frame, this_prologue_cache,
false);
}
static struct amd64_frame_cache * static struct amd64_frame_cache *
amd64_epilogue_frame_cache (frame_info_ptr this_frame, void **this_cache) amd64_epilogue_frame_cache (frame_info_ptr this_frame, void **this_cache)
{ {
@ -3000,6 +3031,17 @@ amd64_epilogue_frame_this_id (frame_info_ptr this_frame,
(*this_id) = frame_id_build (cache->base + 16, cache->pc); (*this_id) = frame_id_build (cache->base + 16, cache->pc);
} }
static const struct frame_unwind amd64_epilogue_override_frame_unwind =
{
"amd64 epilogue override",
NORMAL_FRAME,
amd64_epilogue_frame_unwind_stop_reason,
amd64_epilogue_frame_this_id,
amd64_frame_prev_register,
NULL,
amd64_epilogue_override_frame_sniffer
};
static const struct frame_unwind amd64_epilogue_frame_unwind = static const struct frame_unwind amd64_epilogue_frame_unwind =
{ {
"amd64 epilogue", "amd64 epilogue",
@ -3257,7 +3299,9 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
/* Hook the function epilogue frame unwinder. This unwinder is /* Hook the function epilogue frame unwinder. This unwinder is
appended to the list first, so that it supercedes the other appended to the list first, so that it supercedes the other
unwinders in function epilogues. */ unwinders in function epilogues. */
frame_unwind_prepend_unwinder (gdbarch, &amd64_epilogue_frame_unwind); frame_unwind_prepend_unwinder (gdbarch, &amd64_epilogue_override_frame_unwind);
frame_unwind_append_unwinder (gdbarch, &amd64_epilogue_frame_unwind);
/* Hook the prologue-based frame unwinders. */ /* Hook the prologue-based frame unwinders. */
frame_unwind_append_unwinder (gdbarch, &amd64_sigtramp_frame_unwind); frame_unwind_append_unwinder (gdbarch, &amd64_sigtramp_frame_unwind);

View File

@ -2229,9 +2229,9 @@ i386_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc)
} }
static int static int
i386_epilogue_frame_sniffer (const struct frame_unwind *self, i386_epilogue_frame_sniffer_1 (const struct frame_unwind *self,
frame_info_ptr this_frame, frame_info_ptr this_frame,
void **this_prologue_cache) void **this_prologue_cache, bool override_p)
{ {
struct gdbarch *gdbarch = get_frame_arch (this_frame); struct gdbarch *gdbarch = get_frame_arch (this_frame);
CORE_ADDR pc = get_frame_pc (this_frame); CORE_ADDR pc = get_frame_pc (this_frame);
@ -2240,14 +2240,45 @@ i386_epilogue_frame_sniffer (const struct frame_unwind *self,
/* We're not in the inner frame, so assume we're not in an epilogue. */ /* We're not in the inner frame, so assume we're not in an epilogue. */
return 0; return 0;
if (compunit_epilogue_unwind_valid (find_pc_compunit_symtab (pc))) bool unwind_valid_p
/* Don't override the symtab unwinders. */ = compunit_epilogue_unwind_valid (find_pc_compunit_symtab (pc));
if (override_p)
{
if (unwind_valid_p)
/* Don't override the symtab unwinders, skip
"i386 epilogue override". */
return 0; return 0;
}
else
{
if (!unwind_valid_p)
/* "i386 epilogue override" unwinder already ran, skip
"i386 epilogue". */
return 0;
}
/* Check whether we're in an epilogue. */ /* Check whether we're in an epilogue. */
return i386_stack_frame_destroyed_p (gdbarch, pc); return i386_stack_frame_destroyed_p (gdbarch, pc);
} }
static int
i386_epilogue_override_frame_sniffer (const struct frame_unwind *self,
frame_info_ptr this_frame,
void **this_prologue_cache)
{
return i386_epilogue_frame_sniffer_1 (self, this_frame, this_prologue_cache,
true);
}
static int
i386_epilogue_frame_sniffer (const struct frame_unwind *self,
frame_info_ptr this_frame,
void **this_prologue_cache)
{
return i386_epilogue_frame_sniffer_1 (self, this_frame, this_prologue_cache,
false);
}
static struct i386_frame_cache * static struct i386_frame_cache *
i386_epilogue_frame_cache (frame_info_ptr this_frame, void **this_cache) i386_epilogue_frame_cache (frame_info_ptr this_frame, void **this_cache)
{ {
@ -2320,6 +2351,17 @@ i386_epilogue_frame_prev_register (frame_info_ptr this_frame,
return i386_frame_prev_register (this_frame, this_cache, regnum); return i386_frame_prev_register (this_frame, this_cache, regnum);
} }
static const struct frame_unwind i386_epilogue_override_frame_unwind =
{
"i386 epilogue override",
NORMAL_FRAME,
i386_epilogue_frame_unwind_stop_reason,
i386_epilogue_frame_this_id,
i386_epilogue_frame_prev_register,
NULL,
i386_epilogue_override_frame_sniffer
};
static const struct frame_unwind i386_epilogue_frame_unwind = static const struct frame_unwind i386_epilogue_frame_unwind =
{ {
"i386 epilogue", "i386 epilogue",
@ -8618,13 +8660,16 @@ i386_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
unwinder in function epilogues (where the DWARF unwinder unwinder in function epilogues (where the DWARF unwinder
currently fails). */ currently fails). */
if (info.bfd_arch_info->bits_per_word == 32) if (info.bfd_arch_info->bits_per_word == 32)
frame_unwind_append_unwinder (gdbarch, &i386_epilogue_frame_unwind); frame_unwind_append_unwinder (gdbarch, &i386_epilogue_override_frame_unwind);
/* Hook in the DWARF CFI frame unwinder. This unwinder is appended /* Hook in the DWARF CFI frame unwinder. This unwinder is appended
to the list before the prologue-based unwinders, so that DWARF to the list before the prologue-based unwinders, so that DWARF
CFI info will be used if it is available. */ CFI info will be used if it is available. */
dwarf2_append_unwinders (gdbarch); dwarf2_append_unwinders (gdbarch);
if (info.bfd_arch_info->bits_per_word == 32)
frame_unwind_append_unwinder (gdbarch, &i386_epilogue_frame_unwind);
frame_base_set_default (gdbarch, &i386_frame_base); frame_base_set_default (gdbarch, &i386_frame_base);
/* Pseudo registers may be changed by amd64_init_abi. */ /* Pseudo registers may be changed by amd64_init_abi. */