/* Target-dependent code for GDB, the GNU debugger.
- Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
- 1997, 2000, 2001, 2002, 2003, 2004 Free Software Foundation, Inc.
+ Copyright (C) 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ Free Software Foundation, Inc.
This file is part of GDB.
You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
- Foundation, Inc., 59 Temple Place - Suite 330,
- Boston, MA 02111-1307, USA. */
+ Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ Boston, MA 02110-1301, USA. */
#include "defs.h"
#include "frame.h"
#include "frame-unwind.h"
#include "tramp-frame.h"
-/* The following instructions are used in the signal trampoline code
- on GNU/Linux PPC. The kernel used to use magic syscalls 0x6666 and
- 0x7777 but now uses the sigreturn syscalls. We check for both. */
-#define INSTR_LI_R0_0x6666 0x38006666
-#define INSTR_LI_R0_0x7777 0x38007777
-#define INSTR_LI_R0_NR_sigreturn 0x38000077
-#define INSTR_LI_R0_NR_rt_sigreturn 0x380000AC
-
-#define INSTR_SC 0x44000002
-
-/* Since the *-tdep.c files are platform independent (i.e, they may be
- used to build cross platform debuggers), we can't include system
- headers. Therefore, details concerning the sigcontext structure
- must be painstakingly rerecorded. What's worse, if these details
- ever change in the header files, they'll have to be changed here
- as well. */
-
-/* __SIGNAL_FRAMESIZE from <asm/ptrace.h> */
-#define PPC_LINUX_SIGNAL_FRAMESIZE 64
-
-/* From <asm/sigcontext.h>, offsetof(struct sigcontext_struct, regs) == 0x1c */
-#define PPC_LINUX_REGS_PTR_OFFSET (PPC_LINUX_SIGNAL_FRAMESIZE + 0x1c)
-
-/* From <asm/sigcontext.h>,
- offsetof(struct sigcontext_struct, handler) == 0x14 */
-#define PPC_LINUX_HANDLER_PTR_OFFSET (PPC_LINUX_SIGNAL_FRAMESIZE + 0x14)
-
/* From <asm/ptrace.h>, values for PT_NIP, PT_R1, and PT_LNK */
#define PPC_LINUX_PT_R0 0
#define PPC_LINUX_PT_R1 1
#define PPC_LINUX_PT_FPR31 (PPC_LINUX_PT_FPR0 + 2*31)
#define PPC_LINUX_PT_FPSCR (PPC_LINUX_PT_FPR0 + 2*32 + 1)
-static int ppc_linux_at_sigtramp_return_path (CORE_ADDR pc);
-
-/* Determine if pc is in a signal trampoline...
-
- Ha! That's not what this does at all. wait_for_inferior in
- infrun.c calls get_frame_type() in order to detect entry into a
- signal trampoline just after delivery of a signal. But on
- GNU/Linux, signal trampolines are used for the return path only.
- The kernel sets things up so that the signal handler is called
- directly.
-
- If we use in_sigtramp2() in place of in_sigtramp() (see below)
- we'll (often) end up with stop_pc in the trampoline and prev_pc in
- the (now exited) handler. The code there will cause a temporary
- breakpoint to be set on prev_pc which is not very likely to get hit
- again.
-
- If this is confusing, think of it this way... the code in
- wait_for_inferior() needs to be able to detect entry into a signal
- trampoline just after a signal is delivered, not after the handler
- has been run.
-
- So, we define in_sigtramp() below to return 1 if the following is
- true:
-
- 1) The previous frame is a real signal trampoline.
-
- - and -
-
- 2) pc is at the first or second instruction of the corresponding
- handler.
-
- Why the second instruction? It seems that wait_for_inferior()
- never sees the first instruction when single stepping. When a
- signal is delivered while stepping, the next instruction that
- would've been stepped over isn't, instead a signal is delivered and
- the first instruction of the handler is stepped over instead. That
- puts us on the second instruction. (I added the test for the first
- instruction long after the fact, just in case the observed behavior
- is ever fixed.) */
-
-int
-ppc_linux_in_sigtramp (CORE_ADDR pc, char *func_name)
-{
- CORE_ADDR lr;
- CORE_ADDR sp;
- CORE_ADDR tramp_sp;
- char buf[4];
- CORE_ADDR handler;
-
- lr = read_register (gdbarch_tdep (current_gdbarch)->ppc_lr_regnum);
- if (!ppc_linux_at_sigtramp_return_path (lr))
- return 0;
-
- sp = read_register (SP_REGNUM);
-
- if (target_read_memory (sp, buf, sizeof (buf)) != 0)
- return 0;
-
- tramp_sp = extract_unsigned_integer (buf, 4);
-
- if (target_read_memory (tramp_sp + PPC_LINUX_HANDLER_PTR_OFFSET, buf,
- sizeof (buf)) != 0)
- return 0;
-
- handler = extract_unsigned_integer (buf, 4);
-
- return (pc == handler || pc == handler + 4);
-}
-
-static int
-insn_is_sigreturn (unsigned long pcinsn)
-{
- switch(pcinsn)
- {
- case INSTR_LI_R0_0x6666:
- case INSTR_LI_R0_0x7777:
- case INSTR_LI_R0_NR_sigreturn:
- case INSTR_LI_R0_NR_rt_sigreturn:
- return 1;
- default:
- return 0;
- }
-}
-
-/*
- * The signal handler trampoline is on the stack and consists of exactly
- * two instructions. The easiest and most accurate way of determining
- * whether the pc is in one of these trampolines is by inspecting the
- * instructions. It'd be faster though if we could find a way to do this
- * via some simple address comparisons.
- */
-static int
-ppc_linux_at_sigtramp_return_path (CORE_ADDR pc)
-{
- char buf[12];
- unsigned long pcinsn;
- if (target_read_memory (pc - 4, buf, sizeof (buf)) != 0)
- return 0;
-
- /* extract the instruction at the pc */
- pcinsn = extract_unsigned_integer (buf + 4, 4);
-
- return (
- (insn_is_sigreturn (pcinsn)
- && extract_unsigned_integer (buf + 8, 4) == INSTR_SC)
- ||
- (pcinsn == INSTR_SC
- && insn_is_sigreturn (extract_unsigned_integer (buf, 4))));
-}
static CORE_ADDR
ppc_linux_skip_trampoline_code (CORE_ADDR pc)
{
- char buf[4];
+ gdb_byte buf[4];
struct obj_section *sect;
struct objfile *objfile;
unsigned long insn;
/* Fetch the string; we don't know how long it is. Is it possible
that the following will fail because we're trying to fetch too
much? */
- if (target_read_memory (strtab + symidx, symname, sizeof (symname)) != 0)
+ if (target_read_memory (strtab + symidx, (gdb_byte *) symname,
+ sizeof (symname)) != 0)
return 0;
/* This might not work right if we have multiple symbols with the
regard to removing breakpoints in some potentially self modifying
code. */
int
-ppc_linux_memory_remove_breakpoint (CORE_ADDR addr, char *contents_cache)
+ppc_linux_memory_remove_breakpoint (struct bp_target_info *bp_tgt)
{
+ CORE_ADDR addr = bp_tgt->placed_address;
const unsigned char *bp;
int val;
int bplen;
- char old_contents[BREAKPOINT_MAX];
+ gdb_byte old_contents[BREAKPOINT_MAX];
/* Determine appropriate breakpoint contents and size for this address. */
- bp = BREAKPOINT_FROM_PC (&addr, &bplen);
+ bp = gdbarch_breakpoint_from_pc (current_gdbarch, &addr, &bplen);
if (bp == NULL)
- error ("Software breakpoints not implemented for this target.");
+ error (_("Software breakpoints not implemented for this target."));
val = target_read_memory (addr, old_contents, bplen);
program modified the code on us, so it is wrong to put back the
old value */
if (val == 0 && memcmp (bp, old_contents, bplen) == 0)
- val = target_write_memory (addr, contents_cache, bplen);
+ val = target_write_memory (addr, bp_tgt->shadow_contents, bplen);
return val;
}
static enum return_value_convention
ppc_linux_return_value (struct gdbarch *gdbarch, struct type *valtype,
- struct regcache *regcache, void *readbuf,
- const void *writebuf)
+ struct regcache *regcache, gdb_byte *readbuf,
+ const gdb_byte *writebuf)
{
if ((TYPE_CODE (valtype) == TYPE_CODE_STRUCT
|| TYPE_CODE (valtype) == TYPE_CODE_UNION)
writebuf);
}
-/* Fetch (and possibly build) an appropriate link_map_offsets
- structure for GNU/Linux PPC targets using the struct offsets
- defined in link.h (but without actual reference to that file).
-
- This makes it possible to access GNU/Linux PPC shared libraries
- from a GDB that was not built on an GNU/Linux PPC host (for cross
- debugging). */
-
-struct link_map_offsets *
-ppc_linux_svr4_fetch_link_map_offsets (void)
-{
- static struct link_map_offsets lmo;
- static struct link_map_offsets *lmp = NULL;
-
- if (lmp == NULL)
- {
- lmp = &lmo;
-
- lmo.r_debug_size = 8; /* The actual size is 20 bytes, but
- this is all we need. */
- lmo.r_map_offset = 4;
- lmo.r_map_size = 4;
-
- lmo.link_map_size = 20; /* The actual size is 560 bytes, but
- this is all we need. */
- lmo.l_addr_offset = 0;
- lmo.l_addr_size = 4;
-
- lmo.l_name_offset = 4;
- lmo.l_name_size = 4;
-
- lmo.l_next_offset = 12;
- lmo.l_next_size = 4;
-
- lmo.l_prev_offset = 16;
- lmo.l_prev_size = 4;
- }
-
- return lmp;
-}
-
-
/* Macros for matching instructions. Note that, since all the
operands are masked off before they're or-ed into the instruction,
you can use -1 to make masks. */
trad_frame_set_reg_addr (this_cache, tdep->ppc_cr_regnum,
gpregs + 38 * tdep->wordsize);
- /* Floating point registers. */
- for (i = 0; i < 32; i++)
+ if (ppc_floating_point_unit_p (gdbarch))
{
- int regnum = i + FP0_REGNUM;
- trad_frame_set_reg_addr (this_cache, regnum, fpregs + i * tdep->wordsize);
+ /* Floating point registers. */
+ for (i = 0; i < 32; i++)
+ {
+ int regnum = i + FP0_REGNUM;
+ trad_frame_set_reg_addr (this_cache, regnum,
+ fpregs + i * tdep->wordsize);
+ }
+ trad_frame_set_reg_addr (this_cache, tdep->ppc_fpscr_regnum,
+ fpregs + 32 * tdep->wordsize);
}
- trad_frame_set_reg_addr (this_cache, tdep->ppc_fpscr_regnum,
- fpregs + 32 * tdep->wordsize);
trad_frame_set_id (this_cache, frame_id_build (base, func));
}
set_gdbarch_skip_trampoline_code (gdbarch,
ppc_linux_skip_trampoline_code);
set_solib_svr4_fetch_link_map_offsets
- (gdbarch, ppc_linux_svr4_fetch_link_map_offsets);
+ (gdbarch, svr4_ilp32_fetch_link_map_offsets);
/* Trampolines. */
tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sigaction_tramp_frame);
(gdbarch, ppc64_linux_convert_from_func_ptr_addr);
set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code);
- /* PPC64 malloc's entry-point is called ".malloc". */
- set_gdbarch_name_of_malloc (gdbarch, ".malloc");
+ /* Shared library handling. */
+ set_solib_svr4_fetch_link_map_offsets
+ (gdbarch, svr4_lp64_fetch_link_map_offsets);
/* Trampolines. */
tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sigaction_tramp_frame);
tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sighandler_tramp_frame);
}
set_gdbarch_regset_from_core_section (gdbarch, ppc_linux_regset_from_core_section);
+
+ /* Enable TLS support. */
+ set_gdbarch_fetch_tls_load_module_address (gdbarch,
+ svr4_fetch_objfile_link_map);
}
void