gdb: Implement the init_reg dwarf2_frame_ops for amd64

Djordje Todorovic Djordje.Todorovic@syrmia.com
Thu Nov 18 12:42:32 GMT 2021


Hi Andrew,

Please find the patch, rebased on top of your improvement.

Thanks,
Djordje

---
 gdb/amd64-tdep.c                              | 37 +++++++++++++
 gdb/frame.c                                   |  9 +++-
 .../gdb.arch/amd64-invalid-stack-middle.exp   |  8 +--
 gdb/testsuite/gdb.arch/amd64-not-saved-regs.c | 28 ++++++++++
 .../gdb.arch/amd64-not-saved-regs.exp         | 52 +++++++++++++++++++
 gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp |  4 +-
 .../gdb.dwarf2/dw2-reg-undefined.exp          |  8 +--
 gdb/testsuite/gdb.mi/mi-reg-undefined.exp     |  4 +-
 8 files changed, 136 insertions(+), 14 deletions(-)
 create mode 100644 gdb/testsuite/gdb.arch/amd64-not-saved-regs.c
 create mode 100644 gdb/testsuite/gdb.arch/amd64-not-saved-regs.exp
?
diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index 7c67359678b..a6b544145fb 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -25,6 +25,8 @@
 #include "arch-utils.h"
 #include "block.h"
 #include "dummy-frame.h"
+#include "dwarf2.h"
+#include "dwarf2/frame.h"
 #include "frame.h"
 #include "frame-base.h"
 #include "frame-unwind.h"
@@ -3103,6 +3105,38 @@ amd64_in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc)
        AMD64_RIP_REGNUM);
 }

+/* Implement the "init_reg" dwarf2_frame_ops method.  */
+
+static void
+amd64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+           struct dwarf2_frame_state_reg *reg,
+           struct frame_info *this_frame)
+{
+  switch (regnum)
+    {
+    case AMD64_RIP_REGNUM:
+      reg->how = DWARF2_FRAME_REG_FN;
+      return;
+
+    case AMD64_RSP_REGNUM:
+      reg->how = DWARF2_FRAME_REG_CFA;
+      return;
+
+    /* Caller-saved registers.  */
+    case AMD64_RAX_REGNUM:
+    case AMD64_RDI_REGNUM:
+    case AMD64_RSI_REGNUM:
+    case AMD64_RDX_REGNUM:
+    case AMD64_RCX_REGNUM:
+    case AMD64_R8_REGNUM:
+    case AMD64_R9_REGNUM:
+    case AMD64_R10_REGNUM:
+    case AMD64_R11_REGNUM:
+      reg->how = DWARF2_FRAME_REG_UNDEFINED;
+      return;
+    }
+}
+
 void
 amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
  const target_desc *default_tdesc)
@@ -3217,6 +3251,9 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
   set_gdbarch_stab_reg_to_regnum (gdbarch, amd64_dwarf_reg_to_regnum);
   set_gdbarch_dwarf2_reg_to_regnum (gdbarch, amd64_dwarf_reg_to_regnum);

+  /* Frame handling.  */
+  dwarf2_frame_set_init_reg (gdbarch, amd64_dwarf2_frame_init_reg);
+
   /* We don't override SDB_REG_RO_REGNUM, since COFF doesn't seem to
      be in use on any of the supported AMD64 targets.  */

diff --git a/gdb/frame.c b/gdb/frame.c
index 2a899fc494f..da12ed36e02 100644
--- a/gdb/frame.c
+++ b/gdb/frame.c
@@ -2315,9 +2315,14 @@ get_prev_frame_always (struct frame_info *this_frame)
     }
   catch (const gdb_exception_error &ex)
     {
-      if (ex.error == MEMORY_ERROR)
+      if (ex.error == MEMORY_ERROR || ex.error == OPTIMIZED_OUT_ERROR)
  {
-  this_frame->stop_reason = UNWIND_MEMORY_ERROR;
+      if (ex.error == MEMORY_ERROR)
+    this_frame->stop_reason = UNWIND_MEMORY_ERROR;
+      else
+        /* This is for the OPTIMIZED_OUT_ERROR case.  */
+        this_frame->stop_reason = UNWIND_UNAVAILABLE;
+
   if (ex.message != NULL)
     {
       char *stop_string;
diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
index f9e590d83bb..6ae1c9c1322 100644
--- a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
+++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
@@ -42,11 +42,11 @@ if ![runto breakpt] {
     return -1
 }

-gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
- "first backtrace, with error message"
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: value has been optimized out" \
+        "first backtrace, with error message"

-gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
- "second backtrace, with error message"
+gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: value has been optimized out" \
+        "second backtrace, with error message"

 clean_restart ${binfile}

diff --git a/gdb/testsuite/gdb.arch/amd64-not-saved-regs.c b/gdb/testsuite/gdb.arch/amd64-not-saved-regs.c
new file mode 100644
index 00000000000..5698e549f00
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-not-saved-regs.c
@@ -0,0 +1,28 @@
+/* This test program is part of GDB, the GNU debugger.
+
+   Copyright 2019-2021 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int
+foo (int a)
+{
+  return a; /* break here.  */
+}
+
+int
+main ()
+{
+  return foo (5);
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-not-saved-regs.exp b/gdb/testsuite/gdb.arch/amd64-not-saved-regs.exp
new file mode 100644
index 00000000000..07b870b5d30
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-not-saved-regs.exp
@@ -0,0 +1,52 @@
+# Copyright 2010-2021 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@gnu.org
+
+# This file is part of the gdb testsuite.
+
+if { ![istarget x86_64-*-* ]} {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+# Build program with debug symbols.
+standard_testfile
+set compile_flags {debug}
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} ${compile_flags}] } {
+    return -1
+}
+
+if ![runto_main] {
+    untested "could not run to main"
+    return -1
+}
+
+gdb_breakpoint [ gdb_get_line_number "break here" ]
+gdb_continue_to_breakpoint "break here" ".*break here.*"
+
+# Switch to frame 1.
+gdb_test "frame 1" "#1.*in main ().*"
+
+gdb_test "info registers rax" "rax .* <not saved>"
+gdb_test "info registers rcx" "rcx .* <not saved>"
+gdb_test "info registers rdx" "rdx .* <not saved>"
+gdb_test "info registers rsi" "rsi .* <not saved>"
+gdb_test "info registers rdi" "rdi .* <not saved>"
+gdb_test "info registers r8" "r8 .* <not saved>"
+gdb_test "info registers r9" "r9 .* <not saved>"
+gdb_test "info registers r10" "r10 .* <not saved>"
+gdb_test "info registers r11" "r11 .* <not saved>"
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp b/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp
index 238830e711e..70f22cb9efe 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp
@@ -50,11 +50,11 @@ gdb_test "bt" "#0  ($hex in )?breakpt \\(\\)\r\n#1  ($hex in )?int_param_single_

 # (2) struct_param_single_reg_loc
 gdb_continue_to_breakpoint "Stop in breakpt for struct_param_single_reg_loc"
-gdb_test "bt" "#0  ($hex in )?breakpt \\(\\)\r\n#1  ($hex in )?struct_param_single_reg_loc \\(operand0={a = 0xdeadbe00deadbe01, b = <optimized out>}, operand1={a = <optimized out>, b = 0xdeadbe04deadbe05}, operand2=<optimized out>\\)\r\n#2  ($hex in )?main \\(\\)" "backtrace for test struct_param_single_reg_loc"
+gdb_test "bt" "#0  ($hex in )?breakpt \\(\\)\r\n#1  ($hex in )?struct_param_single_reg_loc \\(operand0={a = 0xdeadbe00deadbe01, b = <optimized out>}, operand1=<optimized out>, operand2=<optimized out>\\)\r\n#2  ($hex in )?main \\(\\)" "backtrace for test struct_param_single_reg_loc"

 # (3) struct_param_two_reg_pieces
 gdb_continue_to_breakpoint "Stop in breakpt for struct_param_two_reg_pieces"
-gdb_test "bt" "#0  ($hex in )?breakpt \\(\\)\r\n#1  ($hex in )?struct_param_two_reg_pieces \\(operand0={a = 0xdeadbe04deadbe05, b = <optimized out>}, operand1={a = <optimized out>, b = 0xdeadbe00deadbe01}, operand2=<optimized out>\\)\r\n#2  ($hex in )?main \\(\\)" "backtrace for test struct_param_two_reg_pieces"
+gdb_test "bt" "#0  ($hex in )?breakpt \\(\\)\r\n#1  ($hex in )?struct_param_two_reg_pieces \\(operand0=<optimized out>, operand1={a = <optimized out>, b = 0xdeadbe00deadbe01}, operand2=<optimized out>\\)\r\n#2  ($hex in )?main \\(\\)" "backtrace for test struct_param_two_reg_pieces"

 # (4) int_param_two_reg_pieces
 gdb_continue_to_breakpoint "Stop in breakpt for int_param_two_reg_pieces"
diff --git a/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp
index b1c28b2f41c..2b296c8d445 100644
--- a/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp
+++ b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp
@@ -47,8 +47,8 @@ for {set f 0} {$f < 3} {incr f} {
     } else {
  set pattern_rax_rbx_rcx_print "<not saved>"
  set pattern_rax_rbx_rcx_info "<not saved>"
- set pattern_r8_r9_print "$hex"
- set pattern_r8_r9_info "$hex\\s+$decimal"
+ set pattern_r8_r9_print "<not saved>"
+ set pattern_r8_r9_info "<not saved>"
     }

     # Select frame.
@@ -79,8 +79,8 @@ for {set f 0} {$f < 3} {incr f} {
 # "not saved" and not "optimized out".
 gdb_test "set debug frame 1"
 gdb_test {print $rax} [multi_line \
- {    \[frame\] frame_unwind_register_value: frame=0, regnum=0\(rax\)} \
- {    \[frame\] frame_unwind_register_value:   -> <not saved>} \
+ {  \[frame\] frame_unwind_register_value: frame=1, regnum=0\(rax\)} \
+ {  \[frame\] frame_unwind_register_value:   -> <not saved>} \
  {.*}]
 gdb_test "set debug frame 0"

diff --git a/gdb/testsuite/gdb.mi/mi-reg-undefined.exp b/gdb/testsuite/gdb.mi/mi-reg-undefined.exp
index f38e20003a3..3f193b1379b 100644
--- a/gdb/testsuite/gdb.mi/mi-reg-undefined.exp
+++ b/gdb/testsuite/gdb.mi/mi-reg-undefined.exp
@@ -62,10 +62,10 @@ for {set f 0} {$f < 3} {incr f} {
     }

     mi_gdb_test "22${f}-data-list-register-values --thread 1 --frame ${f} x  0 1 2 8 9" \
- "22${f}\\^done,register-values=\\\[\{number=\"0\",value=\"${pattern_0_1_2}\"\},\{number=\"1\",value=\"${pattern_0_1_2}\"\},\{number=\"2\",value=\"${pattern_0_1_2}\"\},\{number=\"8\",value=\"$hex\"\},\{number=\"9\",value=\"$hex\"\}\\\]" \
+ "22${f}\\^done,register-values=\\\[\{number=\"0\",value=\"${pattern_0_1_2}\"\},\{number=\"1\",value=\"${pattern_0_1_2}\"\},\{number=\"2\",value=\"${pattern_0_1_2}\"\},\{number=\"8\",value=\"${pattern_0_1_2}\"\},\{number=\"9\",value=\"${pattern_0_1_2}\"\}\\\]" \
  "register values, format x, frame ${f}"

     mi_gdb_test "33${f}-data-list-register-values --thread 1 --frame ${f} r 0 1 2 8 9" \
- "33${f}\\^done,register-values=\\\[\{number=\"0\",value=\"${pattern_0_1_2}\"\},\{number=\"1\",value=\"${pattern_0_1_2}\"\},\{number=\"2\",value=\"${pattern_0_1_2}\"\},\{number=\"8\",value=\"$hex\"\},\{number=\"9\",value=\"$hex\"\}\\\]" \
+ "33${f}\\^done,register-values=\\\[\{number=\"0\",value=\"${pattern_0_1_2}\"\},\{number=\"1\",value=\"${pattern_0_1_2}\"\},\{number=\"2\",value=\"${pattern_0_1_2}\"\},\{number=\"8\",value=\"${pattern_0_1_2}\"\},\{number=\"9\",value=\"${pattern_0_1_2}\"\}\\\]" \
  "register values, format r, frame ${f}"
 }
--
2.25.1
?

________________________________
From: Djordje Todorovic <Djordje.Todorovic@syrmia.com>
Sent: Monday, November 15, 2021 10:06 AM
To: Andrew Burgess <aburgess@redhat.com>; gdb-patches@sourceware.org <gdb-patches@sourceware.org>
Cc: Nikola Tesic <Nikola.Tesic@syrmia.com>; asowda@cisco.com <asowda@cisco.com>
Subject: Re: gdb: Implement the init_reg dwarf2_frame_ops for amd64

Hi Andrew,

Thanks for looking into this! I'll wait for the official commit of the patch you've shared.
The patch for this, rebased on top of the change you are about to commit, looks as follows:

---
 gdb/amd64-tdep.c                              | 37 +++++++++++++
 gdb/testsuite/gdb.arch/amd64-not-saved-regs.c | 28 ++++++++++
 .../gdb.arch/amd64-not-saved-regs.exp         | 52 +++++++++++++++++++
 3 files changed, 117 insertions(+)
 create mode 100644 gdb/testsuite/gdb.arch/amd64-not-saved-regs.c
 create mode 100644 gdb/testsuite/gdb.arch/amd64-not-saved-regs.exp

diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
index de04bbd07c1..cb3caa7d709 100644
--- a/gdb/amd64-tdep.c
+++ b/gdb/amd64-tdep.c
@@ -25,6 +25,8 @@
 #include "arch-utils.h"
 #include "block.h"
 #include "dummy-frame.h"
+#include "dwarf2.h"
+#include "dwarf2/frame.h"
 #include "frame.h"
 #include "frame-base.h"
 #include "frame-unwind.h"
@@ -3101,6 +3103,38 @@ amd64_in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc)
        AMD64_RIP_REGNUM);
 }

+/* Implement the "init_reg" dwarf2_frame_ops method.  */
+
+static void
+amd64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
+           struct dwarf2_frame_state_reg *reg,
+           struct frame_info *this_frame)
+{
+  switch (regnum)
+    {
+    case AMD64_RIP_REGNUM:
+      reg->how = DWARF2_FRAME_REG_FN;
+      return;
+
+    case AMD64_RSP_REGNUM:
+      reg->how = DWARF2_FRAME_REG_CFA;
+      return;
+
+    /* Caller-saved registers.  */
+    case AMD64_RAX_REGNUM:
+    case AMD64_RDI_REGNUM:
+    case AMD64_RSI_REGNUM:
+    case AMD64_RDX_REGNUM:
+    case AMD64_RCX_REGNUM:
+    case AMD64_R8_REGNUM:
+    case AMD64_R9_REGNUM:
+    case AMD64_R10_REGNUM:
+    case AMD64_R11_REGNUM:
+      reg->how = DWARF2_FRAME_REG_UNDEFINED;
+      return;
+    }
+}
+
 void
 amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
  const target_desc *default_tdesc)
@@ -3215,6 +3249,9 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
   set_gdbarch_stab_reg_to_regnum (gdbarch, amd64_dwarf_reg_to_regnum);
   set_gdbarch_dwarf2_reg_to_regnum (gdbarch, amd64_dwarf_reg_to_regnum);

+  /* Frame handling.  */
+  dwarf2_frame_set_init_reg (gdbarch, amd64_dwarf2_frame_init_reg);
+
   /* We don't override SDB_REG_RO_REGNUM, since COFF doesn't seem to
      be in use on any of the supported AMD64 targets.  */

diff --git a/gdb/testsuite/gdb.arch/amd64-not-saved-regs.c b/gdb/testsuite/gdb.arch/amd64-not-saved-regs.c
new file mode 100644
index 00000000000..5698e549f00
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-not-saved-regs.c
@@ -0,0 +1,28 @@
+/* This test program is part of GDB, the GNU debugger.
+
+   Copyright 2019-2021 Free Software Foundation, Inc.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+int
+foo (int a)
+{
+  return a; /* break here.  */
+}
+
+int
+main ()
+{
+  return foo (5);
+}
diff --git a/gdb/testsuite/gdb.arch/amd64-not-saved-regs.exp b/gdb/testsuite/gdb.arch/amd64-not-saved-regs.exp
new file mode 100644
index 00000000000..07b870b5d30
--- /dev/null
+++ b/gdb/testsuite/gdb.arch/amd64-not-saved-regs.exp
@@ -0,0 +1,52 @@
+# Copyright 2010-2021 Free Software Foundation, Inc.
+
+# This program is free software; you can redistribute it and/or modify
+# it under the terms of the GNU General Public License as published by
+# the Free Software Foundation; either version 3 of the License, or
+# (at your option) any later version.
+#
+# This program is distributed in the hope that it will be useful,
+# but WITHOUT ANY WARRANTY; without even the implied warranty of
+# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+# GNU General Public License for more details.
+#
+# You should have received a copy of the GNU General Public License
+# along with this program.  If not, see <http://www.gnu.org/licenses/>.
+
+# Please email any bugs, comments, and/or additions to this file to:
+# bug-gdb@gnu.org
+
+# This file is part of the gdb testsuite.
+
+if { ![istarget x86_64-*-* ]} {
+    verbose "Skipping ${gdb_test_file_name}."
+    return
+}
+
+# Build program with debug symbols.
+standard_testfile
+set compile_flags {debug}
+if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} ${compile_flags}] } {
+    return -1
+}
+
+if ![runto_main] {
+    untested "could not run to main"
+    return -1
+}
+
+gdb_breakpoint [ gdb_get_line_number "break here" ]
+gdb_continue_to_breakpoint "break here" ".*break here.*"
+
+# Switch to frame 1.
+gdb_test "frame 1" "#1.*in main ().*"
+
+gdb_test "info registers rax" "rax .* <not saved>"
+gdb_test "info registers rcx" "rcx .* <not saved>"
+gdb_test "info registers rdx" "rdx .* <not saved>"
+gdb_test "info registers rsi" "rsi .* <not saved>"
+gdb_test "info registers rdi" "rdi .* <not saved>"
+gdb_test "info registers r8" "r8 .* <not saved>"
+gdb_test "info registers r9" "r9 .* <not saved>"
+gdb_test "info registers r10" "r10 .* <not saved>"
+gdb_test "info registers r11" "r11 .* <not saved>"
--
2.25.1
________________________________
From: Andrew Burgess <aburgess@redhat.com>
Sent: Tuesday, November 9, 2021 2:35 PM
To: Djordje Todorovic <Djordje.Todorovic@syrmia.com>; gdb-patches@sourceware.org <gdb-patches@sourceware.org>
Cc: Nikola Tesic <Nikola.Tesic@syrmia.com>; asowda@cisco.com <asowda@cisco.com>
Subject: Re: gdb: Implement the init_reg dwarf2_frame_ops for amd64

Djordje <djordje.todorovic@syrmia.com> writes:

> Hi,
>
> Please consider these two files:
>
> $ cat test2.c
> void f1(int);
> int f2();
> void f3();
>
> void f() {
>    f1(0);
>    int local = f2();
>    f1(local);
>    f3();
> }
>
> $ cat main-for-core.c
> #include <stdio.h>
>
> void f1(int param) {
>    if (param % 2 == 0)
>      return;
>    printf("HELLO\n");
>    abort();
> }
>
> int f2() {
>    int x;
>    scanf("%d", &x);
>    return x;
> }
>
> void f3() {
>    int y;
>    scanf("%d", &y);
>    printf("%d\n", y);
> }
>
> int main() {
>    f();
>    return 0;
> }
>
> Compilation of the files:
>
> $ clang -g -O2 test2.c -c -o object-file-test2.o
> $ clang -g -O2 main-for-core.c object-file-test2.o -o main-for-core
>
> By examining debug_loc from object-file-test2.o for the `local` var we see:
> 00000000 000000000000000f 0000000000000016 (DW_OP_reg0 (rax))
>
> And the code for the f() is:
> 0000000000000000 <f>:
> 0: push %rax
> 1: xor %edi,%edi
> 3: callq 8 <f+0x8>
> 8: xor %eax,%eax
> a: callq f <f+0xf>
> f: mov %eax,%edi
> 11: callq 16 <f+0x16>
> 16: xor %eax,%eax
> 18: pop %rcx
> 19: jmpq 1e <f+0x1e>
>
> While debugging it, by loading the core file generated due to abort() (as an input I typed 5):
>
> $ gdb main-for-core
> ...
> (gdb) bt
> #0 0x00007fb2d7aeb377 in raise () from /lib64/libc.so.6
> #1 0x00007fb2d7aeca68 in abort () from /lib64/libc.so.6
> #2 0x0000000000401197 in f1 (param=<optimized out>) at main-for-core.c:7
> #3 0x0000000000401216 in f () at test2.c:8
> #4 0x00000000004011f8 in main () at main-for-core.c:23
> (gdb) f 3
> #3 0x0000000000401216 in f () at test2.c:8
> 8 f1(local);
> (gdb) disassemble
> Dump of assembler code for function f:
> 0x0000000000401200 <+0>: push %rax
> 0x0000000000401201 <+1>: xor %edi,%edi
> 0x0000000000401203 <+3>: callq 0x401180 <f1>
> 0x0000000000401208 <+8>: xor %eax,%eax
> 0x000000000040120a <+10>: callq 0x4011a0 <f2>
> 0x000000000040120f <+15>: mov %eax,%edi
> 0x0000000000401211 <+17>: callq 0x401180 <f1>
> => 0x0000000000401216 <+22>: xor %eax,%eax
> 0x0000000000401218 <+24>: pop %rcx
> 0x0000000000401219 <+25>: jmpq 0x4011c0 <f3>
> End of assembler dump.
> (gdb) p local
> $1 = 0
>
> But it should be reported as <optimized_out>, because the %eax was clobbered by the call.
>
> GCC produces different high pc address to keep GDB working properly:
> 00000000 000000000000000f 0000000000000015 (DW_OP_reg0 (rax))
>
> This patch fixes the problem inside GDB itself for X86_64 target.
>
> Bug: https://bugs.llvm.org/show_bug.cgi?id=49641
> ---
>   gdb/amd64-tdep.c                              | 37 +++++++++++++
>   gdb/frame.c                                   |  9 +++-
>   .../gdb.arch/amd64-invalid-stack-middle.exp   |  8 +--
>   gdb/testsuite/gdb.arch/amd64-not-saved-regs.c | 28 ++++++++++
>   .../gdb.arch/amd64-not-saved-regs.exp         | 52 +++++++++++++++++++
>   gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp |  4 +-
>   .../gdb.dwarf2/dw2-reg-undefined.exp          |  8 +--
>   gdb/testsuite/gdb.mi/mi-reg-undefined.exp     |  4 +-
>   8 files changed, 136 insertions(+), 14 deletions(-)
>   create mode 100644 gdb/testsuite/gdb.arch/amd64-not-saved-regs.c
>   create mode 100644 gdb/testsuite/gdb.arch/amd64-not-saved-regs.exp
>
> diff --git a/gdb/amd64-tdep.c b/gdb/amd64-tdep.c
> index 47761208088..a4ac36b18be 100644
> --- a/gdb/amd64-tdep.c
> +++ b/gdb/amd64-tdep.c
> @@ -25,6 +25,8 @@
>   #include "arch-utils.h"
>   #include "block.h"
>   #include "dummy-frame.h"
> +#include "dwarf2.h"
> +#include "dwarf2/frame.h"
>   #include "frame.h"
>   #include "frame-base.h"
>   #include "frame-unwind.h"
> @@ -3101,6 +3103,38 @@ amd64_in_indirect_branch_thunk (struct gdbarch *gdbarch, CORE_ADDR pc)
>                                       AMD64_RIP_REGNUM);
>   }
>
> +/* Implement the "init_reg" dwarf2_frame_ops method.  */
> +
> +static void
> +amd64_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum,
> +           struct dwarf2_frame_state_reg *reg,
> +           struct frame_info *this_frame)
> +{
> +  switch (regnum)
> +    {
> +    case AMD64_RIP_REGNUM:
> +      reg->how = DWARF2_FRAME_REG_FN;
> +      return;
> +
> +    case AMD64_RSP_REGNUM:
> +      reg->how = DWARF2_FRAME_REG_CFA;
> +      return;
> +
> +    /* Caller-saved registers.  */
> +    case AMD64_RAX_REGNUM:
> +    case AMD64_RDI_REGNUM:
> +    case AMD64_RSI_REGNUM:
> +    case AMD64_RDX_REGNUM:
> +    case AMD64_RCX_REGNUM:
> +    case AMD64_R8_REGNUM:
> +    case AMD64_R9_REGNUM:
> +    case AMD64_R10_REGNUM:
> +    case AMD64_R11_REGNUM:
> +      reg->how = DWARF2_FRAME_REG_UNDEFINED;
> +      return;
> +    }
> +}
> +
>   void
>   amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
>                const target_desc *default_tdesc)
> @@ -3215,6 +3249,9 @@ amd64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch,
>     set_gdbarch_stab_reg_to_regnum (gdbarch, amd64_dwarf_reg_to_regnum);
>     set_gdbarch_dwarf2_reg_to_regnum (gdbarch, amd64_dwarf_reg_to_regnum);
>
> +  /* Frame handling.  */
> +  dwarf2_frame_set_init_reg (gdbarch, amd64_dwarf2_frame_init_reg);
> +
>     /* We don't override SDB_REG_RO_REGNUM, since COFF doesn't seem to
>        be in use on any of the supported AMD64 targets.  */
>
> diff --git a/gdb/frame.c b/gdb/frame.c
> index 16673258373..a5b43c3f949 100644
> --- a/gdb/frame.c
> +++ b/gdb/frame.c
> @@ -2312,9 +2312,14 @@ get_prev_frame_always (struct frame_info *this_frame)
>       }
>     catch (const gdb_exception_error &ex)
>       {
> -      if (ex.error == MEMORY_ERROR)
> +      if (ex.error == MEMORY_ERROR || ex.error == GENERIC_ERROR)

Thanks for working on this.  I wasn't keen on this use of GENERIC_ERROR,
so I posted this patch:

  https://sourceware.org/pipermail/gdb-patches/2021-November/183267.html

After that has been merged you can rebased this patch and this code
should be improved.

Thanks,
Andrew




>        {
> -       this_frame->stop_reason = UNWIND_MEMORY_ERROR;
> +      if (ex.error == MEMORY_ERROR)
> +         this_frame->stop_reason = UNWIND_MEMORY_ERROR;
> +      else
> +        /* This is for the GENERIC_ERROR case.  */
> +        this_frame->stop_reason = UNWIND_UNAVAILABLE;
> +
>          if (ex.message != NULL)
>            {
>              char *stop_string;
> diff --git a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
> index f9e590d83bb..6ae1c9c1322 100644
> --- a/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
> +++ b/gdb/testsuite/gdb.arch/amd64-invalid-stack-middle.exp
> @@ -42,11 +42,11 @@ if ![runto breakpt] {
>       return -1
>   }
>
> -gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
> -      "first backtrace, with error message"
> +gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: value has been optimized out" \
> +        "first backtrace, with error message"
>
> -gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: Cannot access memory at address 0x\[0-9a-f\]+" \
> -      "second backtrace, with error message"
> +gdb_test "bt" "^bt\r\n#0 +breakpt *\\(\\) \[^\r\n\]*\r\n#1 +0x\[0-9a-f\]+ in func5\[^\r\n\]*\r\n#2 +0x\[0-9a-f\]+ in func4\[^\r\n\]*\r\n#3 +0x\[0-9a-f\]+ in func3\[^\r\n\]*\r\nBacktrace stopped: value has been optimized out" \
> +        "second backtrace, with error message"
>
>   clean_restart ${binfile}
>
> diff --git a/gdb/testsuite/gdb.arch/amd64-not-saved-regs.c b/gdb/testsuite/gdb.arch/amd64-not-saved-regs.c
> new file mode 100644
> index 00000000000..5698e549f00
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/amd64-not-saved-regs.c
> @@ -0,0 +1,28 @@
> +/* This test program is part of GDB, the GNU debugger.
> +
> +   Copyright 2019-2021 Free Software Foundation, Inc.
> +
> +   This program is free software; you can redistribute it and/or modify
> +   it under the terms of the GNU General Public License as published by
> +   the Free Software Foundation; either version 3 of the License, or
> +   (at your option) any later version.
> +
> +   This program is distributed in the hope that it will be useful,
> +   but WITHOUT ANY WARRANTY; without even the implied warranty of
> +   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +   GNU General Public License for more details.
> +
> +   You should have received a copy of the GNU General Public License
> +   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
> +
> +int
> +foo (int a)
> +{
> +  return a; /* break here.  */
> +}
> +
> +int
> +main ()
> +{
> +  return foo (5);
> +}
> diff --git a/gdb/testsuite/gdb.arch/amd64-not-saved-regs.exp b/gdb/testsuite/gdb.arch/amd64-not-saved-regs.exp
> new file mode 100644
> index 00000000000..07b870b5d30
> --- /dev/null
> +++ b/gdb/testsuite/gdb.arch/amd64-not-saved-regs.exp
> @@ -0,0 +1,52 @@
> +# Copyright 2010-2021 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program.  If not, see <http://www.gnu.org/licenses/>.
> +
> +# Please email any bugs, comments, and/or additions to this file to:
> +# bug-gdb@gnu.org
> +
> +# This file is part of the gdb testsuite.
> +
> +if { ![istarget x86_64-*-* ]} {
> +    verbose "Skipping ${gdb_test_file_name}."
> +    return
> +}
> +
> +# Build program with debug symbols.
> +standard_testfile
> +set compile_flags {debug}
> +if { [prepare_for_testing "failed to prepare" ${testfile} ${srcfile} ${compile_flags}] } {
> +    return -1
> +}
> +
> +if ![runto_main] {
> +    untested "could not run to main"
> +    return -1
> +}
> +
> +gdb_breakpoint [ gdb_get_line_number "break here" ]
> +gdb_continue_to_breakpoint "break here" ".*break here.*"
> +
> +# Switch to frame 1.
> +gdb_test "frame 1" "#1.*in main ().*"
> +
> +gdb_test "info registers rax" "rax .* <not saved>"
> +gdb_test "info registers rcx" "rcx .* <not saved>"
> +gdb_test "info registers rdx" "rdx .* <not saved>"
> +gdb_test "info registers rsi" "rsi .* <not saved>"
> +gdb_test "info registers rdi" "rdi .* <not saved>"
> +gdb_test "info registers r8" "r8 .* <not saved>"
> +gdb_test "info registers r9" "r9 .* <not saved>"
> +gdb_test "info registers r10" "r10 .* <not saved>"
> +gdb_test "info registers r11" "r11 .* <not saved>"
> diff --git a/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp b/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp
> index 238830e711e..70f22cb9efe 100644
> --- a/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp
> +++ b/gdb/testsuite/gdb.dwarf2/dw2-op-out-param.exp
> @@ -50,11 +50,11 @@ gdb_test "bt" "#0  ($hex in )?breakpt \\(\\)\r\n#1  ($hex in )?int_param_single_
>
>   # (2) struct_param_single_reg_loc
>   gdb_continue_to_breakpoint "Stop in breakpt for struct_param_single_reg_loc"
> -gdb_test "bt" "#0  ($hex in )?breakpt \\(\\)\r\n#1  ($hex in )?struct_param_single_reg_loc \\(operand0={a = 0xdeadbe00deadbe01, b = <optimized out>}, operand1={a = <optimized out>, b = 0xdeadbe04deadbe05}, operand2=<optimized out>\\)\r\n#2  ($hex in )?main \\(\\)" "backtrace for test struct_param_single_reg_loc"
> +gdb_test "bt" "#0  ($hex in )?breakpt \\(\\)\r\n#1  ($hex in )?struct_param_single_reg_loc \\(operand0={a = 0xdeadbe00deadbe01, b = <optimized out>}, operand1=<optimized out>, operand2=<optimized out>\\)\r\n#2  ($hex in )?main \\(\\)" "backtrace for test struct_param_single_reg_loc"
>
>   # (3) struct_param_two_reg_pieces
>   gdb_continue_to_breakpoint "Stop in breakpt for struct_param_two_reg_pieces"
> -gdb_test "bt" "#0  ($hex in )?breakpt \\(\\)\r\n#1  ($hex in )?struct_param_two_reg_pieces \\(operand0={a = 0xdeadbe04deadbe05, b = <optimized out>}, operand1={a = <optimized out>, b = 0xdeadbe00deadbe01}, operand2=<optimized out>\\)\r\n#2  ($hex in )?main \\(\\)" "backtrace for test struct_param_two_reg_pieces"
> +gdb_test "bt" "#0  ($hex in )?breakpt \\(\\)\r\n#1  ($hex in )?struct_param_two_reg_pieces \\(operand0=<optimized out>, operand1={a = <optimized out>, b = 0xdeadbe00deadbe01}, operand2=<optimized out>\\)\r\n#2  ($hex in )?main \\(\\)" "backtrace for test struct_param_two_reg_pieces"
>
>   # (4) int_param_two_reg_pieces
>   gdb_continue_to_breakpoint "Stop in breakpt for int_param_two_reg_pieces"
> diff --git a/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp
> index b1c28b2f41c..2b296c8d445 100644
> --- a/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp
> +++ b/gdb/testsuite/gdb.dwarf2/dw2-reg-undefined.exp
> @@ -47,8 +47,8 @@ for {set f 0} {$f < 3} {incr f} {
>       } else {
>        set pattern_rax_rbx_rcx_print "<not saved>"
>        set pattern_rax_rbx_rcx_info "<not saved>"
> -     set pattern_r8_r9_print "$hex"
> -     set pattern_r8_r9_info "$hex\\s+$decimal"
> +     set pattern_r8_r9_print "<not saved>"
> +     set pattern_r8_r9_info "<not saved>"
>       }
>
>       # Select frame.
> @@ -79,8 +79,8 @@ for {set f 0} {$f < 3} {incr f} {
>   # "not saved" and not "optimized out".
>   gdb_test "set debug frame 1"
>   gdb_test {print $rax} [multi_line \
> -                     {    \[frame\] frame_unwind_register_value: frame=0, regnum=0\(rax\)} \
> -                     {    \[frame\] frame_unwind_register_value:   -> <not saved>} \
> +                     {  \[frame\] frame_unwind_register_value: frame=1, regnum=0\(rax\)} \
> +                     {  \[frame\] frame_unwind_register_value:   -> <not saved>} \
>                        {.*}]
>   gdb_test "set debug frame 0"
>
> diff --git a/gdb/testsuite/gdb.mi/mi-reg-undefined.exp b/gdb/testsuite/gdb.mi/mi-reg-undefined.exp
> index f38e20003a3..3f193b1379b 100644
> --- a/gdb/testsuite/gdb.mi/mi-reg-undefined.exp
> +++ b/gdb/testsuite/gdb.mi/mi-reg-undefined.exp
> @@ -62,10 +62,10 @@ for {set f 0} {$f < 3} {incr f} {
>       }
>
>       mi_gdb_test "22${f}-data-list-register-values --thread 1 --frame ${f} x  0 1 2 8 9" \
> -     "22${f}\\^done,register-values=\\\[\{number=\"0\",value=\"${pattern_0_1_2}\"\},\{number=\"1\",value=\"${pattern_0_1_2}\"\},\{number=\"2\",value=\"${pattern_0_1_2}\"\},\{number=\"8\",value=\"$hex\"\},\{number=\"9\",value=\"$hex\"\}\\\]" \
> +     "22${f}\\^done,register-values=\\\[\{number=\"0\",value=\"${pattern_0_1_2}\"\},\{number=\"1\",value=\"${pattern_0_1_2}\"\},\{number=\"2\",value=\"${pattern_0_1_2}\"\},\{number=\"8\",value=\"${pattern_0_1_2}\"\},\{number=\"9\",value=\"${pattern_0_1_2}\"\}\\\]" \
>        "register values, format x, frame ${f}"
>
>       mi_gdb_test "33${f}-data-list-register-values --thread 1 --frame ${f} r 0 1 2 8 9" \
> -     "33${f}\\^done,register-values=\\\[\{number=\"0\",value=\"${pattern_0_1_2}\"\},\{number=\"1\",value=\"${pattern_0_1_2}\"\},\{number=\"2\",value=\"${pattern_0_1_2}\"\},\{number=\"8\",value=\"$hex\"\},\{number=\"9\",value=\"$hex\"\}\\\]" \
> +     "33${f}\\^done,register-values=\\\[\{number=\"0\",value=\"${pattern_0_1_2}\"\},\{number=\"1\",value=\"${pattern_0_1_2}\"\},\{number=\"2\",value=\"${pattern_0_1_2}\"\},\{number=\"8\",value=\"${pattern_0_1_2}\"\},\{number=\"9\",value=\"${pattern_0_1_2}\"\}\\\]" \
>        "register values, format r, frame ${f}"
>   }
> --
> 2.25.1



More information about the Gdb-patches mailing list