aboutsummaryrefslogtreecommitdiff
path: root/gdb/gdbarch.c
diff options
context:
space:
mode:
authorTom Tromey <tromey@adacore.com>2023-03-08 10:58:35 -0700
committerTom Tromey <tromey@adacore.com>2023-04-21 07:14:22 -0600
commit9df25c346f5517c0228d067c68ee2f6bfe1728ad (patch)
treea4996b2b7c579cdd89e00e27d82e399c480bf5c8 /gdb/gdbarch.c
parent532d55c0ab4bda1d5da90c6301c7d28ddd98ad18 (diff)
downloadgdb-9df25c346f5517c0228d067c68ee2f6bfe1728ad.zip
gdb-9df25c346f5517c0228d067c68ee2f6bfe1728ad.tar.gz
gdb-9df25c346f5517c0228d067c68ee2f6bfe1728ad.tar.bz2
Handle erroneous DW_AT_call_return_pc
On PPC64, with the test case included in an earlier patch, we found that "finish" would still not correctly find the return value via entry values. The issue is simple. The compiler emits: 0x00000000100032b8 <+28>: bl 0x1000320c <pck__create_large> 0x00000000100032bc <+32>: nop 0x00000000100032c0 <+36>: li r9,42 ... but the DWARF says: <162a> DW_AT_call_return_pc: 0x100032c0 That is, the declared return PC is one instruction past the actual return PC. This patch adds a new arch hook to handle this scenario, and implements it for PPC64. Some care is taken so that GDB will continue to work if this compiler bug is fixed. A GCC patch is here: https://gcc.gnu.org/pipermail/gcc-patches/2023-March/613336.html No check for 'nop' is done, as subsequent discussion revealed that the linker might replace this with another instruction.
Diffstat (limited to 'gdb/gdbarch.c')
-rw-r--r--gdb/gdbarch.c22
1 files changed, 22 insertions, 0 deletions
diff --git a/gdb/gdbarch.c b/gdb/gdbarch.c
index 9406458..30199a0 100644
--- a/gdb/gdbarch.c
+++ b/gdb/gdbarch.c
@@ -115,6 +115,7 @@ struct gdbarch
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;
@@ -372,6 +373,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
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");
@@ -794,6 +796,9 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *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));
gdb_printf (file,
@@ -2639,6 +2644,23 @@ set_gdbarch_dwarf2_omit_typedef_p (struct gdbarch *gdbarch,
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)
{