This is the mail archive of the gdb-patches@sources.redhat.com mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[RFC/i386newframe] Restore all registers from sigframe


Hi,
the attachd patch enables restoration of all registers when unwinding from a signal handler. Currenty only PC and SP were restored and it's a loss since all GPRs are there on the stack.
It's even more important for AMD64 because there parameters are usually passed in regs and not on the stack.


I did it for amd64-linux and i386-linux as I don't know appropriate offsets for other i386-targets. For this reason I kept a fallback to sc_pc_offset/sc_sp_offset.

Do you like the idea? Or would you choose a different approach?

Michal Ludvig
--
* SuSE CR, s.r.o     * mludvig@suse.cz
* (+420) 296.545.373 * http://www.suse.cz
2003-05-29  Michal Ludvig  <mludvig@suse.cz>

	* i386-tdep.h (struct gdbarch_tdep): num_saved_registers,
	sc_reg_offset - new records.
	(I386_*_REGNUM): Moved from i386-tdep.c.
	* i386-linux-tdep.c (i386_linux_init_abi): Initialize 
	offsets in tdep->sc_reg_offset[].
	* x86-64-linux-tdep.c (x86_64_linux_init_abi): Ditto.
	* i386-tdep.c (I386_*_REGNUM): Moved to i386-tdep.h.
	(i386_sigtramp_frame_cache): Use tdep->sc_reg_offset
	if initialized.
	(i386_gdbarch_init): Set tdep->num_saved_registers.
	* x86-64-tdep.c: Ditto for AMD64.
	* x86-64-tdep.h (X86_64_*_REGNUM): Moved from x86-64-tdep.c.

Index: i386-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/i386-tdep.h,v
retrieving revision 1.21.2.2
diff -u -p -r1.21.2.2 i386-tdep.h
--- i386-tdep.h	18 May 2003 09:44:12 -0000	1.21.2.2
+++ i386-tdep.h	29 May 2003 12:57:45 -0000
@@ -71,11 +71,30 @@ struct gdbarch_tdep
   /* Get address of sigcontext for sigtramp.  */
   CORE_ADDR (*sigcontext_addr) (struct frame_info *);
 
+  /* Max number of registers saved for each frame.  */
+  int num_saved_registers;
+  
+  /* Offsets of all registers in `struct sigcontext'.  */
+  int *sc_reg_offset;
+  
   /* Offset of saved PC and SP in `struct sigcontext'.  */
   int sc_pc_offset;
   int sc_sp_offset;
 };
 
+/* Register numbers of various important registers.  */
+
+#define I386_EAX_REGNUM		0 /* %eax */
+#define I386_ECX_REGNUM		1 /* %ecx */
+#define I386_EDX_REGNUM		2 /* %edx */
+#define I386_EBX_REGNUM		3 /* %ebx */
+#define I386_ESP_REGNUM		4 /* %esp */
+#define I386_EBP_REGNUM		5 /* %ebp */
+#define I386_ESI_REGNUM		6 /* %esi */
+#define I386_EDI_REGNUM		7 /* %edi */
+#define I386_EIP_REGNUM		8 /* %eip */
+#define I386_EFLAGS_REGNUM	9 /* %eflags */
+#define I386_ST0_REGNUM		16 /* %st(0) */
 /* Floating-point registers.  */
 
 #define FPU_REG_RAW_SIZE 10
Index: i386-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-linux-tdep.c,v
retrieving revision 1.26.2.5
diff -u -p -r1.26.2.5 i386-linux-tdep.c
--- i386-linux-tdep.c	18 May 2003 09:44:12 -0000	1.26.2.5
+++ i386-linux-tdep.c	29 May 2003 12:57:43 -0000
@@ -444,6 +444,12 @@ i386_linux_init_abi (struct gdbarch_info
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
 
+  /* These offsets come from <asm/sigcontext.h>.  */
+  static int reg_offset[] = {
+    11 * 4, 10 * 4, 9 * 4, 8 * 4,	/* %eax, %ecx, %edx, %ebx */
+    17 * 4, 6 * 4, 5 * 4, 4 * 4,	/* %esp, %ebp, %esi, %edi */
+    14 * 4 };				/* %eip */
+  
   /* GNU/Linux uses ELF.  */
   i386_elf_init_abi (info, gdbarch);
 
@@ -462,9 +468,14 @@ i386_linux_init_abi (struct gdbarch_info
   tdep->jb_pc_offset = 20;	/* From <bits/setjmp.h>.  */
 
   tdep->sigcontext_addr = i386_linux_sigcontext_addr;
-  tdep->sc_pc_offset = 14 * 4;	/* From <asm/sigcontext.h>.  */
-  tdep->sc_sp_offset = 7 * 4;
 
+  /* Offsets of registers saved in a struct sigcontext.  */
+  tdep->sc_reg_offset = reg_offset;
+  tdep->num_saved_registers = sizeof (reg_offset) / sizeof (reg_offset[0]);
+
+  tdep->sc_pc_offset = tdep->sc_reg_offset[I386_EIP_REGNUM];
+  tdep->sc_sp_offset = tdep->sc_reg_offset[I386_ESP_REGNUM];
+  
   /* When the i386 Linux kernel calls a signal handler, the return
      address points to a bit of code on the stack.  This function is
      used to identify this bit of code as a signal trampoline in order
Index: x86-64-linux-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/x86-64-linux-tdep.c,v
retrieving revision 1.17.18.2
diff -u -p -r1.17.18.2 x86-64-linux-tdep.c
--- x86-64-linux-tdep.c	28 May 2003 20:52:03 -0000	1.17.18.2
+++ x86-64-linux-tdep.c	29 May 2003 12:57:45 -0000
@@ -127,13 +127,27 @@ static void
 x86_64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
 {
   struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* These offsets come from <asm/sigcontext.h>.  */
+  static int reg_offset[] = {
+    13 * 8, 11 * 8, 14 * 8, 12 * 8,	/* %rax, %rbx, %rcx, %rdx */
+    9 * 8, 8 * 8, 10 * 8, 15 * 8, 	/* %rsi, %rdi, %rbp, %rsp */
+    0 * 8, 1 * 8, 2 * 8, 3 * 8,		/* %r8 - %r11 */
+    4 * 8, 5 * 8, 6 * 8, 7 * 8,		/* %r12 - %r15 */
+    16 * 8 };				/* %rip */
+
   x86_64_init_abi (info, gdbarch);
 
   set_gdbarch_pc_in_sigtramp (gdbarch, x86_64_linux_pc_in_sigtramp);
 
   tdep->sigcontext_addr = x86_64_linux_sigcontext_addr;
-  tdep->sc_pc_offset = 16 * 8;	/* From <asm/sigcontext.h>.  */
-  tdep->sc_sp_offset = 15 * 8;
+  
+  /* Offsets of registers saved in a struct sigcontext.  */
+  tdep->sc_reg_offset = reg_offset;
+  tdep->num_saved_registers = sizeof (reg_offset) / sizeof (reg_offset[0]);
+
+  tdep->sc_pc_offset = tdep->sc_reg_offset[X86_64_RIP_REGNUM];
+  tdep->sc_sp_offset = tdep->sc_reg_offset[X86_64_RSP_REGNUM];
 }
 
 
Index: i386-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/i386-tdep.c,v
retrieving revision 1.138.2.15
diff -u -p -r1.138.2.15 i386-tdep.c
--- i386-tdep.c	23 May 2003 20:18:32 -0000	1.138.2.15
+++ i386-tdep.c	29 May 2003 12:57:45 -0000
@@ -48,16 +48,6 @@
 #include "i386-tdep.h"
 #include "i387-tdep.h"
 
-/* Register numbers of various important registers.  */
-
-#define I386_EAX_REGNUM		0 /* %eax */
-#define I386_EDX_REGNUM		2 /* %edx */
-#define I386_ESP_REGNUM		4 /* %esp */
-#define I386_EBP_REGNUM		5 /* %ebp */
-#define I386_EIP_REGNUM		8 /* %eip */
-#define I386_EFLAGS_REGNUM	9 /* %eflags */
-#define I386_ST0_REGNUM		16 /* %st(0) */
-
 /* Names of the registers.  The first 10 registers match the register
    numbering scheme used by GCC for stabs and DWARF.  */
 
@@ -879,6 +869,7 @@ i386_sigtramp_frame_cache (struct frame_
   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
   CORE_ADDR addr;
   char buf[4];
+  int i;
 
   if (*this_cache)
     return *this_cache;
@@ -889,8 +880,16 @@ i386_sigtramp_frame_cache (struct frame_
   cache->base = extract_unsigned_integer (buf, 4) - 4;
 
   addr = tdep->sigcontext_addr (next_frame);
-  cache->saved_regs[I386_EIP_REGNUM] = addr + tdep->sc_pc_offset;
-  cache->saved_regs[I386_ESP_REGNUM] = addr + tdep->sc_sp_offset;
+  if (tdep->sc_reg_offset)
+    /* If we have offsets for all registers use them.  */
+    for (i = 0; i < tdep->num_saved_registers; i++)
+      cache->saved_regs[i] = addr + tdep->sc_reg_offset[i];
+  else
+  {
+    /* If not, use only %eip and %esp offsets.  */
+    cache->saved_regs[I386_EIP_REGNUM] = addr + tdep->sc_pc_offset;
+    cache->saved_regs[I386_ESP_REGNUM] = addr + tdep->sc_sp_offset;
+  }
 
   *this_cache = cache;
   return cache;
@@ -1627,6 +1626,8 @@ i386_gdbarch_init (struct gdbarch_info i
   tdep->sigcontext_addr = NULL;
   tdep->sc_pc_offset = -1;
   tdep->sc_sp_offset = -1;
+  tdep->sc_reg_offset = NULL;
+  tdep->num_saved_registers = 0;
 
   /* The format used for `long double' on almost all i386 targets is
      the i387 extended floating-point format.  In fact, of all targets
Index: x86-64-tdep.c
===================================================================
RCS file: /cvs/src/src/gdb/x86-64-tdep.c,v
retrieving revision 1.67.2.5
diff -u -p -r1.67.2.5 x86-64-tdep.c
--- x86-64-tdep.c	19 May 2003 16:58:19 -0000	1.67.2.5
+++ x86-64-tdep.c	29 May 2003 12:57:45 -0000
@@ -40,19 +40,6 @@
 #include "x86-64-tdep.h"
 #include "i387-tdep.h"
 
-/* Register numbers of various important registers.  */
-
-#define X86_64_RAX_REGNUM	0 /* %rax */
-#define X86_64_RDX_REGNUM	3 /* %rdx */
-#define X86_64_RDI_REGNUM	5 /* %rdi */
-#define X86_64_RBP_REGNUM	6 /* %rbp */
-#define X86_64_RSP_REGNUM	7 /* %rsp */
-#define X86_64_RIP_REGNUM	16 /* %rip */
-#define X86_64_EFLAGS_REGNUM	17 /* %eflags */
-#define X86_64_ST0_REGNUM	22 /* %st0 */
-#define X86_64_XMM0_REGNUM	38 /* %xmm0 */
-#define X86_64_XMM1_REGNUM	39 /* %xmm1 */
-
 struct x86_64_register_info
 {
   char *name;
@@ -1040,6 +1027,7 @@ x86_64_sigtramp_frame_cache (struct fram
   struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
   CORE_ADDR addr;
   char buf[8];
+  int i;
 
   if (*this_cache)
     return *this_cache;
@@ -1050,8 +1038,16 @@ x86_64_sigtramp_frame_cache (struct fram
   cache->base = extract_unsigned_integer (buf, 8) - 8;
 
   addr = tdep->sigcontext_addr (next_frame);
-  cache->saved_regs[X86_64_RIP_REGNUM] = addr + tdep->sc_pc_offset;
-  cache->saved_regs[X86_64_RSP_REGNUM] = addr + tdep->sc_sp_offset;
+  if (tdep->sc_reg_offset)
+    /* If we have offsets for all registers use them.  */
+    for (i = 0; i < tdep->num_saved_registers; i++)
+      cache->saved_regs[i] = addr + tdep->sc_reg_offset[i];
+  else
+  {
+    /* If not, use only %rip and %rsp offsets.  */
+    cache->saved_regs[X86_64_RIP_REGNUM] = addr + tdep->sc_pc_offset;
+    cache->saved_regs[X86_64_RSP_REGNUM] = addr + tdep->sc_sp_offset;
+  }
 
   *this_cache = cache;
   return cache;
Index: x86-64-tdep.h
===================================================================
RCS file: /cvs/src/src/gdb/x86-64-tdep.h,v
retrieving revision 1.14.2.1
diff -u -p -r1.14.2.1 x86-64-tdep.h
--- x86-64-tdep.h	17 May 2003 15:09:15 -0000	1.14.2.1
+++ x86-64-tdep.h	29 May 2003 12:57:45 -0000
@@ -33,6 +33,23 @@ struct frame_info;
 /* Number of general purpose registers.  */
 #define X86_64_NUM_GREGS	22
 
+/* Register numbers of various important registers.  */
+
+#define X86_64_RAX_REGNUM	0 /* %rax */
+#define X86_64_RBX_REGNUM	1 /* %rbx */
+#define X86_64_RCX_REGNUM	2 /* %rcx */
+#define X86_64_RDX_REGNUM	3 /* %rdx */
+#define X86_64_RSI_REGNUM	4 /* %rsi */
+#define X86_64_RDI_REGNUM	5 /* %rdi */
+#define X86_64_RBP_REGNUM	6 /* %rbp */
+#define X86_64_RSP_REGNUM	7 /* %rsp */
+#define X86_64_R8_REGNUM	8 /* %rsp */
+#define X86_64_RIP_REGNUM	16 /* %rip */
+#define X86_64_EFLAGS_REGNUM	17 /* %eflags */
+#define X86_64_ST0_REGNUM	22 /* %st0 */
+#define X86_64_XMM0_REGNUM	38 /* %xmm0 */
+#define X86_64_XMM1_REGNUM	39 /* %xmm1 */
+
 void x86_64_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch);
 
 /* Fill GDB's register array with the floating-point and SSE register

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]