gdb: Implement the init_reg dwarf2_frame_ops for amd64

Djordje djordje.todorovic@syrmia.com
Mon Nov 8 12:20:29 GMT 2021


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)
  	{
-	  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