This is the mail archive of the
gdb-patches@sources.redhat.com
mailing list for the GDB project.
[RFC/i386newframe] Restore all registers from sigframe
- From: Michal Ludvig <mludvig at suse dot cz>
- To: Mark Kettenis <kettenis at chello dot nl>
- Cc: GDB Patches <gdb-patches at sources dot redhat dot com>
- Date: Thu, 29 May 2003 15:03:11 +0200
- Subject: [RFC/i386newframe] Restore all registers from sigframe
- Organization: SuSE CR, s.r.o.
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