/* Target-dependent code for GNU/Linux running on i386's, for GDB.
- Copyright 2000, 2001, 2002 Free Software Foundation, Inc.
+ Copyright 2000, 2001, 2002, 2003 Free Software Foundation, Inc.
This file is part of GDB.
#include "value.h"
#include "regcache.h"
#include "inferior.h"
+#include "reggroups.h"
/* For i386_linux_skip_solib_resolver. */
#include "symtab.h"
#include "solib-svr4.h" /* For struct link_map_offsets. */
+#include "osabi.h"
+
#include "i386-tdep.h"
#include "i386-linux-tdep.h"
/* Return the name of register REG. */
-static char *
+static const char *
i386_linux_register_name (int reg)
{
/* Deal with the extra "orig_eax" pseudo register. */
return i386_register_name (reg);
}
+/* Return non-zero, when the register is in the corresponding register
+ group. Put the LINUX_ORIG_EAX register in the system group. */
static int
-i386_linux_register_byte (int reg)
+i386_linux_register_reggroup_p (struct gdbarch *gdbarch, int regnum,
+ struct reggroup *group)
{
- /* Deal with the extra "orig_eax" pseudo register. */
- if (reg == I386_LINUX_ORIG_EAX_REGNUM)
- return (i386_register_byte (I386_LINUX_ORIG_EAX_REGNUM - 1)
- + i386_register_raw_size (I386_LINUX_ORIG_EAX_REGNUM - 1));
-
- return i386_register_byte (reg);
+ if (regnum == I386_LINUX_ORIG_EAX_REGNUM)
+ return (group == system_reggroup
+ || group == save_reggroup
+ || group == restore_reggroup);
+ return i386_register_reggroup_p (gdbarch, regnum, group);
}
-static int
-i386_linux_register_raw_size (int reg)
-{
- /* Deal with the extra "orig_eax" pseudo register. */
- if (reg == I386_LINUX_ORIG_EAX_REGNUM)
- return 4;
-
- return i386_register_raw_size (reg);
-}
\f
/* Recognizing signal handler frames. */
static int
i386_linux_pc_in_sigtramp (CORE_ADDR pc, char *name)
{
- if (name)
- return STREQ ("__restore", name) || STREQ ("__restore_rt", name);
-
- return (i386_linux_sigtramp_start (pc) != 0
- || i386_linux_rt_sigtramp_start (pc) != 0);
+ /* If we have NAME, we can optimize the search. The trampolines are
+ named __restore and __restore_rt. However, they aren't dynamically
+ exported from the shared C library, so the trampoline may appear to
+ be part of the preceding function. This should always be sigaction,
+ __sigaction, or __libc_sigaction (all aliases to the same function). */
+ if (name == NULL || strstr (name, "sigaction") != NULL)
+ return (i386_linux_sigtramp_start (pc) != 0
+ || i386_linux_rt_sigtramp_start (pc) != 0);
+
+ return (strcmp ("__restore", name) == 0
+ || strcmp ("__restore_rt", name) == 0);
}
/* Assuming FRAME is for a GNU/Linux sigtramp routine, return the
address of the associated sigcontext structure. */
-CORE_ADDR
+static CORE_ADDR
i386_linux_sigcontext_addr (struct frame_info *frame)
{
CORE_ADDR pc;
- pc = i386_linux_sigtramp_start (frame->pc);
+ pc = i386_linux_sigtramp_start (get_frame_pc (frame));
if (pc)
{
CORE_ADDR sp;
- if (frame->next)
+ if (get_next_frame (frame))
/* If this isn't the top frame, the next frame must be for the
signal handler itself. The sigcontext structure lives on
the stack, right after the signum argument. */
- return frame->next->frame + 12;
+ return get_frame_base (get_next_frame (frame)) + 12;
/* This is the top frame. We'll have to find the address of the
sigcontext structure by looking at the stack pointer. Keep
"pop %eax". If the PC is at this instruction, adjust the
returned value accordingly. */
sp = read_register (SP_REGNUM);
- if (pc == frame->pc)
+ if (pc == get_frame_pc (frame))
return sp + 4;
return sp;
}
- pc = i386_linux_rt_sigtramp_start (frame->pc);
+ pc = i386_linux_rt_sigtramp_start (get_frame_pc (frame));
if (pc)
{
- if (frame->next)
+ if (get_next_frame (frame))
/* If this isn't the top frame, the next frame must be for the
signal handler itself. The sigcontext structure is part of
the user context. A pointer to the user context is passed
as the third argument to the signal handler. */
- return read_memory_integer (frame->next->frame + 16, 4) + 20;
+ return read_memory_integer (get_frame_base (get_next_frame (frame))
+ + 16, 4) + 20;
/* This is the top frame. Again, use the stack pointer to find
the address of the sigcontext structure. */
return 0;
}
-/* Offset to saved PC in sigcontext, from <asm/sigcontext.h>. */
-#define LINUX_SIGCONTEXT_PC_OFFSET (56)
-
-/* Assuming FRAME is for a GNU/Linux sigtramp routine, return the
- saved program counter. */
-
-static CORE_ADDR
-i386_linux_sigtramp_saved_pc (struct frame_info *frame)
-{
- CORE_ADDR addr;
- addr = i386_linux_sigcontext_addr (frame);
- return read_memory_integer (addr + LINUX_SIGCONTEXT_PC_OFFSET, 4);
-}
-
-/* Offset to saved SP in sigcontext, from <asm/sigcontext.h>. */
-#define LINUX_SIGCONTEXT_SP_OFFSET (28)
-
-/* Assuming FRAME is for a GNU/Linux sigtramp routine, return the
- saved stack pointer. */
-
-static CORE_ADDR
-i386_linux_sigtramp_saved_sp (struct frame_info *frame)
-{
- CORE_ADDR addr;
- addr = i386_linux_sigcontext_addr (frame);
- return read_memory_integer (addr + LINUX_SIGCONTEXT_SP_OFFSET, 4);
-}
-
-/* Signal trampolines don't have a meaningful frame. As in
- "i386/tm-i386.h", the frame pointer value we use is actually the
- frame pointer of the calling frame -- that is, the frame which was
- in progress when the signal trampoline was entered. GDB mostly
- treats this frame pointer value as a magic cookie. We detect the
- case of a signal trampoline by looking at the SIGNAL_HANDLER_CALLER
- field, which is set based on PC_IN_SIGTRAMP.
-
- When a signal trampoline is invoked from a frameless function, we
- essentially have two frameless functions in a row. In this case,
- we use the same magic cookie for three frames in a row. We detect
- this case by seeing whether the next frame has
- SIGNAL_HANDLER_CALLER set, and, if it does, checking whether the
- current frame is actually frameless. In this case, we need to get
- the PC by looking at the SP register value stored in the signal
- context.
-
- This should work in most cases except in horrible situations where
- a signal occurs just as we enter a function but before the frame
- has been set up. */
-
-#define FRAMELESS_SIGNAL(frame) \
- ((frame)->next != NULL \
- && (frame)->next->signal_handler_caller \
- && frameless_look_for_prologue (frame))
-
-CORE_ADDR
-i386_linux_frame_chain (struct frame_info *frame)
-{
- if (frame->signal_handler_caller || FRAMELESS_SIGNAL (frame))
- return frame->frame;
-
- if (! inside_entry_file (frame->pc))
- return read_memory_unsigned_integer (frame->frame, 4);
-
- return 0;
-}
-
-/* Return the saved program counter for FRAME. */
-
-CORE_ADDR
-i386_linux_frame_saved_pc (struct frame_info *frame)
-{
- if (frame->signal_handler_caller)
- return i386_linux_sigtramp_saved_pc (frame);
-
- if (FRAMELESS_SIGNAL (frame))
- {
- CORE_ADDR sp = i386_linux_sigtramp_saved_sp (frame->next);
- return read_memory_unsigned_integer (sp, 4);
- }
-
- return read_memory_unsigned_integer (frame->frame + 4, 4);
-}
-
-/* Immediately after a function call, return the saved pc. */
-
-CORE_ADDR
-i386_linux_saved_pc_after_call (struct frame_info *frame)
-{
- if (frame->signal_handler_caller)
- return i386_linux_sigtramp_saved_pc (frame);
-
- return read_memory_unsigned_integer (read_register (SP_REGNUM), 4);
-}
-
/* Set the program counter for process PTID to PC. */
static void
set_gdbarch_write_pc (gdbarch, i386_linux_write_pc);
set_gdbarch_num_regs (gdbarch, I386_SSE_NUM_REGS + 1);
set_gdbarch_register_name (gdbarch, i386_linux_register_name);
+ set_gdbarch_register_reggroup_p (gdbarch, i386_linux_register_reggroup_p);
set_gdbarch_register_bytes (gdbarch, I386_SSE_SIZEOF_REGS + 4);
- set_gdbarch_register_byte (gdbarch, i386_linux_register_byte);
- set_gdbarch_register_raw_size (gdbarch, i386_linux_register_raw_size);
tdep->jb_pc_offset = 20; /* From <bits/setjmp.h>. */
- /* When the i386 Linux kernel calls a signal handler, the return
- address points to a bit of code on the stack. These definitions
- are used to identify this bit of code as a signal trampoline in
- order to support backtracing through calls to signal handlers. */
+ tdep->sigcontext_addr = i386_linux_sigcontext_addr;
+ tdep->sc_pc_offset = 14 * 4; /* From <asm/sigcontext.h>. */
+ tdep->sc_sp_offset = 7 * 4;
+ /* 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
+ to support backtracing through calls to signal handlers. */
set_gdbarch_pc_in_sigtramp (gdbarch, i386_linux_pc_in_sigtramp);
- set_gdbarch_frame_chain (gdbarch, i386_linux_frame_chain);
- set_gdbarch_frame_saved_pc (gdbarch, i386_linux_frame_saved_pc);
- set_gdbarch_saved_pc_after_call (gdbarch, i386_linux_saved_pc_after_call);
- tdep->sigtramp_saved_pc = i386_linux_sigtramp_saved_pc;
set_solib_svr4_fetch_link_map_offsets (gdbarch,
i386_linux_svr4_fetch_link_map_offsets);
void
_initialize_i386_linux_tdep (void)
{
- gdbarch_register_osabi (bfd_arch_i386, GDB_OSABI_LINUX,
+ gdbarch_register_osabi (bfd_arch_i386, 0, GDB_OSABI_LINUX,
i386_linux_init_abi);
}