/* Target-dependent code for GDB, the GNU debugger.
- Copyright 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996,
- 1997, 2000, 2001, 2002, 2003 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 "ppc-tdep.h"
#include "trad-frame.h"
#include "frame-unwind.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)
+#include "tramp-frame.h"
/* From <asm/ptrace.h>, values for PT_NIP, PT_R1, and PT_LNK */
#define PPC_LINUX_PT_R0 0
#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)
+ppc_linux_skip_trampoline_code (struct frame_info *frame, 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. */
#define PPC64_STANDARD_LINKAGE_LEN \
(sizeof (ppc64_standard_linkage) / sizeof (ppc64_standard_linkage[0]))
-
-/* Recognize a 64-bit PowerPC GNU/Linux linkage function --- what GDB
- calls a "solib trampoline". */
-static int
-ppc64_in_solib_call_trampoline (CORE_ADDR pc, char *name)
-{
- /* Detecting solib call trampolines on PPC64 GNU/Linux is a pain.
-
- It's not specifically solib call trampolines that are the issue.
- Any call from one function to another function that uses a
- different TOC requires a trampoline, to save the caller's TOC
- pointer and then load the callee's TOC. An executable or shared
- library may have more than one TOC, so even intra-object calls
- may require a trampoline. Since executable and shared libraries
- will all have their own distinct TOCs, every inter-object call is
- also an inter-TOC call, and requires a trampoline --- so "solib
- call trampolines" are just a special case.
-
- The 64-bit PowerPC GNU/Linux ABI calls these call trampolines
- "linkage functions". Since they need to be near the functions
- that call them, they all appear in .text, not in any special
- section. The .plt section just contains an array of function
- descriptors, from which the linkage functions load the callee's
- entry point, TOC value, and environment pointer. So
- in_plt_section is useless. The linkage functions don't have any
- special linker symbols to name them, either.
-
- The only way I can see to recognize them is to actually look at
- their code. They're generated by ppc_build_one_stub and some
- other functions in bfd/elf64-ppc.c, so that should show us all
- the instruction sequences we need to recognize. */
- unsigned int insn[PPC64_STANDARD_LINKAGE_LEN];
-
- return insns_match_pattern (pc, ppc64_standard_linkage, insn);
-}
-
-
/* When the dynamic linker is doing lazy symbol resolution, the first
call to a function in another object will go like this:
standard linkage function will send them. (This doesn't deal with
dynamic linker lazy symbol resolution stubs.) */
static CORE_ADDR
-ppc64_standard_linkage_target (CORE_ADDR pc, unsigned int *insn)
+ppc64_standard_linkage_target (struct frame_info *frame,
+ CORE_ADDR pc, unsigned int *insn)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (current_gdbarch);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame));
/* The address of the function descriptor this linkage function
references. */
CORE_ADDR desc
- = ((CORE_ADDR) read_register (tdep->ppc_gp0_regnum + 2)
+ = ((CORE_ADDR) get_frame_register_unsigned (frame,
+ tdep->ppc_gp0_regnum + 2)
+ (insn_d_field (insn[0]) << 16)
+ insn_ds_field (insn[2]));
/* Given that we've begun executing a call trampoline at PC, return
the entry point of the function the trampoline will go to. */
static CORE_ADDR
-ppc64_skip_trampoline_code (CORE_ADDR pc)
+ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
{
unsigned int ppc64_standard_linkage_insn[PPC64_STANDARD_LINKAGE_LEN];
if (insns_match_pattern (pc, ppc64_standard_linkage,
ppc64_standard_linkage_insn))
- return ppc64_standard_linkage_target (pc, ppc64_standard_linkage_insn);
+ return ppc64_standard_linkage_target (frame, pc,
+ ppc64_standard_linkage_insn);
else
return 0;
}
const bfd_byte *buf)
{
regcache_raw_supply (regcache, regnum,
- (buf + wordsize
- - register_size (current_gdbarch, regnum)));
+ (buf + wordsize - register_size (current_gdbarch, regnum)));
}
/* Extract the register values found in the WORDSIZED ABI GREGSET,
NULL, ppc32_linux_supply_gregset
};
-struct ppc_linux_sigtramp_cache
-{
- CORE_ADDR base;
- struct trad_frame_saved_reg *saved_regs;
-};
-
-static struct ppc_linux_sigtramp_cache *
-ppc_linux_sigtramp_cache (struct frame_info *next_frame, void **this_cache)
-{
- CORE_ADDR regs;
- CORE_ADDR gpregs;
- CORE_ADDR fpregs;
- int i;
- struct ppc_linux_sigtramp_cache *cache;
- struct gdbarch *gdbarch = get_frame_arch (next_frame);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-
- if ((*this_cache) != NULL)
- return (*this_cache);
- cache = FRAME_OBSTACK_ZALLOC (struct ppc_linux_sigtramp_cache);
- (*this_cache) = cache;
- cache->saved_regs = trad_frame_alloc_saved_regs (next_frame);
-
- cache->base = frame_unwind_register_unsigned (next_frame, SP_REGNUM);
-
- /* Find the register pointer, which gives the address of the
- register buffers. */
- if (tdep->wordsize == 4)
- regs = (cache->base
- + 0xd0 /* Offset to ucontext_t. */
- + 0x30 /* Offset to .reg. */);
- else
- regs = (cache->base
- + 0x80 /* Offset to ucontext_t. */
- + 0xe0 /* Offset to .reg. */);
- /* And the corresponding register buffers. */
- gpregs = read_memory_unsigned_integer (regs, tdep->wordsize);
- fpregs = gpregs + 48 * tdep->wordsize;
-
- /* General purpose. */
- for (i = 0; i < ppc_num_gprs; i++)
- {
- int regnum = i + tdep->ppc_gp0_regnum;
- cache->saved_regs[regnum].addr = gpregs + i * tdep->wordsize;
- }
- cache->saved_regs[PC_REGNUM].addr = gpregs + 32 * tdep->wordsize;
- cache->saved_regs[tdep->ppc_ctr_regnum].addr = gpregs + 35 * tdep->wordsize;
- cache->saved_regs[tdep->ppc_lr_regnum].addr = gpregs + 36 * tdep->wordsize;
- cache->saved_regs[tdep->ppc_xer_regnum].addr = gpregs + 37 * tdep->wordsize;
- cache->saved_regs[tdep->ppc_cr_regnum].addr = gpregs + 38 * tdep->wordsize;
-
- /* Floating point registers. */
- if (ppc_floating_point_unit_p (gdbarch))
- {
- for (i = 0; i < ppc_num_fprs; i++)
- {
- int regnum = i + tdep->ppc_fp0_regnum;
- cache->saved_regs[regnum].addr = fpregs + i * tdep->wordsize;
- }
- cache->saved_regs[tdep->ppc_fpscr_regnum].addr
- = fpregs + 32 * tdep->wordsize;
- }
-
- return cache;
-}
-
-static void
-ppc_linux_sigtramp_this_id (struct frame_info *next_frame, void **this_cache,
- struct frame_id *this_id)
-{
- struct ppc_linux_sigtramp_cache *info
- = ppc_linux_sigtramp_cache (next_frame, this_cache);
- (*this_id) = frame_id_build (info->base, frame_pc_unwind (next_frame));
-}
-
-static void
-ppc_linux_sigtramp_prev_register (struct frame_info *next_frame,
- void **this_cache,
- int regnum, int *optimizedp,
- enum lval_type *lvalp, CORE_ADDR *addrp,
- int *realnump, void *valuep)
-{
- struct ppc_linux_sigtramp_cache *info
- = ppc_linux_sigtramp_cache (next_frame, this_cache);
- trad_frame_prev_register (next_frame, info->saved_regs, regnum,
- optimizedp, lvalp, addrp, realnump, valuep);
-}
-
-static const struct frame_unwind ppc_linux_sigtramp_unwind =
-{
- SIGTRAMP_FRAME,
- ppc_linux_sigtramp_this_id,
- ppc_linux_sigtramp_prev_register
-};
-
-static const struct frame_unwind *
-ppc_linux_sigtramp_sniffer (struct frame_info *next_frame)
-{
- struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (next_frame));
- if (frame_pc_unwind (next_frame)
- > frame_unwind_register_unsigned (next_frame, SP_REGNUM))
- /* Assume anything that is vaguely on the stack is a signal
- trampoline. */
- return &ppc_linux_sigtramp_unwind;
- else
- return NULL;
-}
-
static void
ppc64_linux_supply_gregset (const struct regset *regset,
struct regcache * regcache,
return NULL;
}
+static void
+ppc_linux_sigtramp_cache (struct frame_info *next_frame,
+ struct trad_frame_cache *this_cache,
+ CORE_ADDR func, LONGEST offset,
+ int bias)
+{
+ CORE_ADDR base;
+ CORE_ADDR regs;
+ CORE_ADDR gpregs;
+ CORE_ADDR fpregs;
+ int i;
+ struct gdbarch *gdbarch = get_frame_arch (next_frame);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+ base = frame_unwind_register_unsigned (next_frame,
+ gdbarch_sp_regnum (current_gdbarch));
+ if (bias > 0 && frame_pc_unwind (next_frame) != func)
+ /* See below, some signal trampolines increment the stack as their
+ first instruction, need to compensate for that. */
+ base -= bias;
+
+ /* Find the address of the register buffer pointer. */
+ regs = base + offset;
+ /* Use that to find the address of the corresponding register
+ buffers. */
+ gpregs = read_memory_unsigned_integer (regs, tdep->wordsize);
+ fpregs = gpregs + 48 * tdep->wordsize;
+
+ /* General purpose. */
+ for (i = 0; i < 32; i++)
+ {
+ int regnum = i + tdep->ppc_gp0_regnum;
+ trad_frame_set_reg_addr (this_cache, regnum, gpregs + i * tdep->wordsize);
+ }
+ trad_frame_set_reg_addr (this_cache,
+ gdbarch_pc_regnum (current_gdbarch),
+ gpregs + 32 * tdep->wordsize);
+ trad_frame_set_reg_addr (this_cache, tdep->ppc_ctr_regnum,
+ gpregs + 35 * tdep->wordsize);
+ trad_frame_set_reg_addr (this_cache, tdep->ppc_lr_regnum,
+ gpregs + 36 * tdep->wordsize);
+ trad_frame_set_reg_addr (this_cache, tdep->ppc_xer_regnum,
+ gpregs + 37 * tdep->wordsize);
+ trad_frame_set_reg_addr (this_cache, tdep->ppc_cr_regnum,
+ gpregs + 38 * tdep->wordsize);
+
+ if (ppc_floating_point_unit_p (gdbarch))
+ {
+ /* Floating point registers. */
+ for (i = 0; i < 32; i++)
+ {
+ int regnum = i + gdbarch_fp0_regnum (current_gdbarch);
+ 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_id (this_cache, frame_id_build (base, func));
+}
+
+static void
+ppc32_linux_sigaction_cache_init (const struct tramp_frame *self,
+ struct frame_info *next_frame,
+ struct trad_frame_cache *this_cache,
+ CORE_ADDR func)
+{
+ ppc_linux_sigtramp_cache (next_frame, this_cache, func,
+ 0xd0 /* Offset to ucontext_t. */
+ + 0x30 /* Offset to .reg. */,
+ 0);
+}
+
+static void
+ppc64_linux_sigaction_cache_init (const struct tramp_frame *self,
+ struct frame_info *next_frame,
+ struct trad_frame_cache *this_cache,
+ CORE_ADDR func)
+{
+ ppc_linux_sigtramp_cache (next_frame, this_cache, func,
+ 0x80 /* Offset to ucontext_t. */
+ + 0xe0 /* Offset to .reg. */,
+ 128);
+}
+
+static void
+ppc32_linux_sighandler_cache_init (const struct tramp_frame *self,
+ struct frame_info *next_frame,
+ struct trad_frame_cache *this_cache,
+ CORE_ADDR func)
+{
+ ppc_linux_sigtramp_cache (next_frame, this_cache, func,
+ 0x40 /* Offset to ucontext_t. */
+ + 0x1c /* Offset to .reg. */,
+ 0);
+}
+
+static void
+ppc64_linux_sighandler_cache_init (const struct tramp_frame *self,
+ struct frame_info *next_frame,
+ struct trad_frame_cache *this_cache,
+ CORE_ADDR func)
+{
+ ppc_linux_sigtramp_cache (next_frame, this_cache, func,
+ 0x80 /* Offset to struct sigcontext. */
+ + 0x38 /* Offset to .reg. */,
+ 128);
+}
+
+static struct tramp_frame ppc32_linux_sigaction_tramp_frame = {
+ SIGTRAMP_FRAME,
+ 4,
+ {
+ { 0x380000ac, -1 }, /* li r0, 172 */
+ { 0x44000002, -1 }, /* sc */
+ { TRAMP_SENTINEL_INSN },
+ },
+ ppc32_linux_sigaction_cache_init
+};
+static struct tramp_frame ppc64_linux_sigaction_tramp_frame = {
+ SIGTRAMP_FRAME,
+ 4,
+ {
+ { 0x38210080, -1 }, /* addi r1,r1,128 */
+ { 0x380000ac, -1 }, /* li r0, 172 */
+ { 0x44000002, -1 }, /* sc */
+ { TRAMP_SENTINEL_INSN },
+ },
+ ppc64_linux_sigaction_cache_init
+};
+static struct tramp_frame ppc32_linux_sighandler_tramp_frame = {
+ SIGTRAMP_FRAME,
+ 4,
+ {
+ { 0x38000077, -1 }, /* li r0,119 */
+ { 0x44000002, -1 }, /* sc */
+ { TRAMP_SENTINEL_INSN },
+ },
+ ppc32_linux_sighandler_cache_init
+};
+static struct tramp_frame ppc64_linux_sighandler_tramp_frame = {
+ SIGTRAMP_FRAME,
+ 4,
+ {
+ { 0x38210080, -1 }, /* addi r1,r1,128 */
+ { 0x38000077, -1 }, /* li r0,119 */
+ { 0x44000002, -1 }, /* sc */
+ { TRAMP_SENTINEL_INSN },
+ },
+ ppc64_linux_sighandler_cache_init
+};
+
static void
ppc_linux_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ /* NOTE: jimb/2004-03-26: The System V ABI PowerPC Processor
+ Supplement says that long doubles are sixteen bytes long.
+ However, as one of the known warts of its ABI, PPC GNU/Linux uses
+ eight-byte long doubles. GCC only recently got 128-bit long
+ double support on PPC, so it may be changing soon. The
+ Linux[sic] Standards Base says that programs that use 'long
+ double' on PPC GNU/Linux are non-conformant. */
+ /* NOTE: cagney/2005-01-25: True for both 32- and 64-bit. */
+ set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
+
if (tdep->wordsize == 4)
{
- /* NOTE: jimb/2004-03-26: The System V ABI PowerPC Processor
- Supplement says that long doubles are sixteen bytes long.
- However, as one of the known warts of its ABI, PPC GNU/Linux
- uses eight-byte long doubles. GCC only recently got 128-bit
- long double support on PPC, so it may be changing soon. The
- Linux Standards Base says that programs that use 'long
- double' on PPC GNU/Linux are non-conformant. */
- set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT);
-
/* Until November 2001, gcc did not comply with the 32 bit SysV
R4 ABI requirement that structures less than or equal to 8
bytes should be returned in registers. Instead GCC was using
ppc_linux_memory_remove_breakpoint);
/* Shared library handling. */
- set_gdbarch_in_solib_call_trampoline (gdbarch, in_plt_section);
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);
+ tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sighandler_tramp_frame);
}
if (tdep->wordsize == 8)
function descriptors). */
set_gdbarch_convert_from_func_ptr_addr
(gdbarch, ppc64_linux_convert_from_func_ptr_addr);
-
- set_gdbarch_in_solib_call_trampoline
- (gdbarch, ppc64_in_solib_call_trampoline);
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);
- frame_unwind_append_sniffer (gdbarch, ppc_linux_sigtramp_sniffer);
+
+ /* Enable TLS support. */
+ set_gdbarch_fetch_tls_load_module_address (gdbarch,
+ svr4_fetch_objfile_link_map);
}
void