return false;
}
+static CORE_ADDR
+default_update_call_site_pc (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ return pc;
+}
+
/* Non-zero if we want to trace architecture code. */
#ifndef GDBARCH_DEBUG
extern bool gdbarch_dwarf2_omit_typedef_p (struct gdbarch *gdbarch, struct type *target_type, const char *producer, const char *name);
extern void set_gdbarch_dwarf2_omit_typedef_p (struct gdbarch *gdbarch, gdbarch_dwarf2_omit_typedef_p_ftype *dwarf2_omit_typedef_p);
+/* Update PC when trying to find a call site. This is useful on
+ architectures where the call site PC, as reported in the DWARF, can be
+ incorrect for some reason.
+
+ The passed-in PC will be an address in the inferior. GDB will have
+ already failed to find a call site at this PC. This function may
+ simply return its parameter if it thinks that should be the correct
+ address. */
+
+typedef CORE_ADDR (gdbarch_update_call_site_pc_ftype) (struct gdbarch *gdbarch, CORE_ADDR pc);
+extern CORE_ADDR gdbarch_update_call_site_pc (struct gdbarch *gdbarch, CORE_ADDR pc);
+extern void set_gdbarch_update_call_site_pc (struct gdbarch *gdbarch, gdbarch_update_call_site_pc_ftype *update_call_site_pc);
+
/* Return true if the return value of function is stored in the first hidden
parameter. In theory, this feature should be language-dependent, specified
by language and its ABI, such as C++. Unfortunately, compiler may
gdbarch_return_value_as_value_ftype *return_value_as_value = default_gdbarch_return_value;
gdbarch_get_return_buf_addr_ftype *get_return_buf_addr = default_get_return_buf_addr;
gdbarch_dwarf2_omit_typedef_p_ftype *dwarf2_omit_typedef_p = default_dwarf2_omit_typedef_p;
+ gdbarch_update_call_site_pc_ftype *update_call_site_pc = default_update_call_site_pc;
gdbarch_return_in_first_hidden_param_p_ftype *return_in_first_hidden_param_p = default_return_in_first_hidden_param_p;
gdbarch_skip_prologue_ftype *skip_prologue = nullptr;
gdbarch_skip_main_prologue_ftype *skip_main_prologue = nullptr;
log.puts ("\n\treturn_value_as_value");
/* Skip verify of get_return_buf_addr, invalid_p == 0 */
/* Skip verify of dwarf2_omit_typedef_p, invalid_p == 0 */
+ /* Skip verify of update_call_site_pc, invalid_p == 0 */
/* Skip verify of return_in_first_hidden_param_p, invalid_p == 0 */
if (gdbarch->skip_prologue == 0)
log.puts ("\n\tskip_prologue");
gdb_printf (file,
"gdbarch_dump: dwarf2_omit_typedef_p = <%s>\n",
host_address_to_string (gdbarch->dwarf2_omit_typedef_p));
+ gdb_printf (file,
+ "gdbarch_dump: update_call_site_pc = <%s>\n",
+ host_address_to_string (gdbarch->update_call_site_pc));
gdb_printf (file,
"gdbarch_dump: return_in_first_hidden_param_p = <%s>\n",
host_address_to_string (gdbarch->return_in_first_hidden_param_p));
gdbarch->dwarf2_omit_typedef_p = dwarf2_omit_typedef_p;
}
+CORE_ADDR
+gdbarch_update_call_site_pc (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ gdb_assert (gdbarch != NULL);
+ gdb_assert (gdbarch->update_call_site_pc != NULL);
+ if (gdbarch_debug >= 2)
+ gdb_printf (gdb_stdlog, "gdbarch_update_call_site_pc called\n");
+ return gdbarch->update_call_site_pc (gdbarch, pc);
+}
+
+void
+set_gdbarch_update_call_site_pc (struct gdbarch *gdbarch,
+ gdbarch_update_call_site_pc_ftype update_call_site_pc)
+{
+ gdbarch->update_call_site_pc = update_call_site_pc;
+}
+
int
gdbarch_return_in_first_hidden_param_p (struct gdbarch *gdbarch, struct type *type)
{
invalid=False,
)
+Method(
+ comment="""
+Update PC when trying to find a call site. This is useful on
+architectures where the call site PC, as reported in the DWARF, can be
+incorrect for some reason.
+
+The passed-in PC will be an address in the inferior. GDB will have
+already failed to find a call site at this PC. This function may
+simply return its parameter if it thinks that should be the correct
+address.""",
+ type="CORE_ADDR",
+ name="update_call_site_pc",
+ params=[("CORE_ADDR", "pc")],
+ predefault="default_update_call_site_pc",
+ invalid=False,
+)
+
Method(
comment="""
Return true if the return value of function is stored in the first hidden
return false;
}
+/* Implement the update_call_site_pc arch hook. */
+
+static CORE_ADDR
+ppc64_update_call_site_pc (struct gdbarch *gdbarch, CORE_ADDR pc)
+{
+ /* Some versions of GCC emit:
+
+ . bl function
+ . nop
+ . ...
+
+ but emit DWARF where the DW_AT_call_return_pc points to
+ instruction after the 'nop'. Note that while the compiler emits
+ a 'nop', the linker might put some other instruction there -- so
+ we just unconditionally check the next instruction. */
+ return pc + 4;
+}
+
/* Initialize the current architecture based on INFO. If possible, re-use an
architecture from ARCHES, which is a list of architectures already created
during this debugging session.
set_gdbarch_return_value (gdbarch, ppc64_sysv_abi_return_value);
set_gdbarch_get_return_buf_addr (gdbarch,
ppc64_sysv_get_return_buf_addr);
+ set_gdbarch_update_call_site_pc (gdbarch, ppc64_update_call_site_pc);
}
else
set_gdbarch_return_value (gdbarch, ppc_sysv_abi_return_value);
struct call_site call_site_local (unrelocated_pc, nullptr, nullptr);
void **slot
= htab_find_slot (m_call_site_htab, &call_site_local, NO_INSERT);
+ if (slot != nullptr)
+ return (call_site *) *slot;
+
+ /* See if the arch knows another PC we should try. On some
+ platforms, GCC emits a DWARF call site that is offset from the
+ actual return location. */
+ struct gdbarch *arch = objfile ()->arch ();
+ CORE_ADDR new_pc = gdbarch_update_call_site_pc (arch, pc);
+ if (pc == new_pc)
+ return nullptr;
+
+ call_site new_call_site_local (new_pc - delta, nullptr, nullptr);
+ slot = htab_find_slot (m_call_site_htab, &new_call_site_local, NO_INSERT);
if (slot == nullptr)
return nullptr;