/* Target-dependent code for GDB, the GNU debugger.
Copyright (C) 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997,
- 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007
+ 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008
Free Software Foundation, Inc.
This file is part of GDB.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
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., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#include "defs.h"
#include "frame.h"
#include "frame-unwind.h"
#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_R1 1
-#define PPC_LINUX_PT_R2 2
-#define PPC_LINUX_PT_R3 3
-#define PPC_LINUX_PT_R4 4
-#define PPC_LINUX_PT_R5 5
-#define PPC_LINUX_PT_R6 6
-#define PPC_LINUX_PT_R7 7
-#define PPC_LINUX_PT_R8 8
-#define PPC_LINUX_PT_R9 9
-#define PPC_LINUX_PT_R10 10
-#define PPC_LINUX_PT_R11 11
-#define PPC_LINUX_PT_R12 12
-#define PPC_LINUX_PT_R13 13
-#define PPC_LINUX_PT_R14 14
-#define PPC_LINUX_PT_R15 15
-#define PPC_LINUX_PT_R16 16
-#define PPC_LINUX_PT_R17 17
-#define PPC_LINUX_PT_R18 18
-#define PPC_LINUX_PT_R19 19
-#define PPC_LINUX_PT_R20 20
-#define PPC_LINUX_PT_R21 21
-#define PPC_LINUX_PT_R22 22
-#define PPC_LINUX_PT_R23 23
-#define PPC_LINUX_PT_R24 24
-#define PPC_LINUX_PT_R25 25
-#define PPC_LINUX_PT_R26 26
-#define PPC_LINUX_PT_R27 27
-#define PPC_LINUX_PT_R28 28
-#define PPC_LINUX_PT_R29 29
-#define PPC_LINUX_PT_R30 30
-#define PPC_LINUX_PT_R31 31
-#define PPC_LINUX_PT_NIP 32
-#define PPC_LINUX_PT_MSR 33
-#define PPC_LINUX_PT_CTR 35
-#define PPC_LINUX_PT_LNK 36
-#define PPC_LINUX_PT_XER 37
-#define PPC_LINUX_PT_CCR 38
-#define PPC_LINUX_PT_MQ 39
-#define PPC_LINUX_PT_FPR0 48 /* each FP reg occupies 2 slots in this space */
-#define PPC_LINUX_PT_FPR31 (PPC_LINUX_PT_FPR0 + 2*31)
-#define PPC_LINUX_PT_FPSCR (PPC_LINUX_PT_FPR0 + 2*32 + 1)
-
-
static CORE_ADDR
ppc_linux_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
{
char symname[1024];
struct minimal_symbol *msymbol;
- /* Find the section pc is in; return if not in .plt */
+ /* Find the section pc is in; if not in .plt, try the default method. */
sect = find_pc_section (pc);
if (!sect || strcmp (sect->the_bfd_section->name, ".plt") != 0)
- return 0;
+ return find_solib_trampoline_target (frame, pc);
objfile = sect->objfile;
regard to removing breakpoints in some potentially self modifying
code. */
int
-ppc_linux_memory_remove_breakpoint (struct bp_target_info *bp_tgt)
+ppc_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
+ struct bp_target_info *bp_tgt)
{
CORE_ADDR addr = bp_tgt->placed_address;
const unsigned char *bp;
int val;
int bplen;
gdb_byte old_contents[BREAKPOINT_MAX];
+ struct cleanup *cleanup;
/* Determine appropriate breakpoint contents and size for this address. */
- bp = gdbarch_breakpoint_from_pc (current_gdbarch, &addr, &bplen);
+ bp = gdbarch_breakpoint_from_pc (gdbarch, &addr, &bplen);
if (bp == NULL)
error (_("Software breakpoints not implemented for this target."));
+ /* Make sure we see the memory breakpoints. */
+ cleanup = make_show_memory_breakpoints_cleanup (1);
val = target_read_memory (addr, old_contents, bplen);
/* If our breakpoint is no longer at the address, this means that the
if (val == 0 && memcmp (bp, old_contents, bplen) == 0)
val = target_write_memory (addr, bp_tgt->shadow_contents, bplen);
+ do_cleanups (cleanup);
return val;
}
return addr;
}
+/* This wrapper clears areas in the linux gregset not written by
+ ppc_collect_gregset. */
+
static void
-right_supply_register (struct regcache *regcache, int wordsize, int regnum,
- const bfd_byte *buf)
+ppc_linux_collect_gregset (const struct regset *regset,
+ const struct regcache *regcache,
+ int regnum, void *gregs, size_t len)
{
- regcache_raw_supply (regcache, regnum,
- (buf + wordsize - register_size (current_gdbarch, regnum)));
+ if (regnum == -1)
+ memset (gregs, 0, len);
+ ppc_collect_gregset (regset, regcache, regnum, gregs, len);
}
-/* Extract the register values found in the WORDSIZED ABI GREGSET,
- storing their values in REGCACHE. Note that some are left-aligned,
- while others are right aligned. */
+/* Regset descriptions. */
+static const struct ppc_reg_offsets ppc32_linux_reg_offsets =
+ {
+ /* General-purpose registers. */
+ /* .r0_offset = */ 0,
+ /* .gpr_size = */ 4,
+ /* .xr_size = */ 4,
+ /* .pc_offset = */ 128,
+ /* .ps_offset = */ 132,
+ /* .cr_offset = */ 152,
+ /* .lr_offset = */ 144,
+ /* .ctr_offset = */ 140,
+ /* .xer_offset = */ 148,
+ /* .mq_offset = */ 156,
+
+ /* Floating-point registers. */
+ /* .f0_offset = */ 0,
+ /* .fpscr_offset = */ 256,
+ /* .fpscr_size = */ 8,
+
+ /* AltiVec registers. */
+ /* .vr0_offset = */ 0,
+ /* .vscr_offset = */ 512 + 12,
+ /* .vrsave_offset = */ 528
+ };
-void
-ppc_linux_supply_gregset (struct regcache *regcache,
- int regnum, const void *gregs, size_t size,
- int wordsize)
-{
- int regi;
- struct gdbarch *regcache_arch = get_regcache_arch (regcache);
- struct gdbarch_tdep *regcache_tdep = gdbarch_tdep (regcache_arch);
- const bfd_byte *buf = gregs;
-
- for (regi = 0; regi < ppc_num_gprs; regi++)
- right_supply_register (regcache, wordsize,
- regcache_tdep->ppc_gp0_regnum + regi,
- buf + wordsize * regi);
-
- right_supply_register (regcache, wordsize, gdbarch_pc_regnum (regcache_arch),
- buf + wordsize * PPC_LINUX_PT_NIP);
- right_supply_register (regcache, wordsize, regcache_tdep->ppc_lr_regnum,
- buf + wordsize * PPC_LINUX_PT_LNK);
- regcache_raw_supply (regcache, regcache_tdep->ppc_cr_regnum,
- buf + wordsize * PPC_LINUX_PT_CCR);
- regcache_raw_supply (regcache, regcache_tdep->ppc_xer_regnum,
- buf + wordsize * PPC_LINUX_PT_XER);
- regcache_raw_supply (regcache, regcache_tdep->ppc_ctr_regnum,
- buf + wordsize * PPC_LINUX_PT_CTR);
- if (regcache_tdep->ppc_mq_regnum != -1)
- right_supply_register (regcache, wordsize, regcache_tdep->ppc_mq_regnum,
- buf + wordsize * PPC_LINUX_PT_MQ);
- right_supply_register (regcache, wordsize, regcache_tdep->ppc_ps_regnum,
- buf + wordsize * PPC_LINUX_PT_MSR);
-}
+static const struct ppc_reg_offsets ppc64_linux_reg_offsets =
+ {
+ /* General-purpose registers. */
+ /* .r0_offset = */ 0,
+ /* .gpr_size = */ 8,
+ /* .xr_size = */ 8,
+ /* .pc_offset = */ 256,
+ /* .ps_offset = */ 264,
+ /* .cr_offset = */ 304,
+ /* .lr_offset = */ 288,
+ /* .ctr_offset = */ 280,
+ /* .xer_offset = */ 296,
+ /* .mq_offset = */ 312,
+
+ /* Floating-point registers. */
+ /* .f0_offset = */ 0,
+ /* .fpscr_offset = */ 256,
+ /* .fpscr_size = */ 8,
+
+ /* AltiVec registers. */
+ /* .vr0_offset = */ 0,
+ /* .vscr_offset = */ 512 + 12,
+ /* .vrsave_offset = */ 528
+ };
-static void
-ppc32_linux_supply_gregset (const struct regset *regset,
- struct regcache *regcache,
- int regnum, const void *gregs, size_t size)
-{
- ppc_linux_supply_gregset (regcache, regnum, gregs, size, 4);
-}
+static const struct regset ppc32_linux_gregset = {
+ &ppc32_linux_reg_offsets,
+ ppc_supply_gregset,
+ ppc_linux_collect_gregset,
+ NULL
+};
-static struct regset ppc32_linux_gregset = {
- NULL, ppc32_linux_supply_gregset
+static const struct regset ppc64_linux_gregset = {
+ &ppc64_linux_reg_offsets,
+ ppc_supply_gregset,
+ ppc_linux_collect_gregset,
+ NULL
};
-static void
-ppc64_linux_supply_gregset (const struct regset *regset,
- struct regcache * regcache,
- int regnum, const void *gregs, size_t size)
-{
- ppc_linux_supply_gregset (regcache, regnum, gregs, size, 8);
-}
+static const struct regset ppc32_linux_fpregset = {
+ &ppc32_linux_reg_offsets,
+ ppc_supply_fpregset,
+ ppc_collect_fpregset,
+ NULL
+};
-static struct regset ppc64_linux_gregset = {
- NULL, ppc64_linux_supply_gregset
+static const struct regset ppc32_linux_vrregset = {
+ &ppc32_linux_reg_offsets,
+ ppc_supply_vrregset,
+ ppc_collect_vrregset,
+ NULL
};
-void
-ppc_linux_supply_fpregset (const struct regset *regset,
- struct regcache * regcache,
- int regnum, const void *fpset, size_t size)
+const struct regset *
+ppc_linux_gregset (int wordsize)
{
- int regi;
- struct gdbarch *regcache_arch = get_regcache_arch (regcache);
- struct gdbarch_tdep *regcache_tdep = gdbarch_tdep (regcache_arch);
- const bfd_byte *buf = fpset;
-
- if (! ppc_floating_point_unit_p (regcache_arch))
- return;
-
- for (regi = 0; regi < ppc_num_fprs; regi++)
- regcache_raw_supply (regcache,
- regcache_tdep->ppc_fp0_regnum + regi,
- buf + 8 * regi);
-
- /* The FPSCR is stored in the low order word of the last
- doubleword in the fpregset. */
- regcache_raw_supply (regcache, regcache_tdep->ppc_fpscr_regnum,
- buf + 8 * 32 + 4);
+ return wordsize == 8 ? &ppc64_linux_gregset : &ppc32_linux_gregset;
}
-static struct regset ppc_linux_fpregset = { NULL, ppc_linux_supply_fpregset };
+const struct regset *
+ppc_linux_fpregset (void)
+{
+ return &ppc32_linux_fpregset;
+}
static const struct regset *
ppc_linux_regset_from_core_section (struct gdbarch *core_arch,
return &ppc64_linux_gregset;
}
if (strcmp (sect_name, ".reg2") == 0)
- return &ppc_linux_fpregset;
+ return &ppc32_linux_fpregset;
+ if (strcmp (sect_name, ".reg-ppc-vmx") == 0)
+ return &ppc32_linux_vrregset;
return NULL;
}
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
base = frame_unwind_register_unsigned (next_frame,
- gdbarch_sp_regnum (current_gdbarch));
+ gdbarch_sp_regnum (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. */
trad_frame_set_reg_addr (this_cache, regnum, gpregs + i * tdep->wordsize);
}
trad_frame_set_reg_addr (this_cache,
- gdbarch_pc_regnum (current_gdbarch),
+ gdbarch_pc_regnum (gdbarch),
gpregs + 32 * tdep->wordsize);
trad_frame_set_reg_addr (this_cache, tdep->ppc_ctr_regnum,
gpregs + 35 * tdep->wordsize);
/* Floating point registers. */
for (i = 0; i < 32; i++)
{
- int regnum = i + gdbarch_fp0_regnum (current_gdbarch);
+ int regnum = i + gdbarch_fp0_regnum (gdbarch);
trad_frame_set_reg_addr (this_cache, regnum,
fpregs + i * tdep->wordsize);
}
{
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);
+ /* PPC GNU/Linux uses either 64-bit or 128-bit long doubles; where
+ 128-bit, they are IBM long double, not IEEE quad long double as
+ in the System V ABI PowerPC Processor Supplement. We can safely
+ let them default to 128-bit, since the debug info will give the
+ size of type actually used in each case. */
+ set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
+ set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
/* Handle PPC GNU/Linux 64-bit function pointers (which are really
function descriptors) and 32-bit secure PLT entries. */