X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Frs6000-tdep.c;h=ead3500c26300c78c9d509833eb1dad7973bbe47;hb=refs%2Fheads%2Fconcurrent-displaced-stepping-2020-04-01;hp=fc12619a7b06ecec9da7e01845672681c0291402;hpb=40887e1a6e8bc0dfb421662f40c1a2c356c8b36d;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c index fc12619a7b..ead3500c26 100644 --- a/gdb/rs6000-tdep.c +++ b/gdb/rs6000-tdep.c @@ -1,8 +1,6 @@ /* Target-dependent code for GDB, the GNU debugger. - Copyright (C) 1986, 1987, 1989, 1991, 1992, 1993, 1994, 1995, 1996, 1997, - 1998, 1999, 2000, 2001, 2002, 2003, 2004, 2005, 2006, 2007, 2008 - Free Software Foundation, Inc. + Copyright (C) 1986-2020 Free Software Foundation, Inc. This file is part of GDB. @@ -22,6 +20,7 @@ #include "defs.h" #include "frame.h" #include "inferior.h" +#include "infrun.h" #include "symtab.h" #include "target.h" #include "gdbcore.h" @@ -30,7 +29,7 @@ #include "arch-utils.h" #include "regcache.h" #include "regset.h" -#include "doublest.h" +#include "target-float.h" #include "value.h" #include "parser-defs.h" #include "osabi.h" @@ -38,11 +37,12 @@ #include "sim-regno.h" #include "gdb/sim-ppc.h" #include "reggroups.h" -#include "dwarf2-frame.h" +#include "dwarf2/frame.h" #include "target-descriptions.h" #include "user-regs.h" +#include "record-full.h" +#include "auxv.h" -#include "libbfd.h" /* for bfd_default_set_arch_mach */ #include "coff/internal.h" /* for libcoff.h */ #include "libcoff.h" /* for xcoff_data */ #include "coff/xcoff.h" @@ -50,28 +50,36 @@ #include "elf-bfd.h" #include "elf/ppc.h" +#include "elf/ppc64.h" #include "solib-svr4.h" #include "ppc-tdep.h" +#include "ppc-ravenscar-thread.h" -#include "gdb_assert.h" #include "dis-asm.h" #include "trad-frame.h" #include "frame-unwind.h" #include "frame-base.h" -#include "rs6000-tdep.h" +#include "ax.h" +#include "ax-gdb.h" +#include #include "features/rs6000/powerpc-32.c" +#include "features/rs6000/powerpc-altivec32.c" +#include "features/rs6000/powerpc-vsx32.c" #include "features/rs6000/powerpc-403.c" #include "features/rs6000/powerpc-403gc.c" +#include "features/rs6000/powerpc-405.c" #include "features/rs6000/powerpc-505.c" #include "features/rs6000/powerpc-601.c" #include "features/rs6000/powerpc-602.c" #include "features/rs6000/powerpc-603.c" #include "features/rs6000/powerpc-604.c" #include "features/rs6000/powerpc-64.c" +#include "features/rs6000/powerpc-altivec64.c" +#include "features/rs6000/powerpc-vsx64.c" #include "features/rs6000/powerpc-7400.c" #include "features/rs6000/powerpc-750.c" #include "features/rs6000/powerpc-860.c" @@ -88,6 +96,42 @@ && (regnum) >= (tdep)->ppc_dl0_regnum \ && (regnum) < (tdep)->ppc_dl0_regnum + 16) +/* Determine if regnum is a "vX" alias for the raw "vrX" vector + registers. */ +#define IS_V_ALIAS_PSEUDOREG(tdep, regnum) (\ + (tdep)->ppc_v0_alias_regnum >= 0 \ + && (regnum) >= (tdep)->ppc_v0_alias_regnum \ + && (regnum) < (tdep)->ppc_v0_alias_regnum + ppc_num_vrs) + +/* Determine if regnum is a POWER7 VSX register. */ +#define IS_VSX_PSEUDOREG(tdep, regnum) ((tdep)->ppc_vsr0_regnum >= 0 \ + && (regnum) >= (tdep)->ppc_vsr0_regnum \ + && (regnum) < (tdep)->ppc_vsr0_regnum + ppc_num_vsrs) + +/* Determine if regnum is a POWER7 Extended FP register. */ +#define IS_EFP_PSEUDOREG(tdep, regnum) ((tdep)->ppc_efpr0_regnum >= 0 \ + && (regnum) >= (tdep)->ppc_efpr0_regnum \ + && (regnum) < (tdep)->ppc_efpr0_regnum + ppc_num_efprs) + +/* Determine if regnum is a checkpointed decimal float + pseudo-register. */ +#define IS_CDFP_PSEUDOREG(tdep, regnum) ((tdep)->ppc_cdl0_regnum >= 0 \ + && (regnum) >= (tdep)->ppc_cdl0_regnum \ + && (regnum) < (tdep)->ppc_cdl0_regnum + 16) + +/* Determine if regnum is a Checkpointed POWER7 VSX register. */ +#define IS_CVSX_PSEUDOREG(tdep, regnum) ((tdep)->ppc_cvsr0_regnum >= 0 \ + && (regnum) >= (tdep)->ppc_cvsr0_regnum \ + && (regnum) < (tdep)->ppc_cvsr0_regnum + ppc_num_vsrs) + +/* Determine if regnum is a Checkpointed POWER7 Extended FP register. */ +#define IS_CEFP_PSEUDOREG(tdep, regnum) ((tdep)->ppc_cefpr0_regnum >= 0 \ + && (regnum) >= (tdep)->ppc_cefpr0_regnum \ + && (regnum) < (tdep)->ppc_cefpr0_regnum + ppc_num_efprs) + +/* Holds the current set of options to be passed to the disassembler. */ +static char *powerpc_disassembler_options; + /* The list of available "set powerpc ..." and "show powerpc ..." commands. */ static struct cmd_list_element *setpowerpccmdlist = NULL; @@ -96,7 +140,7 @@ static struct cmd_list_element *showpowerpccmdlist = NULL; static enum auto_boolean powerpc_soft_float_global = AUTO_BOOLEAN_AUTO; /* The vector ABI to use. Keep this in sync with powerpc_vector_abi. */ -static const char *powerpc_vector_strings[] = +static const char *const powerpc_vector_strings[] = { "auto", "generic", @@ -109,18 +153,7 @@ static const char *powerpc_vector_strings[] = static enum powerpc_vector_abi powerpc_vector_abi_global = POWERPC_VEC_AUTO; static const char *powerpc_vector_abi_string = "auto"; -/* If the kernel has to deliver a signal, it pushes a sigcontext - structure on the stack and then calls the signal handler, passing - the address of the sigcontext in an argument register. Usually - the signal handler doesn't save this register, so we have to - access the sigcontext structure via an offset from the signal handler - frame. - The following constants were determined by experimentation on AIX 3.2. */ -#define SIG_FRAME_PC_OFFSET 96 -#define SIG_FRAME_LR_OFFSET 108 -#define SIG_FRAME_FP_OFFSET 284 - -/* To be used by skip_prologue. */ +/* To be used by skip_prologue. */ struct rs6000_framedata { @@ -128,47 +161,36 @@ struct rs6000_framedata by which we decrement sp to allocate the frame */ int saved_gpr; /* smallest # of saved gpr */ + unsigned int gpr_mask; /* Each bit is an individual saved GPR. */ int saved_fpr; /* smallest # of saved fpr */ int saved_vr; /* smallest # of saved vr */ int saved_ev; /* smallest # of saved ev */ int alloca_reg; /* alloca register number (frame ptr) */ - char frameless; /* true if frameless functions. */ - char nosavedpc; /* true if pc not saved. */ + char frameless; /* true if frameless functions. */ + char nosavedpc; /* true if pc not saved. */ + char used_bl; /* true if link register clobbered */ int gpr_offset; /* offset of saved gprs from prev sp */ int fpr_offset; /* offset of saved fprs from prev sp */ int vr_offset; /* offset of saved vrs from prev sp */ int ev_offset; /* offset of saved evs from prev sp */ int lr_offset; /* offset of saved lr */ + int lr_register; /* register of saved lr, if trustworthy */ int cr_offset; /* offset of saved cr */ int vrsave_offset; /* offset of saved vrsave register */ }; -/* Description of a single register. */ - -struct reg - { - char *name; /* name of register */ - unsigned char sz32; /* size on 32-bit arch, 0 if nonexistent */ - unsigned char sz64; /* size on 64-bit arch, 0 if nonexistent */ - unsigned char fpr; /* whether register is floating-point */ - unsigned char pseudo; /* whether register is pseudo */ - int spr_num; /* PowerPC SPR number, or -1 if not an SPR. - This is an ISA SPR number, not a GDB - register number. */ - }; - -/* Hook for determining the TOC address when calling functions in the - inferior under AIX. The initialization code in rs6000-nat.c sets - this hook to point to find_toc_address. */ - -CORE_ADDR (*rs6000_find_toc_address_hook) (CORE_ADDR) = NULL; - -/* Static function prototypes */ -static CORE_ADDR branch_dest (struct frame_info *frame, int opcode, - int instr, CORE_ADDR pc, CORE_ADDR safety); -static CORE_ADDR skip_prologue (struct gdbarch *, CORE_ADDR, CORE_ADDR, - struct rs6000_framedata *); +/* Is REGNO a VSX register? Return 1 if so, 0 otherwise. */ +int +vsx_register_p (struct gdbarch *gdbarch, int regno) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + if (tdep->ppc_vsr0_regnum < 0) + return 0; + else + return (regno >= tdep->ppc_vsr0_upper_regnum && regno + <= tdep->ppc_vsr0_upper_regnum + 31); +} /* Is REGNO an AltiVec register? Return 1 if so, 0 otherwise. */ int @@ -325,7 +347,7 @@ init_sim_regno_table (struct gdbarch *arch) set_sim_regno (sim_regno, tdep->ppc_acc_regnum, sim_ppc_acc_regnum); /* spefscr is a special-purpose register, so the code below handles it. */ -#ifdef WITH_SIM +#ifdef WITH_PPC_SIM /* Now handle all special-purpose registers. Verify that they haven't mistakenly been assigned numbers by any of the above code. */ @@ -358,9 +380,7 @@ rs6000_register_sim_regno (struct gdbarch *gdbarch, int reg) if (tdep->sim_regno == NULL) init_sim_regno_table (gdbarch); - gdb_assert (0 <= reg - && reg <= gdbarch_num_regs (gdbarch) - + gdbarch_num_pseudo_regs (gdbarch)); + gdb_assert (0 <= reg && reg <= gdbarch_num_cooked_regs (gdbarch)); sim_regno = tdep->sim_regno[reg]; if (sim_regno >= 0) @@ -376,7 +396,7 @@ rs6000_register_sim_regno (struct gdbarch *gdbarch, int reg) /* REGS + OFFSET contains register REGNUM in a field REGSIZE wide. Write the register to REGCACHE. */ -static void +void ppc_supply_reg (struct regcache *regcache, int regnum, const gdb_byte *regs, size_t offset, int regsize) { @@ -384,20 +404,20 @@ ppc_supply_reg (struct regcache *regcache, int regnum, { if (regsize > 4) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch = regcache->arch (); int gdb_regsize = register_size (gdbarch, regnum); if (gdb_regsize < regsize && gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) offset += regsize - gdb_regsize; } - regcache_raw_supply (regcache, regnum, regs + offset); + regcache->raw_supply (regnum, regs + offset); } } /* Read register REGNUM from REGCACHE and store to REGS + OFFSET in a field REGSIZE wide. Zero pad as necessary. */ -static void +void ppc_collect_reg (const struct regcache *regcache, int regnum, gdb_byte *regs, size_t offset, int regsize) { @@ -405,7 +425,7 @@ ppc_collect_reg (const struct regcache *regcache, int regnum, { if (regsize > 4) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch = regcache->arch (); int gdb_regsize = register_size (gdbarch, regnum); if (gdb_regsize < regsize) { @@ -419,7 +439,7 @@ ppc_collect_reg (const struct regcache *regcache, int regnum, regsize - gdb_regsize); } } - regcache_raw_collect (regcache, regnum, regs + offset); + regcache->raw_collect (regnum, regs + offset); } } @@ -476,24 +496,6 @@ ppc_fpreg_offset (struct gdbarch_tdep *tdep, return -1; } -static int -ppc_vrreg_offset (struct gdbarch_tdep *tdep, - const struct ppc_reg_offsets *offsets, - int regnum) -{ - if (regnum >= tdep->ppc_vr0_regnum - && regnum < tdep->ppc_vr0_regnum + ppc_num_vrs) - return offsets->vr0_offset + (regnum - tdep->ppc_vr0_regnum) * 16; - - if (regnum == tdep->ppc_vrsave_regnum - 1) - return offsets->vscr_offset; - - if (regnum == tdep->ppc_vrsave_regnum) - return offsets->vrsave_offset; - - return -1; -} - /* Supply register REGNUM in the general-purpose register set REGSET from the buffer specified by GREGS and LEN to register cache REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ @@ -502,9 +504,10 @@ void ppc_supply_gregset (const struct regset *regset, struct regcache *regcache, int regnum, const void *gregs, size_t len) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch = regcache->arch (); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - const struct ppc_reg_offsets *offsets = regset->descr; + const struct ppc_reg_offsets *offsets + = (const struct ppc_reg_offsets *) regset->regmap; size_t offset; int regsize; @@ -516,27 +519,31 @@ ppc_supply_gregset (const struct regset *regset, struct regcache *regcache, for (i = tdep->ppc_gp0_regnum, offset = offsets->r0_offset; i < tdep->ppc_gp0_regnum + ppc_num_gprs; i++, offset += gpr_size) - ppc_supply_reg (regcache, i, gregs, offset, gpr_size); + ppc_supply_reg (regcache, i, (const gdb_byte *) gregs, offset, + gpr_size); ppc_supply_reg (regcache, gdbarch_pc_regnum (gdbarch), - gregs, offsets->pc_offset, gpr_size); + (const gdb_byte *) gregs, offsets->pc_offset, gpr_size); ppc_supply_reg (regcache, tdep->ppc_ps_regnum, - gregs, offsets->ps_offset, gpr_size); + (const gdb_byte *) gregs, offsets->ps_offset, gpr_size); ppc_supply_reg (regcache, tdep->ppc_lr_regnum, - gregs, offsets->lr_offset, gpr_size); + (const gdb_byte *) gregs, offsets->lr_offset, gpr_size); ppc_supply_reg (regcache, tdep->ppc_ctr_regnum, - gregs, offsets->ctr_offset, gpr_size); + (const gdb_byte *) gregs, offsets->ctr_offset, gpr_size); ppc_supply_reg (regcache, tdep->ppc_cr_regnum, - gregs, offsets->cr_offset, offsets->xr_size); + (const gdb_byte *) gregs, offsets->cr_offset, + offsets->xr_size); ppc_supply_reg (regcache, tdep->ppc_xer_regnum, - gregs, offsets->xer_offset, offsets->xr_size); + (const gdb_byte *) gregs, offsets->xer_offset, + offsets->xr_size); ppc_supply_reg (regcache, tdep->ppc_mq_regnum, - gregs, offsets->mq_offset, offsets->xr_size); + (const gdb_byte *) gregs, offsets->mq_offset, + offsets->xr_size); return; } offset = ppc_greg_offset (gdbarch, tdep, offsets, regnum, ®size); - ppc_supply_reg (regcache, regnum, gregs, offset, regsize); + ppc_supply_reg (regcache, regnum, (const gdb_byte *) gregs, offset, regsize); } /* Supply register REGNUM in the floating-point register set REGSET @@ -547,7 +554,7 @@ void ppc_supply_fpregset (const struct regset *regset, struct regcache *regcache, int regnum, const void *fpregs, size_t len) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch = regcache->arch (); struct gdbarch_tdep *tdep; const struct ppc_reg_offsets *offsets; size_t offset; @@ -556,7 +563,7 @@ ppc_supply_fpregset (const struct regset *regset, struct regcache *regcache, return; tdep = gdbarch_tdep (gdbarch); - offsets = regset->descr; + offsets = (const struct ppc_reg_offsets *) regset->regmap; if (regnum == -1) { int i; @@ -564,62 +571,19 @@ ppc_supply_fpregset (const struct regset *regset, struct regcache *regcache, for (i = tdep->ppc_fp0_regnum, offset = offsets->f0_offset; i < tdep->ppc_fp0_regnum + ppc_num_fprs; i++, offset += 8) - ppc_supply_reg (regcache, i, fpregs, offset, 8); + ppc_supply_reg (regcache, i, (const gdb_byte *) fpregs, offset, 8); ppc_supply_reg (regcache, tdep->ppc_fpscr_regnum, - fpregs, offsets->fpscr_offset, offsets->fpscr_size); + (const gdb_byte *) fpregs, offsets->fpscr_offset, + offsets->fpscr_size); return; } offset = ppc_fpreg_offset (tdep, offsets, regnum); - ppc_supply_reg (regcache, regnum, fpregs, offset, + ppc_supply_reg (regcache, regnum, (const gdb_byte *) fpregs, offset, regnum == tdep->ppc_fpscr_regnum ? offsets->fpscr_size : 8); } -/* Supply register REGNUM in the Altivec register set REGSET - from the buffer specified by VRREGS and LEN to register cache - REGCACHE. If REGNUM is -1, do this for all registers in REGSET. */ - -void -ppc_supply_vrregset (const struct regset *regset, struct regcache *regcache, - int regnum, const void *vrregs, size_t len) -{ - struct gdbarch *gdbarch = get_regcache_arch (regcache); - struct gdbarch_tdep *tdep; - const struct ppc_reg_offsets *offsets; - size_t offset; - - if (!ppc_altivec_support_p (gdbarch)) - return; - - tdep = gdbarch_tdep (gdbarch); - offsets = regset->descr; - if (regnum == -1) - { - int i; - - for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset; - i < tdep->ppc_vr0_regnum + ppc_num_vrs; - i++, offset += 16) - ppc_supply_reg (regcache, i, vrregs, offset, 16); - - ppc_supply_reg (regcache, (tdep->ppc_vrsave_regnum - 1), - vrregs, offsets->vscr_offset, 4); - - ppc_supply_reg (regcache, tdep->ppc_vrsave_regnum, - vrregs, offsets->vrsave_offset, 4); - return; - } - - offset = ppc_vrreg_offset (tdep, offsets, regnum); - if (regnum != tdep->ppc_vrsave_regnum - && regnum != tdep->ppc_vrsave_regnum - 1) - ppc_supply_reg (regcache, regnum, vrregs, offset, 16); - else - ppc_supply_reg (regcache, regnum, - vrregs, offset, 4); -} - /* Collect register REGNUM in the general-purpose register set REGSET from register cache REGCACHE into the buffer specified by GREGS and LEN. If REGNUM is -1, do this for all registers in @@ -630,9 +594,10 @@ ppc_collect_gregset (const struct regset *regset, const struct regcache *regcache, int regnum, void *gregs, size_t len) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch = regcache->arch (); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - const struct ppc_reg_offsets *offsets = regset->descr; + const struct ppc_reg_offsets *offsets + = (const struct ppc_reg_offsets *) regset->regmap; size_t offset; int regsize; @@ -644,27 +609,30 @@ ppc_collect_gregset (const struct regset *regset, for (i = tdep->ppc_gp0_regnum, offset = offsets->r0_offset; i < tdep->ppc_gp0_regnum + ppc_num_gprs; i++, offset += gpr_size) - ppc_collect_reg (regcache, i, gregs, offset, gpr_size); + ppc_collect_reg (regcache, i, (gdb_byte *) gregs, offset, gpr_size); ppc_collect_reg (regcache, gdbarch_pc_regnum (gdbarch), - gregs, offsets->pc_offset, gpr_size); + (gdb_byte *) gregs, offsets->pc_offset, gpr_size); ppc_collect_reg (regcache, tdep->ppc_ps_regnum, - gregs, offsets->ps_offset, gpr_size); + (gdb_byte *) gregs, offsets->ps_offset, gpr_size); ppc_collect_reg (regcache, tdep->ppc_lr_regnum, - gregs, offsets->lr_offset, gpr_size); + (gdb_byte *) gregs, offsets->lr_offset, gpr_size); ppc_collect_reg (regcache, tdep->ppc_ctr_regnum, - gregs, offsets->ctr_offset, gpr_size); + (gdb_byte *) gregs, offsets->ctr_offset, gpr_size); ppc_collect_reg (regcache, tdep->ppc_cr_regnum, - gregs, offsets->cr_offset, offsets->xr_size); + (gdb_byte *) gregs, offsets->cr_offset, + offsets->xr_size); ppc_collect_reg (regcache, tdep->ppc_xer_regnum, - gregs, offsets->xer_offset, offsets->xr_size); + (gdb_byte *) gregs, offsets->xer_offset, + offsets->xr_size); ppc_collect_reg (regcache, tdep->ppc_mq_regnum, - gregs, offsets->mq_offset, offsets->xr_size); + (gdb_byte *) gregs, offsets->mq_offset, + offsets->xr_size); return; } offset = ppc_greg_offset (gdbarch, tdep, offsets, regnum, ®size); - ppc_collect_reg (regcache, regnum, gregs, offset, regsize); + ppc_collect_reg (regcache, regnum, (gdb_byte *) gregs, offset, regsize); } /* Collect register REGNUM in the floating-point register set @@ -677,7 +645,7 @@ ppc_collect_fpregset (const struct regset *regset, const struct regcache *regcache, int regnum, void *fpregs, size_t len) { - struct gdbarch *gdbarch = get_regcache_arch (regcache); + struct gdbarch *gdbarch = regcache->arch (); struct gdbarch_tdep *tdep; const struct ppc_reg_offsets *offsets; size_t offset; @@ -686,7 +654,7 @@ ppc_collect_fpregset (const struct regset *regset, return; tdep = gdbarch_tdep (gdbarch); - offsets = regset->descr; + offsets = (const struct ppc_reg_offsets *) regset->regmap; if (regnum == -1) { int i; @@ -694,103 +662,19 @@ ppc_collect_fpregset (const struct regset *regset, for (i = tdep->ppc_fp0_regnum, offset = offsets->f0_offset; i < tdep->ppc_fp0_regnum + ppc_num_fprs; i++, offset += 8) - ppc_collect_reg (regcache, i, fpregs, offset, 8); + ppc_collect_reg (regcache, i, (gdb_byte *) fpregs, offset, 8); ppc_collect_reg (regcache, tdep->ppc_fpscr_regnum, - fpregs, offsets->fpscr_offset, offsets->fpscr_size); + (gdb_byte *) fpregs, offsets->fpscr_offset, + offsets->fpscr_size); return; } offset = ppc_fpreg_offset (tdep, offsets, regnum); - ppc_collect_reg (regcache, regnum, fpregs, offset, + ppc_collect_reg (regcache, regnum, (gdb_byte *) fpregs, offset, regnum == tdep->ppc_fpscr_regnum ? offsets->fpscr_size : 8); } -/* Collect register REGNUM in the Altivec register set - REGSET from register cache REGCACHE into the buffer specified by - VRREGS and LEN. If REGNUM is -1, do this for all registers in - REGSET. */ - -void -ppc_collect_vrregset (const struct regset *regset, - const struct regcache *regcache, - int regnum, void *vrregs, size_t len) -{ - struct gdbarch *gdbarch = get_regcache_arch (regcache); - struct gdbarch_tdep *tdep; - const struct ppc_reg_offsets *offsets; - size_t offset; - - if (!ppc_altivec_support_p (gdbarch)) - return; - - tdep = gdbarch_tdep (gdbarch); - offsets = regset->descr; - if (regnum == -1) - { - int i; - - for (i = tdep->ppc_vr0_regnum, offset = offsets->vr0_offset; - i < tdep->ppc_vr0_regnum + ppc_num_vrs; - i++, offset += 16) - ppc_collect_reg (regcache, i, vrregs, offset, 16); - - ppc_collect_reg (regcache, (tdep->ppc_vrsave_regnum - 1), - vrregs, offsets->vscr_offset, 4); - - ppc_collect_reg (regcache, tdep->ppc_vrsave_regnum, - vrregs, offsets->vrsave_offset, 4); - return; - } - - offset = ppc_vrreg_offset (tdep, offsets, regnum); - if (regnum != tdep->ppc_vrsave_regnum - && regnum != tdep->ppc_vrsave_regnum - 1) - ppc_collect_reg (regcache, regnum, vrregs, offset, 16); - else - ppc_collect_reg (regcache, regnum, - vrregs, offset, 4); -} - - -/* Read a LEN-byte address from debugged memory address MEMADDR. */ - -static CORE_ADDR -read_memory_addr (CORE_ADDR memaddr, int len) -{ - return read_memory_unsigned_integer (memaddr, len); -} - -static CORE_ADDR -rs6000_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) -{ - struct rs6000_framedata frame; - CORE_ADDR limit_pc, func_addr; - - /* See if we can determine the end of the prologue via the symbol table. - If so, then return either PC, or the PC after the prologue, whichever - is greater. */ - if (find_pc_partial_function (pc, NULL, &func_addr, NULL)) - { - CORE_ADDR post_prologue_pc = skip_prologue_using_sal (func_addr); - if (post_prologue_pc != 0) - return max (pc, post_prologue_pc); - } - - /* Can't determine prologue from the symbol table, need to examine - instructions. */ - - /* Find an upper limit on the function prologue using the debug - information. If the debug information could not be used to provide - that bound, then use an arbitrary large number as the upper bound. */ - limit_pc = skip_prologue_using_sal (pc); - if (limit_pc == 0) - limit_pc = pc + 100; /* Magic. */ - - pc = skip_prologue (gdbarch, pc, limit_pc, &frame); - return pc; -} - static int insn_changes_sp_or_jumps (unsigned long insn) { @@ -844,12 +728,14 @@ insn_changes_sp_or_jumps (unsigned long insn) limit for the size of an epilogue. */ static int -rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) +rs6000_in_function_epilogue_frame_p (struct frame_info *curfrm, + struct gdbarch *gdbarch, CORE_ADDR pc) { + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); bfd_byte insn_buf[PPC_INSN_SIZE]; CORE_ADDR scan_pc, func_start, func_end, epilogue_start, epilogue_end; unsigned long insn; - struct frame_info *curfrm; /* Find the search limits based on function boundaries and hard limit. */ @@ -862,17 +748,26 @@ rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) epilogue_end = pc + PPC_MAX_EPILOGUE_INSTRUCTIONS * PPC_INSN_SIZE; if (epilogue_end > func_end) epilogue_end = func_end; - curfrm = get_current_frame (); - /* Scan forward until next 'blr'. */ for (scan_pc = pc; scan_pc < epilogue_end; scan_pc += PPC_INSN_SIZE) { if (!safe_frame_unwind_memory (curfrm, scan_pc, insn_buf, PPC_INSN_SIZE)) return 0; - insn = extract_unsigned_integer (insn_buf, PPC_INSN_SIZE); + insn = extract_unsigned_integer (insn_buf, PPC_INSN_SIZE, byte_order); if (insn == 0x4e800020) break; + /* Assume a bctr is a tail call unless it points strictly within + this function. */ + if (insn == 0x4e800420) + { + CORE_ADDR ctr = get_frame_register_unsigned (curfrm, + tdep->ppc_ctr_regnum); + if (ctr > func_start && ctr < func_end) + return 0; + else + break; + } if (insn_changes_sp_or_jumps (insn)) return 0; } @@ -885,7 +780,7 @@ rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) { if (!safe_frame_unwind_memory (curfrm, scan_pc, insn_buf, PPC_INSN_SIZE)) return 0; - insn = extract_unsigned_integer (insn_buf, PPC_INSN_SIZE); + insn = extract_unsigned_integer (insn_buf, PPC_INSN_SIZE, byte_order); if (insn_changes_sp_or_jumps (insn)) return 1; } @@ -893,6 +788,15 @@ rs6000_in_function_epilogue_p (struct gdbarch *gdbarch, CORE_ADDR pc) return 0; } +/* Implement the stack_frame_destroyed_p gdbarch method. */ + +static int +rs6000_stack_frame_destroyed_p (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + return rs6000_in_function_epilogue_frame_p (get_current_frame (), + gdbarch, pc); +} + /* Get the ith function argument for the current function. */ static CORE_ADDR rs6000_fetch_pointer_argument (struct frame_info *frame, int argi, @@ -901,226 +805,282 @@ rs6000_fetch_pointer_argument (struct frame_info *frame, int argi, return get_frame_register_unsigned (frame, 3 + argi); } -/* Calculate the destination of a branch/jump. Return -1 if not a branch. */ +/* Sequence of bytes for breakpoint instruction. */ -static CORE_ADDR -branch_dest (struct frame_info *frame, int opcode, int instr, - CORE_ADDR pc, CORE_ADDR safety) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (get_frame_arch (frame)); - CORE_ADDR dest; - int immediate; - int absolute; - int ext_op; +constexpr gdb_byte big_breakpoint[] = { 0x7d, 0x82, 0x10, 0x08 }; +constexpr gdb_byte little_breakpoint[] = { 0x08, 0x10, 0x82, 0x7d }; - absolute = (int) ((instr >> 1) & 1); +typedef BP_MANIPULATION_ENDIAN (little_breakpoint, big_breakpoint) + rs6000_breakpoint; - switch (opcode) - { - case 18: - immediate = ((instr & ~3) << 6) >> 6; /* br unconditional */ - if (absolute) - dest = immediate; - else - dest = pc + immediate; - break; +/* Instruction masks for displaced stepping. */ +#define BRANCH_MASK 0xfc000000 +#define BP_MASK 0xFC0007FE +#define B_INSN 0x48000000 +#define BC_INSN 0x40000000 +#define BXL_INSN 0x4c000000 +#define BP_INSN 0x7C000008 - case 16: - immediate = ((instr & ~3) << 16) >> 16; /* br conditional */ - if (absolute) - dest = immediate; - else - dest = pc + immediate; - break; +/* Instruction masks used during single-stepping of atomic + sequences. */ +#define LOAD_AND_RESERVE_MASK 0xfc0007fe +#define LWARX_INSTRUCTION 0x7c000028 +#define LDARX_INSTRUCTION 0x7c0000A8 +#define LBARX_INSTRUCTION 0x7c000068 +#define LHARX_INSTRUCTION 0x7c0000e8 +#define LQARX_INSTRUCTION 0x7c000228 +#define STORE_CONDITIONAL_MASK 0xfc0007ff +#define STWCX_INSTRUCTION 0x7c00012d +#define STDCX_INSTRUCTION 0x7c0001ad +#define STBCX_INSTRUCTION 0x7c00056d +#define STHCX_INSTRUCTION 0x7c0005ad +#define STQCX_INSTRUCTION 0x7c00016d + +/* Check if insn is one of the Load And Reserve instructions used for atomic + sequences. */ +#define IS_LOAD_AND_RESERVE_INSN(insn) ((insn & LOAD_AND_RESERVE_MASK) == LWARX_INSTRUCTION \ + || (insn & LOAD_AND_RESERVE_MASK) == LDARX_INSTRUCTION \ + || (insn & LOAD_AND_RESERVE_MASK) == LBARX_INSTRUCTION \ + || (insn & LOAD_AND_RESERVE_MASK) == LHARX_INSTRUCTION \ + || (insn & LOAD_AND_RESERVE_MASK) == LQARX_INSTRUCTION) +/* Check if insn is one of the Store Conditional instructions used for atomic + sequences. */ +#define IS_STORE_CONDITIONAL_INSN(insn) ((insn & STORE_CONDITIONAL_MASK) == STWCX_INSTRUCTION \ + || (insn & STORE_CONDITIONAL_MASK) == STDCX_INSTRUCTION \ + || (insn & STORE_CONDITIONAL_MASK) == STBCX_INSTRUCTION \ + || (insn & STORE_CONDITIONAL_MASK) == STHCX_INSTRUCTION \ + || (insn & STORE_CONDITIONAL_MASK) == STQCX_INSTRUCTION) + +typedef buf_displaced_step_copy_insn_closure ppc_displaced_step_copy_insn_closure; + +/* We can't displaced step atomic sequences. */ + +static displaced_step_copy_insn_closure_up +ppc_displaced_step_copy_insn (struct gdbarch *gdbarch, + CORE_ADDR from, CORE_ADDR to, + struct regcache *regs) +{ + size_t len = gdbarch_max_insn_length (gdbarch); + std::unique_ptr closure + (new ppc_displaced_step_copy_insn_closure (len)); + gdb_byte *buf = closure->buf.data (); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + int insn; - case 19: - ext_op = (instr >> 1) & 0x3ff; + read_memory (from, buf, len); - if (ext_op == 16) /* br conditional register */ - { - dest = get_frame_register_unsigned (frame, tdep->ppc_lr_regnum) & ~3; + insn = extract_signed_integer (buf, PPC_INSN_SIZE, byte_order); - /* If we are about to return from a signal handler, dest is - something like 0x3c90. The current frame is a signal handler - caller frame, upon completion of the sigreturn system call - execution will return to the saved PC in the frame. */ - if (dest < tdep->text_segment_base) - dest = read_memory_addr (get_frame_base (frame) + SIG_FRAME_PC_OFFSET, - tdep->wordsize); + /* Assume all atomic sequences start with a Load and Reserve instruction. */ + if (IS_LOAD_AND_RESERVE_INSN (insn)) + { + if (debug_displaced) + { + fprintf_unfiltered (gdb_stdlog, + "displaced: can't displaced step " + "atomic sequence at %s\n", + paddress (gdbarch, from)); } - else if (ext_op == 528) /* br cond to count reg */ - { - dest = get_frame_register_unsigned (frame, tdep->ppc_ctr_regnum) & ~3; + return NULL; + } - /* If we are about to execute a system call, dest is something - like 0x22fc or 0x3b00. Upon completion the system call - will return to the address in the link register. */ - if (dest < tdep->text_segment_base) - dest = get_frame_register_unsigned (frame, tdep->ppc_lr_regnum) & ~3; - } - else - return -1; - break; + write_memory (to, buf, len); - default: - return -1; + if (debug_displaced) + { + fprintf_unfiltered (gdb_stdlog, "displaced: copy %s->%s: ", + paddress (gdbarch, from), paddress (gdbarch, to)); + displaced_step_dump_bytes (gdb_stdlog, buf, len); } - return (dest < tdep->text_segment_base) ? safety : dest; + + /* This is a work around for a problem with g++ 4.8. */ + return displaced_step_copy_insn_closure_up (closure.release ()); } +/* Fix up the state of registers and memory after having single-stepped + a displaced instruction. */ +static void +ppc_displaced_step_fixup (struct gdbarch *gdbarch, + struct displaced_step_copy_insn_closure *closure_, + CORE_ADDR from, CORE_ADDR to, + struct regcache *regs) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + /* Our closure is a copy of the instruction. */ + ppc_displaced_step_copy_insn_closure *closure = (ppc_displaced_step_copy_insn_closure *) closure_; + ULONGEST insn = extract_unsigned_integer (closure->buf.data (), + PPC_INSN_SIZE, byte_order); + ULONGEST opcode = 0; + /* Offset for non PC-relative instructions. */ + LONGEST offset = PPC_INSN_SIZE; -/* Sequence of bytes for breakpoint instruction. */ + opcode = insn & BRANCH_MASK; -const static unsigned char * -rs6000_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *bp_addr, - int *bp_size) -{ - static unsigned char big_breakpoint[] = { 0x7d, 0x82, 0x10, 0x08 }; - static unsigned char little_breakpoint[] = { 0x08, 0x10, 0x82, 0x7d }; - *bp_size = 4; - if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) - return big_breakpoint; - else - return little_breakpoint; -} + if (debug_displaced) + fprintf_unfiltered (gdb_stdlog, + "displaced: (ppc) fixup (%s, %s)\n", + paddress (gdbarch, from), paddress (gdbarch, to)); -/* Instruction masks used during single-stepping of atomic sequences. */ -#define LWARX_MASK 0xfc0007fe -#define LWARX_INSTRUCTION 0x7c000028 -#define LDARX_INSTRUCTION 0x7c0000A8 -#define STWCX_MASK 0xfc0007ff -#define STWCX_INSTRUCTION 0x7c00012d -#define STDCX_INSTRUCTION 0x7c0001ad -#define BC_MASK 0xfc000000 -#define BC_INSTRUCTION 0x40000000 + /* Handle PC-relative branch instructions. */ + if (opcode == B_INSN || opcode == BC_INSN || opcode == BXL_INSN) + { + ULONGEST current_pc; -/* Checks for an atomic sequence of instructions beginning with a LWARX/LDARX - instruction and ending with a STWCX/STDCX instruction. If such a sequence - is found, attempt to step through it. A breakpoint is placed at the end of - the sequence. */ + /* Read the current PC value after the instruction has been executed + in a displaced location. Calculate the offset to be applied to the + original PC value before the displaced stepping. */ + regcache_cooked_read_unsigned (regs, gdbarch_pc_regnum (gdbarch), + ¤t_pc); + offset = current_pc - to; -static int -deal_with_atomic_sequence (struct frame_info *frame) + if (opcode != BXL_INSN) + { + /* Check for AA bit indicating whether this is an absolute + addressing or PC-relative (1: absolute, 0: relative). */ + if (!(insn & 0x2)) + { + /* PC-relative addressing is being used in the branch. */ + if (debug_displaced) + fprintf_unfiltered + (gdb_stdlog, + "displaced: (ppc) branch instruction: %s\n" + "displaced: (ppc) adjusted PC from %s to %s\n", + paddress (gdbarch, insn), paddress (gdbarch, current_pc), + paddress (gdbarch, from + offset)); + + regcache_cooked_write_unsigned (regs, + gdbarch_pc_regnum (gdbarch), + from + offset); + } + } + else + { + /* If we're here, it means we have a branch to LR or CTR. If the + branch was taken, the offset is probably greater than 4 (the next + instruction), so it's safe to assume that an offset of 4 means we + did not take the branch. */ + if (offset == PPC_INSN_SIZE) + regcache_cooked_write_unsigned (regs, gdbarch_pc_regnum (gdbarch), + from + PPC_INSN_SIZE); + } + + /* Check for LK bit indicating whether we should set the link + register to point to the next instruction + (1: Set, 0: Don't set). */ + if (insn & 0x1) + { + /* Link register needs to be set to the next instruction's PC. */ + regcache_cooked_write_unsigned (regs, + gdbarch_tdep (gdbarch)->ppc_lr_regnum, + from + PPC_INSN_SIZE); + if (debug_displaced) + fprintf_unfiltered (gdb_stdlog, + "displaced: (ppc) adjusted LR to %s\n", + paddress (gdbarch, from + PPC_INSN_SIZE)); + + } + } + /* Check for breakpoints in the inferior. If we've found one, place the PC + right at the breakpoint instruction. */ + else if ((insn & BP_MASK) == BP_INSN) + regcache_cooked_write_unsigned (regs, gdbarch_pc_regnum (gdbarch), from); + else + /* Handle any other instructions that do not fit in the categories above. */ + regcache_cooked_write_unsigned (regs, gdbarch_pc_regnum (gdbarch), + from + offset); +} + +/* Always use hardware single-stepping to execute the + displaced instruction. */ +static int +ppc_displaced_step_hw_singlestep (struct gdbarch *gdbarch, + struct displaced_step_copy_insn_closure *closure) { - CORE_ADDR pc = get_frame_pc (frame); - CORE_ADDR breaks[2] = {-1, -1}; + return 1; +} + +/* Checks for an atomic sequence of instructions beginning with a + Load And Reserve instruction and ending with a Store Conditional + instruction. If such a sequence is found, attempt to step through it. + A breakpoint is placed at the end of the sequence. */ +std::vector +ppc_deal_with_atomic_sequence (struct regcache *regcache) +{ + struct gdbarch *gdbarch = regcache->arch (); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + CORE_ADDR pc = regcache_read_pc (regcache); + CORE_ADDR breaks[2] = {CORE_ADDR_MAX, CORE_ADDR_MAX}; CORE_ADDR loc = pc; - CORE_ADDR branch_bp; /* Breakpoint at branch instruction's destination. */ CORE_ADDR closing_insn; /* Instruction that closes the atomic sequence. */ - int insn = read_memory_integer (loc, PPC_INSN_SIZE); + int insn = read_memory_integer (loc, PPC_INSN_SIZE, byte_order); int insn_count; int index; int last_breakpoint = 0; /* Defaults to 0 (no breakpoints placed). */ const int atomic_sequence_length = 16; /* Instruction sequence length. */ - int opcode; /* Branch instruction's OPcode. */ int bc_insn_count = 0; /* Conditional branch instruction count. */ - /* Assume all atomic sequences start with a lwarx/ldarx instruction. */ - if ((insn & LWARX_MASK) != LWARX_INSTRUCTION - && (insn & LWARX_MASK) != LDARX_INSTRUCTION) - return 0; + /* Assume all atomic sequences start with a Load And Reserve instruction. */ + if (!IS_LOAD_AND_RESERVE_INSN (insn)) + return {}; /* Assume that no atomic sequence is longer than "atomic_sequence_length" instructions. */ for (insn_count = 0; insn_count < atomic_sequence_length; ++insn_count) { loc += PPC_INSN_SIZE; - insn = read_memory_integer (loc, PPC_INSN_SIZE); + insn = read_memory_integer (loc, PPC_INSN_SIZE, byte_order); /* Assume that there is at most one conditional branch in the atomic sequence. If a conditional branch is found, put a breakpoint in its destination address. */ - if ((insn & BC_MASK) == BC_INSTRUCTION) + if ((insn & BRANCH_MASK) == BC_INSN) { + int immediate = ((insn & 0xfffc) ^ 0x8000) - 0x8000; + int absolute = insn & 2; + if (bc_insn_count >= 1) - return 0; /* More than one conditional branch found, fallback - to the standard single-step code. */ - - opcode = insn >> 26; - branch_bp = branch_dest (frame, opcode, insn, pc, breaks[0]); - - if (branch_bp != -1) - { - breaks[1] = branch_bp; - bc_insn_count++; - last_breakpoint++; - } + return {}; /* More than one conditional branch found, fallback + to the standard single-step code. */ + + if (absolute) + breaks[1] = immediate; + else + breaks[1] = loc + immediate; + + bc_insn_count++; + last_breakpoint++; } - if ((insn & STWCX_MASK) == STWCX_INSTRUCTION - || (insn & STWCX_MASK) == STDCX_INSTRUCTION) + if (IS_STORE_CONDITIONAL_INSN (insn)) break; } - /* Assume that the atomic sequence ends with a stwcx/stdcx instruction. */ - if ((insn & STWCX_MASK) != STWCX_INSTRUCTION - && (insn & STWCX_MASK) != STDCX_INSTRUCTION) - return 0; + /* Assume that the atomic sequence ends with a Store Conditional + instruction. */ + if (!IS_STORE_CONDITIONAL_INSN (insn)) + return {}; closing_insn = loc; loc += PPC_INSN_SIZE; - insn = read_memory_integer (loc, PPC_INSN_SIZE); /* Insert a breakpoint right after the end of the atomic sequence. */ breaks[0] = loc; /* Check for duplicated breakpoints. Check also for a breakpoint - placed (branch instruction's destination) at the stwcx/stdcx - instruction, this resets the reservation and take us back to the - lwarx/ldarx instruction at the beginning of the atomic sequence. */ - if (last_breakpoint && ((breaks[1] == breaks[0]) - || (breaks[1] == closing_insn))) + placed (branch instruction's destination) anywhere in sequence. */ + if (last_breakpoint + && (breaks[1] == breaks[0] + || (breaks[1] >= pc && breaks[1] <= closing_insn))) last_breakpoint = 0; - /* Effectively inserts the breakpoints. */ - for (index = 0; index <= last_breakpoint; index++) - insert_single_step_breakpoint (breaks[index]); - - return 1; -} - -/* AIX does not support PT_STEP. Simulate it. */ - -int -rs6000_software_single_step (struct frame_info *frame) -{ - CORE_ADDR dummy; - int breakp_sz; - const gdb_byte *breakp - = rs6000_breakpoint_from_pc (get_frame_arch (frame), &dummy, &breakp_sz); - int ii, insn; - CORE_ADDR loc; - CORE_ADDR breaks[2]; - int opcode; - - loc = get_frame_pc (frame); - - insn = read_memory_integer (loc, 4); - - if (deal_with_atomic_sequence (frame)) - return 1; - - breaks[0] = loc + breakp_sz; - opcode = insn >> 26; - breaks[1] = branch_dest (frame, opcode, insn, loc, breaks[0]); + std::vector next_pcs; - /* Don't put two breakpoints on the same address. */ - if (breaks[1] == breaks[0]) - breaks[1] = -1; - - for (ii = 0; ii < 2; ++ii) - { - /* ignore invalid breakpoint. */ - if (breaks[ii] == -1) - continue; - insert_single_step_breakpoint (breaks[ii]); - } + for (index = 0; index <= last_breakpoint; index++) + next_pcs.push_back (breaks[index]); - errno = 0; /* FIXME, don't ignore errors! */ - /* What errors? {read,write}_memory call error(). */ - return 1; + return next_pcs; } @@ -1214,7 +1174,7 @@ store_param_on_stack_p (unsigned long op, int framep, int *r0_contains_arg) they can use to access PIC data using PC-relative offsets. */ static int -bl_to_blrl_insn_p (CORE_ADDR pc, int insn) +bl_to_blrl_insn_p (CORE_ADDR pc, int insn, enum bfd_endian byte_order) { CORE_ADDR dest; int immediate; @@ -1228,77 +1188,310 @@ bl_to_blrl_insn_p (CORE_ADDR pc, int insn) else dest = pc + immediate; - dest_insn = read_memory_integer (dest, 4); + dest_insn = read_memory_integer (dest, 4, byte_order); if ((dest_insn & 0xfc00ffff) == 0x4c000021) /* blrl */ return 1; return 0; } -/* return pc value after skipping a function prologue and also return - information about a function frame. +/* Return true if OP is a stw or std instruction with + register operands RS and RA and any immediate offset. - in struct rs6000_framedata fdata: - - frameless is TRUE, if function does not have a frame. - - nosavedpc is TRUE, if function does not save %pc value in its frame. - - offset is the initial size of this stack frame --- the amount by - which we decrement the sp to allocate the frame. - - saved_gpr is the number of the first saved gpr. - - saved_fpr is the number of the first saved fpr. - - saved_vr is the number of the first saved vr. - - saved_ev is the number of the first saved ev. - - alloca_reg is the number of the register used for alloca() handling. - Otherwise -1. - - gpr_offset is the offset of the first saved gpr from the previous frame. - - fpr_offset is the offset of the first saved fpr from the previous frame. - - vr_offset is the offset of the first saved vr from the previous frame. - - ev_offset is the offset of the first saved ev from the previous frame. - - lr_offset is the offset of the saved lr - - cr_offset is the offset of the saved cr - - vrsave_offset is the offset of the saved vrsave register - */ + If WITH_UPDATE is true, also return true if OP is + a stwu or stdu instruction with the same operands. -static CORE_ADDR -skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, - struct rs6000_framedata *fdata) + Return false otherwise. + */ +static bool +store_insn_p (unsigned long op, unsigned long rs, + unsigned long ra, bool with_update) { - CORE_ADDR orig_pc = pc; - CORE_ADDR last_prologue_pc = pc; - CORE_ADDR li_found_pc = 0; - gdb_byte buf[4]; - unsigned long op; - long offset = 0; - long vr_saved_offset = 0; - int lr_reg = -1; - int cr_reg = -1; - int vr_reg = -1; - int ev_reg = -1; - long ev_offset = 0; - int vrsave_reg = -1; - int reg; - int framep = 0; - int minimal_toc_loaded = 0; - int prev_insn_was_prologue_insn = 1; - int num_skip_non_prologue_insns = 0; - int r0_contains_arg = 0; - const struct bfd_arch_info *arch_info = gdbarch_bfd_arch_info (gdbarch); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + rs = rs << 21; + ra = ra << 16; - memset (fdata, 0, sizeof (struct rs6000_framedata)); - fdata->saved_gpr = -1; - fdata->saved_fpr = -1; - fdata->saved_vr = -1; - fdata->saved_ev = -1; - fdata->alloca_reg = -1; - fdata->frameless = 1; - fdata->nosavedpc = 1; + if (/* std RS, SIMM(RA) */ + ((op & 0xffff0003) == (rs | ra | 0xf8000000)) || + /* stw RS, SIMM(RA) */ + ((op & 0xffff0000) == (rs | ra | 0x90000000))) + return true; - for (;; pc += 4) + if (with_update) + { + if (/* stdu RS, SIMM(RA) */ + ((op & 0xffff0003) == (rs | ra | 0xf8000001)) || + /* stwu RS, SIMM(RA) */ + ((op & 0xffff0000) == (rs | ra | 0x94000000))) + return true; + } + + return false; +} + +/* Masks for decoding a branch-and-link (bl) instruction. + + BL_MASK and BL_INSTRUCTION are used in combination with each other. + The former is anded with the opcode in question; if the result of + this masking operation is equal to BL_INSTRUCTION, then the opcode in + question is a ``bl'' instruction. + + BL_DISPLACEMENT_MASK is anded with the opcode in order to extract + the branch displacement. */ + +#define BL_MASK 0xfc000001 +#define BL_INSTRUCTION 0x48000001 +#define BL_DISPLACEMENT_MASK 0x03fffffc + +static unsigned long +rs6000_fetch_instruction (struct gdbarch *gdbarch, const CORE_ADDR pc) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + gdb_byte buf[4]; + unsigned long op; + + /* Fetch the instruction and convert it to an integer. */ + if (target_read_memory (pc, buf, 4)) + return 0; + op = extract_unsigned_integer (buf, 4, byte_order); + + return op; +} + +/* GCC generates several well-known sequences of instructions at the begining + of each function prologue when compiling with -fstack-check. If one of + such sequences starts at START_PC, then return the address of the + instruction immediately past this sequence. Otherwise, return START_PC. */ + +static CORE_ADDR +rs6000_skip_stack_check (struct gdbarch *gdbarch, const CORE_ADDR start_pc) +{ + CORE_ADDR pc = start_pc; + unsigned long op = rs6000_fetch_instruction (gdbarch, pc); + + /* First possible sequence: A small number of probes. + stw 0, -(1) + [repeat this instruction any (small) number of times]. */ + + if ((op & 0xffff0000) == 0x90010000) + { + while ((op & 0xffff0000) == 0x90010000) + { + pc = pc + 4; + op = rs6000_fetch_instruction (gdbarch, pc); + } + return pc; + } + + /* Second sequence: A probing loop. + addi 12,1,- + lis 0,- + [possibly ori 0,0,] + add 0,12,0 + cmpw 0,12,0 + beq 0, + addi 12,12,- + stw 0,0(12) + b + [possibly one last probe: stw 0,(12)]. */ + + while (1) + { + /* addi 12,1,- */ + if ((op & 0xffff0000) != 0x39810000) + break; + + /* lis 0,- */ + pc = pc + 4; + op = rs6000_fetch_instruction (gdbarch, pc); + if ((op & 0xffff0000) != 0x3c000000) + break; + + pc = pc + 4; + op = rs6000_fetch_instruction (gdbarch, pc); + /* [possibly ori 0,0,] */ + if ((op & 0xffff0000) == 0x60000000) + { + pc = pc + 4; + op = rs6000_fetch_instruction (gdbarch, pc); + } + /* add 0,12,0 */ + if (op != 0x7c0c0214) + break; + + /* cmpw 0,12,0 */ + pc = pc + 4; + op = rs6000_fetch_instruction (gdbarch, pc); + if (op != 0x7c0c0000) + break; + + /* beq 0, */ + pc = pc + 4; + op = rs6000_fetch_instruction (gdbarch, pc); + if ((op & 0xff9f0001) != 0x41820000) + break; + + /* addi 12,12,- */ + pc = pc + 4; + op = rs6000_fetch_instruction (gdbarch, pc); + if ((op & 0xffff0000) != 0x398c0000) + break; + + /* stw 0,0(12) */ + pc = pc + 4; + op = rs6000_fetch_instruction (gdbarch, pc); + if (op != 0x900c0000) + break; + + /* b */ + pc = pc + 4; + op = rs6000_fetch_instruction (gdbarch, pc); + if ((op & 0xfc000001) != 0x48000000) + break; + + /* [possibly one last probe: stw 0,(12)]. */ + pc = pc + 4; + op = rs6000_fetch_instruction (gdbarch, pc); + if ((op & 0xffff0000) == 0x900c0000) + { + pc = pc + 4; + op = rs6000_fetch_instruction (gdbarch, pc); + } + + /* We found a valid stack-check sequence, return the new PC. */ + return pc; + } + + /* Third sequence: No probe; instead, a comparison between the stack size + limit (saved in a run-time global variable) and the current stack + pointer: + + addi 0,1,- + lis 12,__gnat_stack_limit@ha + lwz 12,__gnat_stack_limit@l(12) + twllt 0,12 + + or, with a small variant in the case of a bigger stack frame: + addis 0,1, + addic 0,0,- + lis 12,__gnat_stack_limit@ha + lwz 12,__gnat_stack_limit@l(12) + twllt 0,12 + */ + while (1) + { + /* addi 0,1,- */ + if ((op & 0xffff0000) != 0x38010000) + { + /* small stack frame variant not recognized; try the + big stack frame variant: */ + + /* addis 0,1, */ + if ((op & 0xffff0000) != 0x3c010000) + break; + + /* addic 0,0,- */ + pc = pc + 4; + op = rs6000_fetch_instruction (gdbarch, pc); + if ((op & 0xffff0000) != 0x30000000) + break; + } + + /* lis 12, */ + pc = pc + 4; + op = rs6000_fetch_instruction (gdbarch, pc); + if ((op & 0xffff0000) != 0x3d800000) + break; + + /* lwz 12,(12) */ + pc = pc + 4; + op = rs6000_fetch_instruction (gdbarch, pc); + if ((op & 0xffff0000) != 0x818c0000) + break; + + /* twllt 0,12 */ + pc = pc + 4; + op = rs6000_fetch_instruction (gdbarch, pc); + if ((op & 0xfffffffe) != 0x7c406008) + break; + + /* We found a valid stack-check sequence, return the new PC. */ + return pc; + } + + /* No stack check code in our prologue, return the start_pc. */ + return start_pc; +} + +/* return pc value after skipping a function prologue and also return + information about a function frame. + + in struct rs6000_framedata fdata: + - frameless is TRUE, if function does not have a frame. + - nosavedpc is TRUE, if function does not save %pc value in its frame. + - offset is the initial size of this stack frame --- the amount by + which we decrement the sp to allocate the frame. + - saved_gpr is the number of the first saved gpr. + - saved_fpr is the number of the first saved fpr. + - saved_vr is the number of the first saved vr. + - saved_ev is the number of the first saved ev. + - alloca_reg is the number of the register used for alloca() handling. + Otherwise -1. + - gpr_offset is the offset of the first saved gpr from the previous frame. + - fpr_offset is the offset of the first saved fpr from the previous frame. + - vr_offset is the offset of the first saved vr from the previous frame. + - ev_offset is the offset of the first saved ev from the previous frame. + - lr_offset is the offset of the saved lr + - cr_offset is the offset of the saved cr + - vrsave_offset is the offset of the saved vrsave register. */ + +static CORE_ADDR +skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, + struct rs6000_framedata *fdata) +{ + CORE_ADDR orig_pc = pc; + CORE_ADDR last_prologue_pc = pc; + CORE_ADDR li_found_pc = 0; + gdb_byte buf[4]; + unsigned long op; + long offset = 0; + long alloca_reg_offset = 0; + long vr_saved_offset = 0; + int lr_reg = -1; + int cr_reg = -1; + int vr_reg = -1; + int ev_reg = -1; + long ev_offset = 0; + int vrsave_reg = -1; + int reg; + int framep = 0; + int minimal_toc_loaded = 0; + int prev_insn_was_prologue_insn = 1; + int num_skip_non_prologue_insns = 0; + int r0_contains_arg = 0; + const struct bfd_arch_info *arch_info = gdbarch_bfd_arch_info (gdbarch); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + + memset (fdata, 0, sizeof (struct rs6000_framedata)); + fdata->saved_gpr = -1; + fdata->saved_fpr = -1; + fdata->saved_vr = -1; + fdata->saved_ev = -1; + fdata->alloca_reg = -1; + fdata->frameless = 1; + fdata->nosavedpc = 1; + fdata->lr_register = -1; + + pc = rs6000_skip_stack_check (gdbarch, pc); + if (pc >= lim_pc) + pc = lim_pc; + + for (;; pc += 4) { /* Sometimes it isn't clear if an instruction is a prologue instruction or not. When we encounter one of these ambiguous cases, we'll set prev_insn_was_prologue_insn to 0 (false). - Otherwise, we'll assume that it really is a prologue instruction. */ + Otherwise, we'll assume that it really is a prologue instruction. */ if (prev_insn_was_prologue_insn) last_prologue_pc = pc; @@ -1311,7 +1504,7 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, /* Fetch the instruction and convert it to an integer. */ if (target_read_memory (pc, buf, 4)) break; - op = extract_unsigned_integer (buf, 4); + op = extract_unsigned_integer (buf, 4, byte_order); if ((op & 0xfc1fffff) == 0x7c0802a6) { /* mflr Rx */ @@ -1333,14 +1526,14 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, remember just the first one, but skip over additional ones. */ if (lr_reg == -1) - lr_reg = (op & 0x03e00000); + lr_reg = (op & 0x03e00000) >> 21; if (lr_reg == 0) r0_contains_arg = 0; continue; } else if ((op & 0xfc1fffff) == 0x7c000026) { /* mfcr Rx */ - cr_reg = (op & 0x03e00000); + cr_reg = (op & 0x03e00000) >> 21; if (cr_reg == 0) r0_contains_arg = 0; continue; @@ -1364,6 +1557,10 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, { reg = GET_SRC_REG (op); + if ((op & 0xfc1f0000) == 0xbc010000) + fdata->gpr_mask |= ~((1U << reg) - 1); + else + fdata->gpr_mask |= 1U << reg; if (fdata->saved_gpr == -1 || fdata->saved_gpr > reg) { fdata->saved_gpr = reg; @@ -1374,19 +1571,30 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, continue; } - else if ((op & 0xffff0000) == 0x60000000) + else if ((op & 0xffff0000) == 0x3c4c0000 + || (op & 0xffff0000) == 0x3c400000 + || (op & 0xffff0000) == 0x38420000) + { + /* . 0: addis 2,12,.TOC.-0b@ha + . addi 2,2,.TOC.-0b@l + or + . lis 2,.TOC.@ha + . addi 2,2,.TOC.@l + used by ELFv2 global entry points to set up r2. */ + continue; + } + else if (op == 0x60000000) { /* nop */ /* Allow nops in the prologue, but do not consider them to be part of the prologue unless followed by other prologue - instructions. */ + instructions. */ prev_insn_was_prologue_insn = 0; continue; } else if ((op & 0xffff0000) == 0x3c000000) - { /* addis 0,0,NUM, used - for >= 32k frames */ + { /* addis 0,0,NUM, used for >= 32k frames */ fdata->offset = (op & 0x0000ffff) << 16; fdata->frameless = 0; r0_contains_arg = 0; @@ -1394,8 +1602,7 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, } else if ((op & 0xffff0000) == 0x60000000) - { /* ori 0,0,NUM, 2nd ha - lf of >= 32k frames */ + { /* ori 0,0,NUM, 2nd half of >= 32k frames */ fdata->offset |= (op & 0x0000ffff); fdata->frameless = 0; r0_contains_arg = 0; @@ -1403,14 +1610,17 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, } else if (lr_reg >= 0 && - /* std Rx, NUM(r1) || stdu Rx, NUM(r1) */ - (((op & 0xffff0000) == (lr_reg | 0xf8010000)) || - /* stw Rx, NUM(r1) */ - ((op & 0xffff0000) == (lr_reg | 0x90010000)) || - /* stwu Rx, NUM(r1) */ - ((op & 0xffff0000) == (lr_reg | 0x94010000)))) - { /* where Rx == lr */ - fdata->lr_offset = offset; + ((store_insn_p (op, lr_reg, 1, true)) || + (framep && + (store_insn_p (op, lr_reg, + fdata->alloca_reg - tdep->ppc_gp0_regnum, + false))))) + { + if (store_insn_p (op, lr_reg, 1, true)) + fdata->lr_offset = offset; + else /* LR save through frame pointer. */ + fdata->lr_offset = alloca_reg_offset; + fdata->nosavedpc = 0; /* Invalidate lr_reg, but don't set it to -1. That would mean that it had never been set. */ @@ -1425,13 +1635,8 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, } else if (cr_reg >= 0 && - /* std Rx, NUM(r1) || stdu Rx, NUM(r1) */ - (((op & 0xffff0000) == (cr_reg | 0xf8010000)) || - /* stw Rx, NUM(r1) */ - ((op & 0xffff0000) == (cr_reg | 0x90010000)) || - /* stwu Rx, NUM(r1) */ - ((op & 0xffff0000) == (cr_reg | 0x94010000)))) - { /* where Rx == cr */ + (store_insn_p (op, cr_reg, 1, true))) + { fdata->cr_offset = offset; /* Invalidate cr_reg, but don't set it to -1. That would mean that it had never been set. */ @@ -1455,6 +1660,7 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, else if (op == 0x48000005) { /* bl .+4 used in -mrelocatable */ + fdata->used_bl = 1; continue; } @@ -1472,14 +1678,17 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, } else if ((op & 0xfc000001) == 0x48000001) { /* bl foo, - to save fprs??? */ + to save fprs??? */ fdata->frameless = 0; /* If the return address has already been saved, we can skip calls to blrl (for PIC). */ - if (lr_reg != -1 && bl_to_blrl_insn_p (pc, op)) - continue; + if (lr_reg != -1 && bl_to_blrl_insn_p (pc, op, byte_order)) + { + fdata->used_bl = 1; + continue; + } /* Don't skip over the subroutine call if it is not within the first three instructions of the prologue and either @@ -1491,22 +1700,24 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, struct symtab_and_line prologue_sal = find_pc_line (orig_pc, 0); struct symtab_and_line this_sal = find_pc_line (pc, 0); - if ((prologue_sal.line == 0) || (prologue_sal.line != this_sal.line)) + if ((prologue_sal.line == 0) + || (prologue_sal.line != this_sal.line)) break; } - op = read_memory_integer (pc + 4, 4); + op = read_memory_integer (pc + 4, 4, byte_order); /* At this point, make sure this is not a trampoline function (a function that simply calls another functions, and nothing else). If the next is not a nop, this branch - was part of the function prologue. */ + was part of the function prologue. */ if (op == 0x4def7b82 || op == 0) /* crorc 15, 15, 15 */ - break; /* don't skip over - this branch */ - continue; + break; /* Don't skip over + this branch. */ + fdata->used_bl = 1; + continue; } /* update stack pointer */ else if ((op & 0xfc1f0000) == 0x94010000) @@ -1516,9 +1727,9 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, offset = fdata->offset; continue; } - else if ((op & 0xfc1f016a) == 0x7c01016e) - { /* stwux rX,r1,rY */ - /* no way to figure out what r1 is going to be */ + else if ((op & 0xfc1f07fa) == 0x7c01016a) + { /* stwux rX,r1,rY || stdux rX,r1,rY */ + /* No way to figure out what r1 is going to be. */ fdata->frameless = 0; offset = fdata->offset; continue; @@ -1530,13 +1741,6 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, offset = fdata->offset; continue; } - else if ((op & 0xfc1f016a) == 0x7c01016a) - { /* stdux rX,r1,rY */ - /* no way to figure out what r1 is going to be */ - fdata->frameless = 0; - offset = fdata->offset; - continue; - } else if ((op & 0xffff0000) == 0x38210000) { /* addi r1,r1,SIMM */ fdata->frameless = 0; @@ -1546,8 +1750,8 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, } /* Load up minimal toc pointer. Do not treat an epilogue restore of r31 as a minimal TOC load. */ - else if (((op >> 22) == 0x20f || /* l r31,... or l r30,... */ - (op >> 22) == 0x3af) /* ld r31,... or ld r30,... */ + else if (((op >> 22) == 0x20f || /* l r31,... or l r30,... */ + (op >> 22) == 0x3af) /* ld r31,... or ld r30,... */ && !framep && !minimal_toc_loaded) { @@ -1560,7 +1764,8 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, else if ((op & 0xfc0007fe) == 0x7c000378 && /* mr(.) Rx,Ry */ (((op >> 21) & 31) >= 3) && /* R3 >= Ry >= R10 */ (((op >> 21) & 31) <= 10) && - ((long) ((op >> 16) & 31) >= fdata->saved_gpr)) /* Rx: local var reg */ + ((long) ((op >> 16) & 31) + >= fdata->saved_gpr)) /* Rx: local var reg */ { continue; @@ -1573,12 +1778,23 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, /* Set up frame pointer */ } + else if (op == 0x603d0000) /* oril r29, r1, 0x0 */ + { + fdata->frameless = 0; + framep = 1; + fdata->alloca_reg = (tdep->ppc_gp0_regnum + 29); + alloca_reg_offset = offset; + continue; + + /* Another way to set up the frame pointer. */ + } else if (op == 0x603f0000 /* oril r31, r1, 0x0 */ || op == 0x7c3f0b78) { /* mr r31, r1 */ fdata->frameless = 0; framep = 1; fdata->alloca_reg = (tdep->ppc_gp0_regnum + 31); + alloca_reg_offset = offset; continue; /* Another way to set up the frame pointer. */ @@ -1589,6 +1805,7 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, framep = 1; fdata->alloca_reg = (tdep->ppc_gp0_regnum + ((op & ~0x38010000) >> 21)); + alloca_reg_offset = offset; continue; } /* AltiVec related instructions. */ @@ -1642,7 +1859,7 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, vr_saved_offset = SIGNED_SHORT (op); /* This insn by itself is not part of the prologue, unless - if part of the pair of insns mentioned above. So do not + if part of the pair of insns mentioned above. So do not record this insn as part of the prologue yet. */ prev_insn_was_prologue_insn = 0; } @@ -1770,9 +1987,16 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, /* Not a recognized prologue instruction. Handle optimizer code motions into the prologue by continuing the search if we have no valid frame yet or if the return - address is not yet saved in the frame. */ - if (fdata->frameless == 0 && fdata->nosavedpc == 0) - break; + address is not yet saved in the frame. Also skip instructions + if some of the GPRs expected to be saved are not yet saved. */ + if (fdata->frameless == 0 && fdata->nosavedpc == 0 + && fdata->saved_gpr != -1) + { + unsigned int all_mask = ~((1U << fdata->saved_gpr) - 1); + + if ((fdata->gpr_mask & all_mask) == all_mask) + break; + } if (op == 0x4e800020 /* blr */ || op == 0x4e800420) /* bctr */ @@ -1796,7 +2020,7 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, #if 0 /* I have problems with skipping over __main() that I need to address - * sometime. Previously, I used to use misc_function_vector which + * sometime. Previously, I used to use misc_function_vector which * didn't work as well as I wanted to be. -MGO */ /* If the first thing after skipping a prolog is a branch to a function, @@ -1807,8 +2031,8 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, if ((op & 0xfc000001) == 0x48000001) - { /* bl foo, an initializer function? */ - op = read_memory_integer (pc + 4, 4); + { /* bl foo, an initializer function? */ + op = read_memory_integer (pc + 4, 4, byte_order); if (op == 0x4def7b82) { /* cror 0xf, 0xf, 0xf (nop) */ @@ -1824,446 +2048,147 @@ skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc, CORE_ADDR lim_pc, } #endif /* 0 */ + if (pc == lim_pc && lr_reg >= 0) + fdata->lr_register = lr_reg; + fdata->offset = -fdata->offset; return last_prologue_pc; } - -/************************************************************************* - Support for creating pushing a dummy frame into the stack, and popping - frames, etc. -*************************************************************************/ - - -/* All the ABI's require 16 byte alignment. */ -static CORE_ADDR -rs6000_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr) -{ - return (addr & -16); -} - -/* Pass the arguments in either registers, or in the stack. In RS/6000, - the first eight words of the argument list (that might be less than - eight parameters if some parameters occupy more than one word) are - passed in r3..r10 registers. float and double parameters are - passed in fpr's, in addition to that. Rest of the parameters if any - are passed in user stack. There might be cases in which half of the - parameter is copied into registers, the other half is pushed into - stack. - - Stack must be aligned on 64-bit boundaries when synthesizing - function calls. - - If the function is returning a structure, then the return address is passed - in r3, then the first 7 words of the parameters can be passed in registers, - starting from r4. */ - static CORE_ADDR -rs6000_push_dummy_call (struct gdbarch *gdbarch, struct value *function, - struct regcache *regcache, CORE_ADDR bp_addr, - int nargs, struct value **args, CORE_ADDR sp, - int struct_return, CORE_ADDR struct_addr) +rs6000_skip_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) { - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - int ii; - int len = 0; - int argno; /* current argument number */ - int argbytes; /* current argument byte */ - gdb_byte tmp_buffer[50]; - int f_argno = 0; /* current floating point argno */ - int wordsize = gdbarch_tdep (gdbarch)->wordsize; - CORE_ADDR func_addr = find_function_addr (function, NULL); - - struct value *arg = 0; - struct type *type; - - ULONGEST saved_sp; - - /* The calling convention this function implements assumes the - processor has floating-point registers. We shouldn't be using it - on PPC variants that lack them. */ - gdb_assert (ppc_floating_point_unit_p (gdbarch)); - - /* The first eight words of ther arguments are passed in registers. - Copy them appropriately. */ - ii = 0; + struct rs6000_framedata frame; + CORE_ADDR limit_pc, func_addr, func_end_addr = 0; - /* If the function is returning a `struct', then the first word - (which will be passed in r3) is used for struct return address. - In that case we should advance one word and start from r4 - register to copy parameters. */ - if (struct_return) + /* See if we can determine the end of the prologue via the symbol table. + If so, then return either PC, or the PC after the prologue, whichever + is greater. */ + if (find_pc_partial_function (pc, NULL, &func_addr, &func_end_addr)) { - regcache_raw_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3, - struct_addr); - ii++; + CORE_ADDR post_prologue_pc + = skip_prologue_using_sal (gdbarch, func_addr); + if (post_prologue_pc != 0) + return std::max (pc, post_prologue_pc); } -/* - effectively indirect call... gcc does... - - return_val example( float, int); - - eabi: - float in fp0, int in r3 - offset of stack on overflow 8/16 - for varargs, must go by type. - power open: - float in r3&r4, int in r5 - offset of stack on overflow different - both: - return in r3 or f0. If no float, must study how gcc emulates floats; - pay attention to arg promotion. - User may have to cast\args to handle promotion correctly - since gdb won't know if prototype supplied or not. - */ - - for (argno = 0, argbytes = 0; argno < nargs && ii < 8; ++ii) - { - int reg_size = register_size (gdbarch, ii + 3); + /* Can't determine prologue from the symbol table, need to examine + instructions. */ - arg = args[argno]; - type = check_typedef (value_type (arg)); - len = TYPE_LENGTH (type); + /* Find an upper limit on the function prologue using the debug + information. If the debug information could not be used to provide + that bound, then use an arbitrary large number as the upper bound. */ + limit_pc = skip_prologue_using_sal (gdbarch, pc); + if (limit_pc == 0) + limit_pc = pc + 100; /* Magic. */ - if (TYPE_CODE (type) == TYPE_CODE_FLT) - { + /* Do not allow limit_pc to be past the function end, if we know + where that end is... */ + if (func_end_addr && limit_pc > func_end_addr) + limit_pc = func_end_addr; - /* Floating point arguments are passed in fpr's, as well as gpr's. - There are 13 fpr's reserved for passing parameters. At this point - there is no way we would run out of them. */ + pc = skip_prologue (gdbarch, pc, limit_pc, &frame); + return pc; +} - gdb_assert (len <= 8); +/* When compiling for EABI, some versions of GCC emit a call to __eabi + in the prologue of main(). - regcache_cooked_write (regcache, - tdep->ppc_fp0_regnum + 1 + f_argno, - value_contents (arg)); - ++f_argno; - } + The function below examines the code pointed at by PC and checks to + see if it corresponds to a call to __eabi. If so, it returns the + address of the instruction following that call. Otherwise, it simply + returns PC. */ - if (len > reg_size) - { +static CORE_ADDR +rs6000_skip_main_prologue (struct gdbarch *gdbarch, CORE_ADDR pc) +{ + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + gdb_byte buf[4]; + unsigned long op; - /* Argument takes more than one register. */ - while (argbytes < len) - { - gdb_byte word[MAX_REGISTER_SIZE]; - memset (word, 0, reg_size); - memcpy (word, - ((char *) value_contents (arg)) + argbytes, - (len - argbytes) > reg_size - ? reg_size : len - argbytes); - regcache_cooked_write (regcache, - tdep->ppc_gp0_regnum + 3 + ii, - word); - ++ii, argbytes += reg_size; - - if (ii >= 8) - goto ran_out_of_registers_for_arguments; - } - argbytes = 0; - --ii; - } - else - { - /* Argument can fit in one register. No problem. */ - int adj = gdbarch_byte_order (gdbarch) - == BFD_ENDIAN_BIG ? reg_size - len : 0; - gdb_byte word[MAX_REGISTER_SIZE]; + if (target_read_memory (pc, buf, 4)) + return pc; + op = extract_unsigned_integer (buf, 4, byte_order); - memset (word, 0, reg_size); - memcpy (word, value_contents (arg), len); - regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3 +ii, word); - } - ++argno; + if ((op & BL_MASK) == BL_INSTRUCTION) + { + CORE_ADDR displ = op & BL_DISPLACEMENT_MASK; + CORE_ADDR call_dest = pc + 4 + displ; + struct bound_minimal_symbol s = lookup_minimal_symbol_by_pc (call_dest); + + /* We check for ___eabi (three leading underscores) in addition + to __eabi in case the GCC option "-fleading-underscore" was + used to compile the program. */ + if (s.minsym != NULL + && s.minsym->linkage_name () != NULL + && (strcmp (s.minsym->linkage_name (), "__eabi") == 0 + || strcmp (s.minsym->linkage_name (), "___eabi") == 0)) + pc += 4; } + return pc; +} -ran_out_of_registers_for_arguments: +/* All the ABI's require 16 byte alignment. */ +static CORE_ADDR +rs6000_frame_align (struct gdbarch *gdbarch, CORE_ADDR addr) +{ + return (addr & -16); +} - regcache_cooked_read_unsigned (regcache, - gdbarch_sp_regnum (gdbarch), - &saved_sp); +/* Return whether handle_inferior_event() should proceed through code + starting at PC in function NAME when stepping. - /* Location for 8 parameters are always reserved. */ - sp -= wordsize * 8; + The AIX -bbigtoc linker option generates functions @FIX0, @FIX1, etc. to + handle memory references that are too distant to fit in instructions + generated by the compiler. For example, if 'foo' in the following + instruction: - /* Another six words for back chain, TOC register, link register, etc. */ - sp -= wordsize * 6; + lwz r9,foo(r2) - /* Stack pointer must be quadword aligned. */ - sp &= -16; + is greater than 32767, the linker might replace the lwz with a branch to + somewhere in @FIX1 that does the load in 2 instructions and then branches + back to where execution should continue. - /* If there are more arguments, allocate space for them in - the stack, then push them starting from the ninth one. */ + GDB should silently step over @FIX code, just like AIX dbx does. + Unfortunately, the linker uses the "b" instruction for the + branches, meaning that the link register doesn't get set. + Therefore, GDB's usual step_over_function () mechanism won't work. - if ((argno < nargs) || argbytes) - { - int space = 0, jj; + Instead, use the gdbarch_skip_trampoline_code and + gdbarch_skip_trampoline_code hooks in handle_inferior_event() to skip past + @FIX code. */ - if (argbytes) - { - space += ((len - argbytes + 3) & -4); - jj = argno + 1; - } - else - jj = argno; +static int +rs6000_in_solib_return_trampoline (struct gdbarch *gdbarch, + CORE_ADDR pc, const char *name) +{ + return name && startswith (name, "@FIX"); +} - for (; jj < nargs; ++jj) - { - struct value *val = args[jj]; - space += ((TYPE_LENGTH (value_type (val))) + 3) & -4; - } +/* Skip code that the user doesn't want to see when stepping: - /* Add location required for the rest of the parameters. */ - space = (space + 15) & -16; - sp -= space; + 1. Indirect function calls use a piece of trampoline code to do context + switching, i.e. to set the new TOC table. Skip such code if we are on + its first instruction (as when we have single-stepped to here). - /* This is another instance we need to be concerned about - securing our stack space. If we write anything underneath %sp - (r1), we might conflict with the kernel who thinks he is free - to use this area. So, update %sp first before doing anything - else. */ + 2. Skip shared library trampoline code (which is different from + indirect function call trampolines). - regcache_raw_write_signed (regcache, - gdbarch_sp_regnum (gdbarch), sp); + 3. Skip bigtoc fixup code. - /* If the last argument copied into the registers didn't fit there - completely, push the rest of it into stack. */ + Result is desired PC to step until, or NULL if we are not in + code that should be skipped. */ - if (argbytes) - { - write_memory (sp + 24 + (ii * 4), - value_contents (arg) + argbytes, - len - argbytes); - ++argno; - ii += ((len - argbytes + 3) & -4) / 4; - } - - /* Push the rest of the arguments into stack. */ - for (; argno < nargs; ++argno) - { - - arg = args[argno]; - type = check_typedef (value_type (arg)); - len = TYPE_LENGTH (type); - - - /* Float types should be passed in fpr's, as well as in the - stack. */ - if (TYPE_CODE (type) == TYPE_CODE_FLT && f_argno < 13) - { - - gdb_assert (len <= 8); - - regcache_cooked_write (regcache, - tdep->ppc_fp0_regnum + 1 + f_argno, - value_contents (arg)); - ++f_argno; - } - - write_memory (sp + 24 + (ii * 4), value_contents (arg), len); - ii += ((len + 3) & -4) / 4; - } - } - - /* Set the stack pointer. According to the ABI, the SP is meant to - be set _before_ the corresponding stack space is used. On AIX, - this even applies when the target has been completely stopped! - Not doing this can lead to conflicts with the kernel which thinks - that it still has control over this not-yet-allocated stack - region. */ - regcache_raw_write_signed (regcache, gdbarch_sp_regnum (gdbarch), sp); - - /* Set back chain properly. */ - store_unsigned_integer (tmp_buffer, wordsize, saved_sp); - write_memory (sp, tmp_buffer, wordsize); - - /* Point the inferior function call's return address at the dummy's - breakpoint. */ - regcache_raw_write_signed (regcache, tdep->ppc_lr_regnum, bp_addr); - - /* Set the TOC register, get the value from the objfile reader - which, in turn, gets it from the VMAP table. */ - if (rs6000_find_toc_address_hook != NULL) - { - CORE_ADDR tocvalue = (*rs6000_find_toc_address_hook) (func_addr); - regcache_raw_write_signed (regcache, tdep->ppc_toc_regnum, tocvalue); - } - - target_store_registers (regcache, -1); - return sp; -} - -static enum return_value_convention -rs6000_return_value (struct gdbarch *gdbarch, struct type *valtype, - struct regcache *regcache, gdb_byte *readbuf, - const gdb_byte *writebuf) -{ - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - gdb_byte buf[8]; - - /* The calling convention this function implements assumes the - processor has floating-point registers. We shouldn't be using it - on PowerPC variants that lack them. */ - gdb_assert (ppc_floating_point_unit_p (gdbarch)); - - /* AltiVec extension: Functions that declare a vector data type as a - return value place that return value in VR2. */ - if (TYPE_CODE (valtype) == TYPE_CODE_ARRAY && TYPE_VECTOR (valtype) - && TYPE_LENGTH (valtype) == 16) - { - if (readbuf) - regcache_cooked_read (regcache, tdep->ppc_vr0_regnum + 2, readbuf); - if (writebuf) - regcache_cooked_write (regcache, tdep->ppc_vr0_regnum + 2, writebuf); - - return RETURN_VALUE_REGISTER_CONVENTION; - } - - /* If the called subprogram returns an aggregate, there exists an - implicit first argument, whose value is the address of a caller- - allocated buffer into which the callee is assumed to store its - return value. All explicit parameters are appropriately - relabeled. */ - if (TYPE_CODE (valtype) == TYPE_CODE_STRUCT - || TYPE_CODE (valtype) == TYPE_CODE_UNION - || TYPE_CODE (valtype) == TYPE_CODE_ARRAY) - return RETURN_VALUE_STRUCT_CONVENTION; - - /* Scalar floating-point values are returned in FPR1 for float or - double, and in FPR1:FPR2 for quadword precision. Fortran - complex*8 and complex*16 are returned in FPR1:FPR2, and - complex*32 is returned in FPR1:FPR4. */ - if (TYPE_CODE (valtype) == TYPE_CODE_FLT - && (TYPE_LENGTH (valtype) == 4 || TYPE_LENGTH (valtype) == 8)) - { - struct type *regtype = register_type (gdbarch, tdep->ppc_fp0_regnum); - gdb_byte regval[8]; - - /* FIXME: kettenis/2007-01-01: Add support for quadword - precision and complex. */ - - if (readbuf) - { - regcache_cooked_read (regcache, tdep->ppc_fp0_regnum + 1, regval); - convert_typed_floating (regval, regtype, readbuf, valtype); - } - if (writebuf) - { - convert_typed_floating (writebuf, valtype, regval, regtype); - regcache_cooked_write (regcache, tdep->ppc_fp0_regnum + 1, regval); - } - - return RETURN_VALUE_REGISTER_CONVENTION; - } - - /* Values of the types int, long, short, pointer, and char (length - is less than or equal to four bytes), as well as bit values of - lengths less than or equal to 32 bits, must be returned right - justified in GPR3 with signed values sign extended and unsigned - values zero extended, as necessary. */ - if (TYPE_LENGTH (valtype) <= tdep->wordsize) - { - if (readbuf) - { - ULONGEST regval; - - /* For reading we don't have to worry about sign extension. */ - regcache_cooked_read_unsigned (regcache, tdep->ppc_gp0_regnum + 3, - ®val); - store_unsigned_integer (readbuf, TYPE_LENGTH (valtype), regval); - } - if (writebuf) - { - /* For writing, use unpack_long since that should handle any - required sign extension. */ - regcache_cooked_write_unsigned (regcache, tdep->ppc_gp0_regnum + 3, - unpack_long (valtype, writebuf)); - } - - return RETURN_VALUE_REGISTER_CONVENTION; - } - - /* Eight-byte non-floating-point scalar values must be returned in - GPR3:GPR4. */ - - if (TYPE_LENGTH (valtype) == 8) - { - gdb_assert (TYPE_CODE (valtype) != TYPE_CODE_FLT); - gdb_assert (tdep->wordsize == 4); - - if (readbuf) - { - gdb_byte regval[8]; - - regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 3, regval); - regcache_cooked_read (regcache, tdep->ppc_gp0_regnum + 4, - regval + 4); - memcpy (readbuf, regval, 8); - } - if (writebuf) - { - regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 3, writebuf); - regcache_cooked_write (regcache, tdep->ppc_gp0_regnum + 4, - writebuf + 4); - } - - return RETURN_VALUE_REGISTER_CONVENTION; - } - - return RETURN_VALUE_STRUCT_CONVENTION; -} - -/* Return whether handle_inferior_event() should proceed through code - starting at PC in function NAME when stepping. - - The AIX -bbigtoc linker option generates functions @FIX0, @FIX1, etc. to - handle memory references that are too distant to fit in instructions - generated by the compiler. For example, if 'foo' in the following - instruction: - - lwz r9,foo(r2) - - is greater than 32767, the linker might replace the lwz with a branch to - somewhere in @FIX1 that does the load in 2 instructions and then branches - back to where execution should continue. - - GDB should silently step over @FIX code, just like AIX dbx does. - Unfortunately, the linker uses the "b" instruction for the - branches, meaning that the link register doesn't get set. - Therefore, GDB's usual step_over_function () mechanism won't work. - - Instead, use the gdbarch_skip_trampoline_code and - gdbarch_skip_trampoline_code hooks in handle_inferior_event() to skip past - @FIX code. */ - -int -rs6000_in_solib_return_trampoline (CORE_ADDR pc, char *name) -{ - return name && !strncmp (name, "@FIX", 4); -} - -/* Skip code that the user doesn't want to see when stepping: - - 1. Indirect function calls use a piece of trampoline code to do context - switching, i.e. to set the new TOC table. Skip such code if we are on - its first instruction (as when we have single-stepped to here). - - 2. Skip shared library trampoline code (which is different from - indirect function call trampolines). - - 3. Skip bigtoc fixup code. - - Result is desired PC to step until, or NULL if we are not in - code that should be skipped. */ - -CORE_ADDR -rs6000_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) -{ - unsigned int ii, op; - int rel; - CORE_ADDR solib_target_pc; - struct minimal_symbol *msymbol; +static CORE_ADDR +rs6000_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + unsigned int ii, op; + int rel; + CORE_ADDR solib_target_pc; + struct bound_minimal_symbol msymbol; static unsigned trampoline_code[] = { @@ -2279,12 +2204,12 @@ rs6000_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) /* Check for bigtoc fixup code. */ msymbol = lookup_minimal_symbol_by_pc (pc); - if (msymbol - && rs6000_in_solib_return_trampoline (pc, - DEPRECATED_SYMBOL_NAME (msymbol))) + if (msymbol.minsym + && rs6000_in_solib_return_trampoline (gdbarch, pc, + msymbol.minsym->linkage_name ())) { /* Double-check that the third instruction from PC is relative "b". */ - op = read_memory_integer (pc + 8, 4); + op = read_memory_integer (pc + 8, 4, byte_order); if ((op & 0xfc000003) == 0x48000000) { /* Extract bits 6-29 as a signed 24-bit relative word address and @@ -2301,13 +2226,13 @@ rs6000_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc) for (ii = 0; trampoline_code[ii]; ++ii) { - op = read_memory_integer (pc + (ii * 4), 4); + op = read_memory_integer (pc + (ii * 4), 4, byte_order); if (op != trampoline_code[ii]) return 0; } - ii = get_frame_register_unsigned (frame, 11); /* r11 holds destination addr */ - pc = read_memory_addr (ii, - gdbarch_tdep (get_frame_arch (frame))->wordsize); /* (r11) value */ + ii = get_frame_register_unsigned (frame, 11); /* r11 holds destination + addr. */ + pc = read_memory_unsigned_integer (ii, tdep->wordsize, byte_order); return pc; } @@ -2320,6 +2245,8 @@ rs6000_builtin_type_vec64 (struct gdbarch *gdbarch) if (!tdep->ppc_builtin_type_vec64) { + const struct builtin_type *bt = builtin_type (gdbarch); + /* The type we're building is this: */ #if 0 union __gdb_builtin_type_vec64 @@ -2334,32 +2261,71 @@ rs6000_builtin_type_vec64 (struct gdbarch *gdbarch) struct type *t; - t = init_composite_type ("__ppc_builtin_type_vec64", TYPE_CODE_UNION); - append_composite_type_field (t, "uint64", builtin_type_int64); + t = arch_composite_type (gdbarch, + "__ppc_builtin_type_vec64", TYPE_CODE_UNION); + append_composite_type_field (t, "uint64", bt->builtin_int64); append_composite_type_field (t, "v2_float", - init_vector_type (builtin_type_float, 2)); + init_vector_type (bt->builtin_float, 2)); append_composite_type_field (t, "v2_int32", - init_vector_type (builtin_type_int32, 2)); + init_vector_type (bt->builtin_int32, 2)); append_composite_type_field (t, "v4_int16", - init_vector_type (builtin_type_int16, 4)); + init_vector_type (bt->builtin_int16, 4)); append_composite_type_field (t, "v8_int8", - init_vector_type (builtin_type_int8, 8)); + init_vector_type (bt->builtin_int8, 8)); - TYPE_FLAGS (t) |= TYPE_FLAG_VECTOR; - TYPE_NAME (t) = "ppc_builtin_type_vec64"; + TYPE_VECTOR (t) = 1; + t->set_name ("ppc_builtin_type_vec64"); tdep->ppc_builtin_type_vec64 = t; } return tdep->ppc_builtin_type_vec64; } -/* Return the size of register REG when words are WORDSIZE bytes long. If REG - isn't available with that word size, return 0. */ +/* Vector 128 type. */ -static int -regsize (const struct reg *reg, int wordsize) +static struct type * +rs6000_builtin_type_vec128 (struct gdbarch *gdbarch) { - return wordsize == 8 ? reg->sz64 : reg->sz32; + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (!tdep->ppc_builtin_type_vec128) + { + const struct builtin_type *bt = builtin_type (gdbarch); + + /* The type we're building is this + + type = union __ppc_builtin_type_vec128 { + uint128_t uint128; + double v2_double[2]; + float v4_float[4]; + int32_t v4_int32[4]; + int16_t v8_int16[8]; + int8_t v16_int8[16]; + } + */ + + struct type *t; + + t = arch_composite_type (gdbarch, + "__ppc_builtin_type_vec128", TYPE_CODE_UNION); + append_composite_type_field (t, "uint128", bt->builtin_uint128); + append_composite_type_field (t, "v2_double", + init_vector_type (bt->builtin_double, 2)); + append_composite_type_field (t, "v4_float", + init_vector_type (bt->builtin_float, 4)); + append_composite_type_field (t, "v4_int32", + init_vector_type (bt->builtin_int32, 4)); + append_composite_type_field (t, "v8_int16", + init_vector_type (bt->builtin_int16, 8)); + append_composite_type_field (t, "v16_int8", + init_vector_type (bt->builtin_int8, 16)); + + TYPE_VECTOR (t) = 1; + t->set_name ("ppc_builtin_type_vec128"); + tdep->ppc_builtin_type_vec128 = t; + } + + return tdep->ppc_builtin_type_vec128; } /* Return the name of register number REGNO, or the empty string if it @@ -2378,6 +2344,17 @@ rs6000_register_name (struct gdbarch *gdbarch, int regno) && regno < tdep->ppc_ev0_upper_regnum + ppc_num_gprs) return ""; + /* Hide the upper halves of the vs0~vs31 registers. */ + if (tdep->ppc_vsr0_regnum >= 0 + && tdep->ppc_vsr0_upper_regnum <= regno + && regno < tdep->ppc_vsr0_upper_regnum + ppc_num_gprs) + return ""; + + /* Hide the upper halves of the cvs0~cvs31 registers. */ + if (PPC_CVSR0_UPPER_REGNUM <= regno + && regno < PPC_CVSR0_UPPER_REGNUM + ppc_num_gprs) + return ""; + /* Check if the SPE pseudo registers are available. */ if (IS_SPE_PSEUDOREG (tdep, regno)) { @@ -2402,6 +2379,90 @@ rs6000_register_name (struct gdbarch *gdbarch, int regno) return dfp128_regnames[regno - tdep->ppc_dl0_regnum]; } + /* Check if this is a vX alias for a raw vrX vector register. */ + if (IS_V_ALIAS_PSEUDOREG (tdep, regno)) + { + static const char *const vector_alias_regnames[] = { + "v0", "v1", "v2", "v3", "v4", "v5", "v6", "v7", + "v8", "v9", "v10", "v11", "v12", "v13", "v14", "v15", + "v16", "v17", "v18", "v19", "v20", "v21", "v22", "v23", + "v24", "v25", "v26", "v27", "v28", "v29", "v30", "v31" + }; + return vector_alias_regnames[regno - tdep->ppc_v0_alias_regnum]; + } + + /* Check if this is a VSX pseudo-register. */ + if (IS_VSX_PSEUDOREG (tdep, regno)) + { + static const char *const vsx_regnames[] = { + "vs0", "vs1", "vs2", "vs3", "vs4", "vs5", "vs6", "vs7", + "vs8", "vs9", "vs10", "vs11", "vs12", "vs13", "vs14", + "vs15", "vs16", "vs17", "vs18", "vs19", "vs20", "vs21", + "vs22", "vs23", "vs24", "vs25", "vs26", "vs27", "vs28", + "vs29", "vs30", "vs31", "vs32", "vs33", "vs34", "vs35", + "vs36", "vs37", "vs38", "vs39", "vs40", "vs41", "vs42", + "vs43", "vs44", "vs45", "vs46", "vs47", "vs48", "vs49", + "vs50", "vs51", "vs52", "vs53", "vs54", "vs55", "vs56", + "vs57", "vs58", "vs59", "vs60", "vs61", "vs62", "vs63" + }; + return vsx_regnames[regno - tdep->ppc_vsr0_regnum]; + } + + /* Check if the this is a Extended FP pseudo-register. */ + if (IS_EFP_PSEUDOREG (tdep, regno)) + { + static const char *const efpr_regnames[] = { + "f32", "f33", "f34", "f35", "f36", "f37", "f38", + "f39", "f40", "f41", "f42", "f43", "f44", "f45", + "f46", "f47", "f48", "f49", "f50", "f51", + "f52", "f53", "f54", "f55", "f56", "f57", + "f58", "f59", "f60", "f61", "f62", "f63" + }; + return efpr_regnames[regno - tdep->ppc_efpr0_regnum]; + } + + /* Check if this is a Checkpointed DFP pseudo-register. */ + if (IS_CDFP_PSEUDOREG (tdep, regno)) + { + static const char *const cdfp128_regnames[] = { + "cdl0", "cdl1", "cdl2", "cdl3", + "cdl4", "cdl5", "cdl6", "cdl7", + "cdl8", "cdl9", "cdl10", "cdl11", + "cdl12", "cdl13", "cdl14", "cdl15" + }; + return cdfp128_regnames[regno - tdep->ppc_cdl0_regnum]; + } + + /* Check if this is a Checkpointed VSX pseudo-register. */ + if (IS_CVSX_PSEUDOREG (tdep, regno)) + { + static const char *const cvsx_regnames[] = { + "cvs0", "cvs1", "cvs2", "cvs3", "cvs4", "cvs5", "cvs6", "cvs7", + "cvs8", "cvs9", "cvs10", "cvs11", "cvs12", "cvs13", "cvs14", + "cvs15", "cvs16", "cvs17", "cvs18", "cvs19", "cvs20", "cvs21", + "cvs22", "cvs23", "cvs24", "cvs25", "cvs26", "cvs27", "cvs28", + "cvs29", "cvs30", "cvs31", "cvs32", "cvs33", "cvs34", "cvs35", + "cvs36", "cvs37", "cvs38", "cvs39", "cvs40", "cvs41", "cvs42", + "cvs43", "cvs44", "cvs45", "cvs46", "cvs47", "cvs48", "cvs49", + "cvs50", "cvs51", "cvs52", "cvs53", "cvs54", "cvs55", "cvs56", + "cvs57", "cvs58", "cvs59", "cvs60", "cvs61", "cvs62", "cvs63" + }; + return cvsx_regnames[regno - tdep->ppc_cvsr0_regnum]; + } + + /* Check if the this is a Checkpointed Extended FP pseudo-register. */ + if (IS_CEFP_PSEUDOREG (tdep, regno)) + { + static const char *const cefpr_regnames[] = { + "cf32", "cf33", "cf34", "cf35", "cf36", "cf37", "cf38", + "cf39", "cf40", "cf41", "cf42", "cf43", "cf44", "cf45", + "cf46", "cf47", "cf48", "cf49", "cf50", "cf51", + "cf52", "cf53", "cf54", "cf55", "cf56", "cf57", + "cf58", "cf59", "cf60", "cf61", "cf62", "cf63" + }; + return cefpr_regnames[regno - tdep->ppc_cefpr0_regnum]; + } + return tdesc_register_name (gdbarch, regno); } @@ -2413,35 +2474,49 @@ rs6000_pseudo_register_type (struct gdbarch *gdbarch, int regnum) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - /* These are the only pseudo-registers we support. */ - gdb_assert (IS_SPE_PSEUDOREG (tdep, regnum) - || IS_DFP_PSEUDOREG (tdep, regnum)); - /* These are the e500 pseudo-registers. */ if (IS_SPE_PSEUDOREG (tdep, regnum)) return rs6000_builtin_type_vec64 (gdbarch); - else - /* Could only be the ppc decimal128 pseudo-registers. */ + else if (IS_DFP_PSEUDOREG (tdep, regnum) + || IS_CDFP_PSEUDOREG (tdep, regnum)) + /* PPC decimal128 pseudo-registers. */ return builtin_type (gdbarch)->builtin_declong; + else if (IS_V_ALIAS_PSEUDOREG (tdep, regnum)) + return gdbarch_register_type (gdbarch, + tdep->ppc_vr0_regnum + + (regnum + - tdep->ppc_v0_alias_regnum)); + else if (IS_VSX_PSEUDOREG (tdep, regnum) + || IS_CVSX_PSEUDOREG (tdep, regnum)) + /* POWER7 VSX pseudo-registers. */ + return rs6000_builtin_type_vec128 (gdbarch); + else if (IS_EFP_PSEUDOREG (tdep, regnum) + || IS_CEFP_PSEUDOREG (tdep, regnum)) + /* POWER7 Extended FP pseudo-registers. */ + return builtin_type (gdbarch)->builtin_double; + else + internal_error (__FILE__, __LINE__, + _("rs6000_pseudo_register_type: " + "called on unexpected register '%s' (%d)"), + gdbarch_register_name (gdbarch, regnum), regnum); } -/* Is REGNUM a member of REGGROUP? */ +/* Check if REGNUM is a member of REGGROUP. We only need to handle + the vX aliases for the vector registers by always returning false + to avoid duplicated information in "info register vector/all", + since the raw vrX registers will already show in these cases. For + other pseudo-registers we use the default membership function. */ + static int rs6000_pseudo_register_reggroup_p (struct gdbarch *gdbarch, int regnum, struct reggroup *group) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - /* These are the only pseudo-registers we support. */ - gdb_assert (IS_SPE_PSEUDOREG (tdep, regnum) - || IS_DFP_PSEUDOREG (tdep, regnum)); - - /* These are the e500 pseudo-registers. */ - if (IS_SPE_PSEUDOREG (tdep, regnum)) - return group == all_reggroup || group == vector_reggroup; + if (IS_V_ALIAS_PSEUDOREG (tdep, regnum)) + return 0; else - /* Could only be the ppc decimal128 pseudo-registers. */ - return group == all_reggroup || group == float_reggroup; + return default_register_reggroup_p (gdbarch, regnum, group); } /* The register format for RS/6000 floating point registers is always @@ -2456,22 +2531,32 @@ rs6000_convert_register_p (struct gdbarch *gdbarch, int regnum, return (tdep->ppc_fp0_regnum >= 0 && regnum >= tdep->ppc_fp0_regnum && regnum < tdep->ppc_fp0_regnum + ppc_num_fprs - && TYPE_CODE (type) == TYPE_CODE_FLT - && TYPE_LENGTH (type) != TYPE_LENGTH (builtin_type_double)); + && type->code () == TYPE_CODE_FLT + && TYPE_LENGTH (type) + != TYPE_LENGTH (builtin_type (gdbarch)->builtin_double)); } -static void +static int rs6000_register_to_value (struct frame_info *frame, int regnum, struct type *type, - gdb_byte *to) + gdb_byte *to, + int *optimizedp, int *unavailablep) { - gdb_byte from[MAX_REGISTER_SIZE]; + struct gdbarch *gdbarch = get_frame_arch (frame); + gdb_byte from[PPC_MAX_REGISTER_SIZE]; - gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT); + gdb_assert (type->code () == TYPE_CODE_FLT); + + if (!get_frame_register_bytes (frame, regnum, 0, + register_size (gdbarch, regnum), + from, optimizedp, unavailablep)) + return 0; - get_frame_register (frame, regnum, from); - convert_typed_floating (from, builtin_type_double, to, type); + target_float_convert (from, builtin_type (gdbarch)->builtin_double, + to, type); + *optimizedp = *unavailablep = 0; + return 1; } static void @@ -2480,14 +2565,21 @@ rs6000_value_to_register (struct frame_info *frame, struct type *type, const gdb_byte *from) { - gdb_byte to[MAX_REGISTER_SIZE]; + struct gdbarch *gdbarch = get_frame_arch (frame); + gdb_byte to[PPC_MAX_REGISTER_SIZE]; - gdb_assert (TYPE_CODE (type) == TYPE_CODE_FLT); + gdb_assert (type->code () == TYPE_CODE_FLT); - convert_typed_floating (from, type, to, builtin_type_double); + target_float_convert (from, type, + to, builtin_type (gdbarch)->builtin_double); put_frame_register (frame, regnum, to); } + /* The type of a function that moves the value of REG between CACHE + or BUF --- in either direction. */ +typedef enum register_status (*move_ev_register_func) (struct regcache *, + int, void *); + /* Move SPE vector register values between a 64-bit buffer and the two 32-bit raw register halves in a regcache. This function handles both splitting a 64-bit value into two 32-bit halves, and joining @@ -2511,16 +2603,16 @@ rs6000_value_to_register (struct frame_info *frame, MOVE, since this function can't tell at compile-time which of REGCACHE or BUFFER is acting as the source of the data. If C had co-variant type qualifiers, ... */ -static void -e500_move_ev_register (void (*move) (struct regcache *regcache, - int regnum, gdb_byte *buf), - struct regcache *regcache, int ev_reg, - gdb_byte *buffer) + +static enum register_status +e500_move_ev_register (move_ev_register_func move, + struct regcache *regcache, int ev_reg, void *buffer) { - struct gdbarch *arch = get_regcache_arch (regcache); + struct gdbarch *arch = regcache->arch (); struct gdbarch_tdep *tdep = gdbarch_tdep (arch); int reg_index; - gdb_byte *byte_buffer = buffer; + gdb_byte *byte_buffer = (gdb_byte *) buffer; + enum register_status status; gdb_assert (IS_SPE_PSEUDOREG (tdep, ev_reg)); @@ -2528,149 +2620,570 @@ e500_move_ev_register (void (*move) (struct regcache *regcache, if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG) { - move (regcache, tdep->ppc_ev0_upper_regnum + reg_index, byte_buffer); - move (regcache, tdep->ppc_gp0_regnum + reg_index, byte_buffer + 4); + status = move (regcache, tdep->ppc_ev0_upper_regnum + reg_index, + byte_buffer); + if (status == REG_VALID) + status = move (regcache, tdep->ppc_gp0_regnum + reg_index, + byte_buffer + 4); } else { - move (regcache, tdep->ppc_gp0_regnum + reg_index, byte_buffer); - move (regcache, tdep->ppc_ev0_upper_regnum + reg_index, byte_buffer + 4); + status = move (regcache, tdep->ppc_gp0_regnum + reg_index, byte_buffer); + if (status == REG_VALID) + status = move (regcache, tdep->ppc_ev0_upper_regnum + reg_index, + byte_buffer + 4); } + + return status; } -static void -e500_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, - int reg_nr, gdb_byte *buffer) +static enum register_status +do_regcache_raw_write (struct regcache *regcache, int regnum, void *buffer) { - e500_move_ev_register (regcache_raw_read, regcache, reg_nr, buffer); + regcache->raw_write (regnum, (const gdb_byte *) buffer); + + return REG_VALID; +} + +static enum register_status +e500_pseudo_register_read (struct gdbarch *gdbarch, readable_regcache *regcache, + int ev_reg, gdb_byte *buffer) +{ + struct gdbarch *arch = regcache->arch (); + struct gdbarch_tdep *tdep = gdbarch_tdep (arch); + int reg_index; + enum register_status status; + + gdb_assert (IS_SPE_PSEUDOREG (tdep, ev_reg)); + + reg_index = ev_reg - tdep->ppc_ev0_regnum; + + if (gdbarch_byte_order (arch) == BFD_ENDIAN_BIG) + { + status = regcache->raw_read (tdep->ppc_ev0_upper_regnum + reg_index, + buffer); + if (status == REG_VALID) + status = regcache->raw_read (tdep->ppc_gp0_regnum + reg_index, + buffer + 4); + } + else + { + status = regcache->raw_read (tdep->ppc_gp0_regnum + reg_index, buffer); + if (status == REG_VALID) + status = regcache->raw_read (tdep->ppc_ev0_upper_regnum + reg_index, + buffer + 4); + } + + return status; + } static void e500_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, int reg_nr, const gdb_byte *buffer) { - e500_move_ev_register ((void (*) (struct regcache *, int, gdb_byte *)) - regcache_raw_write, - regcache, reg_nr, (gdb_byte *) buffer); + e500_move_ev_register (do_regcache_raw_write, regcache, + reg_nr, (void *) buffer); } -/* Read method for PPC pseudo-registers. Currently this is handling the - 16 decimal128 registers that map into 16 pairs of FP registers. */ -static void -ppc_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, +/* Read method for DFP pseudo-registers. */ +static enum register_status +dfp_pseudo_register_read (struct gdbarch *gdbarch, readable_regcache *regcache, int reg_nr, gdb_byte *buffer) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - int reg_index = reg_nr - tdep->ppc_dl0_regnum; + int reg_index, fp0; + enum register_status status; + + if (IS_DFP_PSEUDOREG (tdep, reg_nr)) + { + reg_index = reg_nr - tdep->ppc_dl0_regnum; + fp0 = PPC_F0_REGNUM; + } + else + { + gdb_assert (IS_CDFP_PSEUDOREG (tdep, reg_nr)); + + reg_index = reg_nr - tdep->ppc_cdl0_regnum; + fp0 = PPC_CF0_REGNUM; + } if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) { /* Read two FP registers to form a whole dl register. */ - regcache_raw_read (regcache, tdep->ppc_fp0_regnum + - 2 * reg_index, buffer); - regcache_raw_read (regcache, tdep->ppc_fp0_regnum + - 2 * reg_index + 1, buffer + 8); + status = regcache->raw_read (fp0 + 2 * reg_index, buffer); + if (status == REG_VALID) + status = regcache->raw_read (fp0 + 2 * reg_index + 1, + buffer + 8); } else { - regcache_raw_read (regcache, tdep->ppc_fp0_regnum + - 2 * reg_index + 1, buffer + 8); - regcache_raw_read (regcache, tdep->ppc_fp0_regnum + - 2 * reg_index, buffer); + status = regcache->raw_read (fp0 + 2 * reg_index + 1, buffer); + if (status == REG_VALID) + status = regcache->raw_read (fp0 + 2 * reg_index, buffer + 8); } + + return status; } -/* Write method for PPC pseudo-registers. Currently this is handling the - 16 decimal128 registers that map into 16 pairs of FP registers. */ +/* Write method for DFP pseudo-registers. */ static void -ppc_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, +dfp_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, int reg_nr, const gdb_byte *buffer) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - int reg_index = reg_nr - tdep->ppc_dl0_regnum; + int reg_index, fp0; + + if (IS_DFP_PSEUDOREG (tdep, reg_nr)) + { + reg_index = reg_nr - tdep->ppc_dl0_regnum; + fp0 = PPC_F0_REGNUM; + } + else + { + gdb_assert (IS_CDFP_PSEUDOREG (tdep, reg_nr)); + + reg_index = reg_nr - tdep->ppc_cdl0_regnum; + fp0 = PPC_CF0_REGNUM; + } if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) { /* Write each half of the dl register into a separate - FP register. */ - regcache_raw_write (regcache, tdep->ppc_fp0_regnum + - 2 * reg_index, buffer); - regcache_raw_write (regcache, tdep->ppc_fp0_regnum + - 2 * reg_index + 1, buffer + 8); + FP register. */ + regcache->raw_write (fp0 + 2 * reg_index, buffer); + regcache->raw_write (fp0 + 2 * reg_index + 1, buffer + 8); } else { - regcache_raw_write (regcache, tdep->ppc_fp0_regnum + - 2 * reg_index + 1, buffer + 8); - regcache_raw_write (regcache, tdep->ppc_fp0_regnum + - 2 * reg_index, buffer); + regcache->raw_write (fp0 + 2 * reg_index + 1, buffer); + regcache->raw_write (fp0 + 2 * reg_index, buffer + 8); } } -static void -rs6000_pseudo_register_read (struct gdbarch *gdbarch, struct regcache *regcache, - int reg_nr, gdb_byte *buffer) -{ - struct gdbarch *regcache_arch = get_regcache_arch (regcache); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); +/* Read method for the vX aliases for the raw vrX registers. */ - gdb_assert (regcache_arch == gdbarch); +static enum register_status +v_alias_pseudo_register_read (struct gdbarch *gdbarch, + readable_regcache *regcache, int reg_nr, + gdb_byte *buffer) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + gdb_assert (IS_V_ALIAS_PSEUDOREG (tdep, reg_nr)); - if (IS_SPE_PSEUDOREG (tdep, reg_nr)) - e500_pseudo_register_read (gdbarch, regcache, reg_nr, buffer); - else if (IS_DFP_PSEUDOREG (tdep, reg_nr)) - ppc_pseudo_register_read (gdbarch, regcache, reg_nr, buffer); - else - internal_error (__FILE__, __LINE__, - _("rs6000_pseudo_register_read: " - "called on unexpected register '%s' (%d)"), - gdbarch_register_name (gdbarch, reg_nr), reg_nr); + return regcache->raw_read (tdep->ppc_vr0_regnum + + (reg_nr - tdep->ppc_v0_alias_regnum), + buffer); } +/* Write method for the vX aliases for the raw vrX registers. */ + static void -rs6000_pseudo_register_write (struct gdbarch *gdbarch, - struct regcache *regcache, - int reg_nr, const gdb_byte *buffer) +v_alias_pseudo_register_write (struct gdbarch *gdbarch, + struct regcache *regcache, + int reg_nr, const gdb_byte *buffer) { - struct gdbarch *regcache_arch = get_regcache_arch (regcache); - struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - - gdb_assert (regcache_arch == gdbarch); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + gdb_assert (IS_V_ALIAS_PSEUDOREG (tdep, reg_nr)); - if (IS_SPE_PSEUDOREG (tdep, reg_nr)) - e500_pseudo_register_write (gdbarch, regcache, reg_nr, buffer); - else if (IS_DFP_PSEUDOREG (tdep, reg_nr)) - ppc_pseudo_register_write (gdbarch, regcache, reg_nr, buffer); - else - internal_error (__FILE__, __LINE__, - _("rs6000_pseudo_register_write: " - "called on unexpected register '%s' (%d)"), - gdbarch_register_name (gdbarch, reg_nr), reg_nr); + regcache->raw_write (tdep->ppc_vr0_regnum + + (reg_nr - tdep->ppc_v0_alias_regnum), buffer); } -/* Convert a DBX STABS register number to a GDB register number. */ -static int -rs6000_stab_reg_to_regnum (struct gdbarch *gdbarch, int num) +/* Read method for POWER7 VSX pseudo-registers. */ +static enum register_status +vsx_pseudo_register_read (struct gdbarch *gdbarch, readable_regcache *regcache, + int reg_nr, gdb_byte *buffer) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int reg_index, vr0, fp0, vsr0_upper; + enum register_status status; - if (0 <= num && num <= 31) - return tdep->ppc_gp0_regnum + num; - else if (32 <= num && num <= 63) - /* FIXME: jimb/2004-05-05: What should we do when the debug info - specifies registers the architecture doesn't have? Our - callers don't check the value we return. */ - return tdep->ppc_fp0_regnum + (num - 32); - else if (77 <= num && num <= 108) - return tdep->ppc_vr0_regnum + (num - 77); - else if (1200 <= num && num < 1200 + 32) - return tdep->ppc_ev0_regnum + (num - 1200); + if (IS_VSX_PSEUDOREG (tdep, reg_nr)) + { + reg_index = reg_nr - tdep->ppc_vsr0_regnum; + vr0 = PPC_VR0_REGNUM; + fp0 = PPC_F0_REGNUM; + vsr0_upper = PPC_VSR0_UPPER_REGNUM; + } else - switch (num) + { + gdb_assert (IS_CVSX_PSEUDOREG (tdep, reg_nr)); + + reg_index = reg_nr - tdep->ppc_cvsr0_regnum; + vr0 = PPC_CVR0_REGNUM; + fp0 = PPC_CF0_REGNUM; + vsr0_upper = PPC_CVSR0_UPPER_REGNUM; + } + + /* Read the portion that overlaps the VMX registers. */ + if (reg_index > 31) + status = regcache->raw_read (vr0 + reg_index - 32, buffer); + else + /* Read the portion that overlaps the FPR registers. */ + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) { - case 64: - return tdep->ppc_mq_regnum; - case 65: + status = regcache->raw_read (fp0 + reg_index, buffer); + if (status == REG_VALID) + status = regcache->raw_read (vsr0_upper + reg_index, + buffer + 8); + } + else + { + status = regcache->raw_read (fp0 + reg_index, buffer + 8); + if (status == REG_VALID) + status = regcache->raw_read (vsr0_upper + reg_index, buffer); + } + + return status; +} + +/* Write method for POWER7 VSX pseudo-registers. */ +static void +vsx_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, + int reg_nr, const gdb_byte *buffer) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int reg_index, vr0, fp0, vsr0_upper; + + if (IS_VSX_PSEUDOREG (tdep, reg_nr)) + { + reg_index = reg_nr - tdep->ppc_vsr0_regnum; + vr0 = PPC_VR0_REGNUM; + fp0 = PPC_F0_REGNUM; + vsr0_upper = PPC_VSR0_UPPER_REGNUM; + } + else + { + gdb_assert (IS_CVSX_PSEUDOREG (tdep, reg_nr)); + + reg_index = reg_nr - tdep->ppc_cvsr0_regnum; + vr0 = PPC_CVR0_REGNUM; + fp0 = PPC_CF0_REGNUM; + vsr0_upper = PPC_CVSR0_UPPER_REGNUM; + } + + /* Write the portion that overlaps the VMX registers. */ + if (reg_index > 31) + regcache->raw_write (vr0 + reg_index - 32, buffer); + else + /* Write the portion that overlaps the FPR registers. */ + if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG) + { + regcache->raw_write (fp0 + reg_index, buffer); + regcache->raw_write (vsr0_upper + reg_index, buffer + 8); + } + else + { + regcache->raw_write (fp0 + reg_index, buffer + 8); + regcache->raw_write (vsr0_upper + reg_index, buffer); + } +} + +/* Read method for POWER7 Extended FP pseudo-registers. */ +static enum register_status +efp_pseudo_register_read (struct gdbarch *gdbarch, readable_regcache *regcache, + int reg_nr, gdb_byte *buffer) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int reg_index, vr0; + + if (IS_EFP_PSEUDOREG (tdep, reg_nr)) + { + reg_index = reg_nr - tdep->ppc_efpr0_regnum; + vr0 = PPC_VR0_REGNUM; + } + else + { + gdb_assert (IS_CEFP_PSEUDOREG (tdep, reg_nr)); + + reg_index = reg_nr - tdep->ppc_cefpr0_regnum; + vr0 = PPC_CVR0_REGNUM; + } + + int offset = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 0 : 8; + + /* Read the portion that overlaps the VMX register. */ + return regcache->raw_read_part (vr0 + reg_index, offset, + register_size (gdbarch, reg_nr), + buffer); +} + +/* Write method for POWER7 Extended FP pseudo-registers. */ +static void +efp_pseudo_register_write (struct gdbarch *gdbarch, struct regcache *regcache, + int reg_nr, const gdb_byte *buffer) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int reg_index, vr0; + int offset = gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG ? 0 : 8; + + if (IS_EFP_PSEUDOREG (tdep, reg_nr)) + { + reg_index = reg_nr - tdep->ppc_efpr0_regnum; + vr0 = PPC_VR0_REGNUM; + } + else + { + gdb_assert (IS_CEFP_PSEUDOREG (tdep, reg_nr)); + + reg_index = reg_nr - tdep->ppc_cefpr0_regnum; + vr0 = PPC_CVR0_REGNUM; + + /* The call to raw_write_part fails silently if the initial read + of the read-update-write sequence returns an invalid status, + so we check this manually and throw an error if needed. */ + regcache->raw_update (vr0 + reg_index); + if (regcache->get_register_status (vr0 + reg_index) != REG_VALID) + error (_("Cannot write to the checkpointed EFP register, " + "the corresponding vector register is unavailable.")); + } + + /* Write the portion that overlaps the VMX register. */ + regcache->raw_write_part (vr0 + reg_index, offset, + register_size (gdbarch, reg_nr), buffer); +} + +static enum register_status +rs6000_pseudo_register_read (struct gdbarch *gdbarch, + readable_regcache *regcache, + int reg_nr, gdb_byte *buffer) +{ + struct gdbarch *regcache_arch = regcache->arch (); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + gdb_assert (regcache_arch == gdbarch); + + if (IS_SPE_PSEUDOREG (tdep, reg_nr)) + return e500_pseudo_register_read (gdbarch, regcache, reg_nr, buffer); + else if (IS_DFP_PSEUDOREG (tdep, reg_nr) + || IS_CDFP_PSEUDOREG (tdep, reg_nr)) + return dfp_pseudo_register_read (gdbarch, regcache, reg_nr, buffer); + else if (IS_V_ALIAS_PSEUDOREG (tdep, reg_nr)) + return v_alias_pseudo_register_read (gdbarch, regcache, reg_nr, + buffer); + else if (IS_VSX_PSEUDOREG (tdep, reg_nr) + || IS_CVSX_PSEUDOREG (tdep, reg_nr)) + return vsx_pseudo_register_read (gdbarch, regcache, reg_nr, buffer); + else if (IS_EFP_PSEUDOREG (tdep, reg_nr) + || IS_CEFP_PSEUDOREG (tdep, reg_nr)) + return efp_pseudo_register_read (gdbarch, regcache, reg_nr, buffer); + else + internal_error (__FILE__, __LINE__, + _("rs6000_pseudo_register_read: " + "called on unexpected register '%s' (%d)"), + gdbarch_register_name (gdbarch, reg_nr), reg_nr); +} + +static void +rs6000_pseudo_register_write (struct gdbarch *gdbarch, + struct regcache *regcache, + int reg_nr, const gdb_byte *buffer) +{ + struct gdbarch *regcache_arch = regcache->arch (); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + gdb_assert (regcache_arch == gdbarch); + + if (IS_SPE_PSEUDOREG (tdep, reg_nr)) + e500_pseudo_register_write (gdbarch, regcache, reg_nr, buffer); + else if (IS_DFP_PSEUDOREG (tdep, reg_nr) + || IS_CDFP_PSEUDOREG (tdep, reg_nr)) + dfp_pseudo_register_write (gdbarch, regcache, reg_nr, buffer); + else if (IS_V_ALIAS_PSEUDOREG (tdep, reg_nr)) + v_alias_pseudo_register_write (gdbarch, regcache, reg_nr, buffer); + else if (IS_VSX_PSEUDOREG (tdep, reg_nr) + || IS_CVSX_PSEUDOREG (tdep, reg_nr)) + vsx_pseudo_register_write (gdbarch, regcache, reg_nr, buffer); + else if (IS_EFP_PSEUDOREG (tdep, reg_nr) + || IS_CEFP_PSEUDOREG (tdep, reg_nr)) + efp_pseudo_register_write (gdbarch, regcache, reg_nr, buffer); + else + internal_error (__FILE__, __LINE__, + _("rs6000_pseudo_register_write: " + "called on unexpected register '%s' (%d)"), + gdbarch_register_name (gdbarch, reg_nr), reg_nr); +} + +/* Set the register mask in AX with the registers that form the DFP or + checkpointed DFP pseudo-register REG_NR. */ + +static void +dfp_ax_pseudo_register_collect (struct gdbarch *gdbarch, + struct agent_expr *ax, int reg_nr) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int reg_index, fp0; + + if (IS_DFP_PSEUDOREG (tdep, reg_nr)) + { + reg_index = reg_nr - tdep->ppc_dl0_regnum; + fp0 = PPC_F0_REGNUM; + } + else + { + gdb_assert (IS_CDFP_PSEUDOREG (tdep, reg_nr)); + + reg_index = reg_nr - tdep->ppc_cdl0_regnum; + fp0 = PPC_CF0_REGNUM; + } + + ax_reg_mask (ax, fp0 + 2 * reg_index); + ax_reg_mask (ax, fp0 + 2 * reg_index + 1); +} + +/* Set the register mask in AX with the raw vector register that + corresponds to its REG_NR alias. */ + +static void +v_alias_pseudo_register_collect (struct gdbarch *gdbarch, + struct agent_expr *ax, int reg_nr) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + gdb_assert (IS_V_ALIAS_PSEUDOREG (tdep, reg_nr)); + + ax_reg_mask (ax, tdep->ppc_vr0_regnum + + (reg_nr - tdep->ppc_v0_alias_regnum)); +} + +/* Set the register mask in AX with the registers that form the VSX or + checkpointed VSX pseudo-register REG_NR. */ + +static void +vsx_ax_pseudo_register_collect (struct gdbarch *gdbarch, + struct agent_expr *ax, int reg_nr) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int reg_index, vr0, fp0, vsr0_upper; + + if (IS_VSX_PSEUDOREG (tdep, reg_nr)) + { + reg_index = reg_nr - tdep->ppc_vsr0_regnum; + vr0 = PPC_VR0_REGNUM; + fp0 = PPC_F0_REGNUM; + vsr0_upper = PPC_VSR0_UPPER_REGNUM; + } + else + { + gdb_assert (IS_CVSX_PSEUDOREG (tdep, reg_nr)); + + reg_index = reg_nr - tdep->ppc_cvsr0_regnum; + vr0 = PPC_CVR0_REGNUM; + fp0 = PPC_CF0_REGNUM; + vsr0_upper = PPC_CVSR0_UPPER_REGNUM; + } + + if (reg_index > 31) + { + ax_reg_mask (ax, vr0 + reg_index - 32); + } + else + { + ax_reg_mask (ax, fp0 + reg_index); + ax_reg_mask (ax, vsr0_upper + reg_index); + } +} + +/* Set the register mask in AX with the register that corresponds to + the EFP or checkpointed EFP pseudo-register REG_NR. */ + +static void +efp_ax_pseudo_register_collect (struct gdbarch *gdbarch, + struct agent_expr *ax, int reg_nr) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int reg_index, vr0; + + if (IS_EFP_PSEUDOREG (tdep, reg_nr)) + { + reg_index = reg_nr - tdep->ppc_efpr0_regnum; + vr0 = PPC_VR0_REGNUM; + } + else + { + gdb_assert (IS_CEFP_PSEUDOREG (tdep, reg_nr)); + + reg_index = reg_nr - tdep->ppc_cefpr0_regnum; + vr0 = PPC_CVR0_REGNUM; + } + + ax_reg_mask (ax, vr0 + reg_index); +} + +static int +rs6000_ax_pseudo_register_collect (struct gdbarch *gdbarch, + struct agent_expr *ax, int reg_nr) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + if (IS_SPE_PSEUDOREG (tdep, reg_nr)) + { + int reg_index = reg_nr - tdep->ppc_ev0_regnum; + ax_reg_mask (ax, tdep->ppc_gp0_regnum + reg_index); + ax_reg_mask (ax, tdep->ppc_ev0_upper_regnum + reg_index); + } + else if (IS_DFP_PSEUDOREG (tdep, reg_nr) + || IS_CDFP_PSEUDOREG (tdep, reg_nr)) + { + dfp_ax_pseudo_register_collect (gdbarch, ax, reg_nr); + } + else if (IS_V_ALIAS_PSEUDOREG (tdep, reg_nr)) + { + v_alias_pseudo_register_collect (gdbarch, ax, reg_nr); + } + else if (IS_VSX_PSEUDOREG (tdep, reg_nr) + || IS_CVSX_PSEUDOREG (tdep, reg_nr)) + { + vsx_ax_pseudo_register_collect (gdbarch, ax, reg_nr); + } + else if (IS_EFP_PSEUDOREG (tdep, reg_nr) + || IS_CEFP_PSEUDOREG (tdep, reg_nr)) + { + efp_ax_pseudo_register_collect (gdbarch, ax, reg_nr); + } + else + internal_error (__FILE__, __LINE__, + _("rs6000_pseudo_register_collect: " + "called on unexpected register '%s' (%d)"), + gdbarch_register_name (gdbarch, reg_nr), reg_nr); + return 0; +} + + +static void +rs6000_gen_return_address (struct gdbarch *gdbarch, + struct agent_expr *ax, struct axs_value *value, + CORE_ADDR scope) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + value->type = register_type (gdbarch, tdep->ppc_lr_regnum); + value->kind = axs_lvalue_register; + value->u.reg = tdep->ppc_lr_regnum; +} + + +/* Convert a DBX STABS register number to a GDB register number. */ +static int +rs6000_stab_reg_to_regnum (struct gdbarch *gdbarch, int num) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + if (0 <= num && num <= 31) + return tdep->ppc_gp0_regnum + num; + else if (32 <= num && num <= 63) + /* FIXME: jimb/2004-05-05: What should we do when the debug info + specifies registers the architecture doesn't have? Our + callers don't check the value we return. */ + return tdep->ppc_fp0_regnum + (num - 32); + else if (77 <= num && num <= 108) + return tdep->ppc_vr0_regnum + (num - 77); + else if (1200 <= num && num < 1200 + 32) + return tdep->ppc_ev0_upper_regnum + (num - 1200); + else + switch (num) + { + case 64: + return tdep->ppc_mq_regnum; + case 65: return tdep->ppc_lr_regnum; case 66: return tdep->ppc_ctr_regnum; @@ -2706,7 +3219,7 @@ rs6000_dwarf2_reg_to_regnum (struct gdbarch *gdbarch, int num) else if (1124 <= num && num < 1124 + 32) return tdep->ppc_vr0_regnum + (num - 1124); else if (1200 <= num && num < 1200 + 32) - return tdep->ppc_ev0_regnum + (num - 1200); + return tdep->ppc_ev0_upper_regnum + (num - 1200); else switch (num) { @@ -2797,52 +3310,18 @@ rs6000_adjust_frame_regnum (struct gdbarch *gdbarch, int num, int eh_frame_p) } } -/* Support for CONVERT_FROM_FUNC_PTR_ADDR (ARCH, ADDR, TARG). - - Usually a function pointer's representation is simply the address - of the function. On the RS/6000 however, a function pointer is - represented by a pointer to an OPD entry. This OPD entry contains - three words, the first word is the address of the function, the - second word is the TOC pointer (r2), and the third word is the - static chain value. Throughout GDB it is currently assumed that a - function pointer contains the address of the function, which is not - easy to fix. In addition, the conversion of a function address to - a function pointer would require allocation of an OPD entry in the - inferior's memory space, with all its drawbacks. To be able to - call C++ virtual methods in the inferior (which are called via - function pointers), find_function_addr uses this function to get the - function address from a function pointer. */ - -/* Return real function address if ADDR (a function pointer) is in the data - space and is therefore a special function pointer. */ - -static CORE_ADDR -rs6000_convert_from_func_ptr_addr (struct gdbarch *gdbarch, - CORE_ADDR addr, - struct target_ops *targ) -{ - struct obj_section *s; - - s = find_pc_section (addr); - if (s && s->the_bfd_section->flags & SEC_CODE) - return addr; - - /* ADDR is in the data space, so it's a special function pointer. */ - return read_memory_addr (addr, gdbarch_tdep (gdbarch)->wordsize); -} - /* Handling the various POWER/PowerPC variants. */ /* Information about a particular processor variant. */ -struct variant +struct ppc_variant { /* Name of this variant. */ - char *name; + const char *name; /* English description of the variant. */ - char *description; + const char *description; /* bfd_arch_info.arch corresponding to variant. */ enum bfd_architecture arch; @@ -2854,14 +3333,16 @@ struct variant struct target_desc **tdesc; }; -static struct variant variants[] = +static struct ppc_variant variants[] = { {"powerpc", "PowerPC user-level", bfd_arch_powerpc, - bfd_mach_ppc, &tdesc_powerpc_32}, + bfd_mach_ppc, &tdesc_powerpc_altivec32}, {"power", "POWER user-level", bfd_arch_rs6000, bfd_mach_rs6k, &tdesc_rs6000}, {"403", "IBM PowerPC 403", bfd_arch_powerpc, bfd_mach_ppc_403, &tdesc_powerpc_403}, + {"405", "IBM PowerPC 405", bfd_arch_powerpc, + bfd_mach_ppc_405, &tdesc_powerpc_405}, {"601", "Motorola PowerPC 601", bfd_arch_powerpc, bfd_mach_ppc_601, &tdesc_powerpc_601}, {"602", "Motorola PowerPC 602", bfd_arch_powerpc, @@ -2885,7 +3366,7 @@ static struct variant variants[] = /* 64-bit */ {"powerpc64", "PowerPC 64-bit user-level", bfd_arch_powerpc, - bfd_mach_ppc64, &tdesc_powerpc_64}, + bfd_mach_ppc64, &tdesc_powerpc_altivec64}, {"620", "Motorola PowerPC 620", bfd_arch_powerpc, bfd_mach_ppc_620, &tdesc_powerpc_64}, {"630", "Motorola PowerPC 630", bfd_arch_powerpc, @@ -2905,16 +3386,16 @@ static struct variant variants[] = {"rs2", "IBM POWER RS2", bfd_arch_rs6000, bfd_mach_rs6k_rs2, &tdesc_rs6000}, - {0, 0, 0, 0, 0} + {0, 0, (enum bfd_architecture) 0, 0, 0} }; /* Return the variant corresponding to architecture ARCH and machine number MACH. If no such variant exists, return null. */ -static const struct variant * +static const struct ppc_variant * find_variant_by_arch (enum bfd_architecture arch, unsigned long mach) { - const struct variant *v; + const struct ppc_variant *v; for (v = variants; v->name; v++) if (arch == v->arch && mach == v->mach) @@ -2923,74 +3404,68 @@ find_variant_by_arch (enum bfd_architecture arch, unsigned long mach) return NULL; } -static int -gdb_print_insn_powerpc (bfd_vma memaddr, disassemble_info *info) -{ - if (!info->disassembler_options) - info->disassembler_options = "any"; - - if (info->endian == BFD_ENDIAN_BIG) - return print_insn_big_powerpc (memaddr, info); - else - return print_insn_little_powerpc (memaddr, info); -} -static CORE_ADDR -rs6000_unwind_pc (struct gdbarch *gdbarch, struct frame_info *next_frame) -{ - return frame_unwind_register_unsigned (next_frame, - gdbarch_pc_regnum (gdbarch)); -} - -static struct frame_id -rs6000_unwind_dummy_id (struct gdbarch *gdbarch, struct frame_info *next_frame) -{ - return frame_id_build (frame_unwind_register_unsigned - (next_frame, gdbarch_sp_regnum (gdbarch)), - frame_pc_unwind (next_frame)); -} struct rs6000_frame_cache { CORE_ADDR base; CORE_ADDR initial_sp; struct trad_frame_saved_reg *saved_regs; + + /* Set BASE_P to true if this frame cache is properly initialized. + Otherwise set to false because some registers or memory cannot + collected. */ + int base_p; + /* Cache PC for building unavailable frame. */ + CORE_ADDR pc; }; static struct rs6000_frame_cache * -rs6000_frame_cache (struct frame_info *next_frame, void **this_cache) +rs6000_frame_cache (struct frame_info *this_frame, void **this_cache) { struct rs6000_frame_cache *cache; - struct gdbarch *gdbarch = get_frame_arch (next_frame); + struct gdbarch *gdbarch = get_frame_arch (this_frame); struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); struct rs6000_framedata fdata; int wordsize = tdep->wordsize; - CORE_ADDR func, pc; + CORE_ADDR func = 0, pc = 0; if ((*this_cache) != NULL) - return (*this_cache); + return (struct rs6000_frame_cache *) (*this_cache); cache = FRAME_OBSTACK_ZALLOC (struct rs6000_frame_cache); (*this_cache) = cache; - cache->saved_regs = trad_frame_alloc_saved_regs (next_frame); - - func = frame_func_unwind (next_frame, NORMAL_FRAME); - pc = frame_pc_unwind (next_frame); - skip_prologue (gdbarch, func, pc, &fdata); + cache->pc = 0; + cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); - /* Figure out the parent's stack pointer. */ - - /* NOTE: cagney/2002-04-14: The ->frame points to the inner-most - address of the current frame. Things might be easier if the - ->frame pointed to the outer-most address of the frame. In - the mean time, the address of the prev frame is used as the - base address of this frame. */ - cache->base = frame_unwind_register_unsigned - (next_frame, gdbarch_sp_regnum (gdbarch)); + try + { + func = get_frame_func (this_frame); + cache->pc = func; + pc = get_frame_pc (this_frame); + skip_prologue (gdbarch, func, pc, &fdata); + + /* Figure out the parent's stack pointer. */ + + /* NOTE: cagney/2002-04-14: The ->frame points to the inner-most + address of the current frame. Things might be easier if the + ->frame pointed to the outer-most address of the frame. In + the mean time, the address of the prev frame is used as the + base address of this frame. */ + cache->base = get_frame_register_unsigned + (this_frame, gdbarch_sp_regnum (gdbarch)); + } + catch (const gdb_exception_error &ex) + { + if (ex.error != NOT_AVAILABLE_ERROR) + throw; + return (struct rs6000_frame_cache *) (*this_cache); + } /* If the function appears to be frameless, check a couple of likely indicators that we have simply failed to find the frame setup. Two common cases of this are missing symbols (i.e. - frame_func_unwind returns the wrong address or 0), and assembly + get_frame_func returns the wrong address or 0), and assembly stubs which have a fast exit path but set up a frame on the slow path. @@ -3001,8 +3476,7 @@ rs6000_frame_cache (struct frame_info *next_frame, void **this_cache) CORE_ADDR saved_lr; int make_frame = 0; - saved_lr = frame_unwind_register_unsigned (next_frame, - tdep->ppc_lr_regnum); + saved_lr = get_frame_register_unsigned (this_frame, tdep->ppc_lr_regnum); if (func == 0 && saved_lr == pc) make_frame = 1; else if (func != 0) @@ -3020,8 +3494,14 @@ rs6000_frame_cache (struct frame_info *next_frame, void **this_cache) } if (!fdata.frameless) - /* Frameless really means stackless. */ - cache->base = read_memory_addr (cache->base, wordsize); + { + /* Frameless really means stackless. */ + ULONGEST backchain; + + if (safe_read_memory_unsigned_integer (cache->base, wordsize, + byte_order, &backchain)) + cache->base = (CORE_ADDR) backchain; + } trad_frame_set_value (cache->saved_regs, gdbarch_sp_regnum (gdbarch), cache->base); @@ -3047,7 +3527,8 @@ rs6000_frame_cache (struct frame_info *next_frame, void **this_cache) } /* if != -1, fdata.saved_gpr is the smallest number of saved_gpr. - All gpr's from saved_gpr to gpr31 are saved. */ + All gpr's from saved_gpr to gpr31 are saved (except during the + prologue). */ if (fdata.saved_gpr >= 0) { @@ -3055,7 +3536,8 @@ rs6000_frame_cache (struct frame_info *next_frame, void **this_cache) CORE_ADDR gpr_addr = cache->base + fdata.gpr_offset; for (i = fdata.saved_gpr; i < ppc_num_gprs; i++) { - cache->saved_regs[tdep->ppc_gp0_regnum + i].addr = gpr_addr; + if (fdata.gpr_mask & (1U << i)) + cache->saved_regs[tdep->ppc_gp0_regnum + i].addr = gpr_addr; gpr_addr += wordsize; } } @@ -3077,31 +3559,37 @@ rs6000_frame_cache (struct frame_info *next_frame, void **this_cache) } /* if != -1, fdata.saved_ev is the smallest number of saved_ev. - All vr's from saved_ev to ev31 are saved. ????? */ + All vr's from saved_ev to ev31 are saved. ????? */ if (tdep->ppc_ev0_regnum != -1) { if (fdata.saved_ev >= 0) { int i; CORE_ADDR ev_addr = cache->base + fdata.ev_offset; + CORE_ADDR off = (byte_order == BFD_ENDIAN_BIG ? 4 : 0); + for (i = fdata.saved_ev; i < ppc_num_gprs; i++) { cache->saved_regs[tdep->ppc_ev0_regnum + i].addr = ev_addr; - cache->saved_regs[tdep->ppc_gp0_regnum + i].addr = ev_addr + 4; + cache->saved_regs[tdep->ppc_gp0_regnum + i].addr = ev_addr + off; ev_addr += register_size (gdbarch, tdep->ppc_ev0_regnum); - } + } } } /* If != 0, fdata.cr_offset is the offset from the frame that holds the CR. */ if (fdata.cr_offset != 0) - cache->saved_regs[tdep->ppc_cr_regnum].addr = cache->base + fdata.cr_offset; + cache->saved_regs[tdep->ppc_cr_regnum].addr + = cache->base + fdata.cr_offset; /* If != 0, fdata.lr_offset is the offset from the frame that holds the LR. */ if (fdata.lr_offset != 0) - cache->saved_regs[tdep->ppc_lr_regnum].addr = cache->base + fdata.lr_offset; + cache->saved_regs[tdep->ppc_lr_regnum].addr + = cache->base + fdata.lr_offset; + else if (fdata.lr_register != -1) + cache->saved_regs[tdep->ppc_lr_regnum].realreg = fdata.lr_register; /* The PC is found in the link register. */ cache->saved_regs[gdbarch_pc_regnum (gdbarch)] = cache->saved_regs[tdep->ppc_lr_regnum]; @@ -3109,87 +3597,189 @@ rs6000_frame_cache (struct frame_info *next_frame, void **this_cache) /* If != 0, fdata.vrsave_offset is the offset from the frame that holds the VRSAVE. */ if (fdata.vrsave_offset != 0) - cache->saved_regs[tdep->ppc_vrsave_regnum].addr = cache->base + fdata.vrsave_offset; + cache->saved_regs[tdep->ppc_vrsave_regnum].addr + = cache->base + fdata.vrsave_offset; if (fdata.alloca_reg < 0) /* If no alloca register used, then fi->frame is the value of the %sp for this frame, and it is good enough. */ - cache->initial_sp = frame_unwind_register_unsigned - (next_frame, gdbarch_sp_regnum (gdbarch)); + cache->initial_sp + = get_frame_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch)); else - cache->initial_sp = frame_unwind_register_unsigned (next_frame, - fdata.alloca_reg); + cache->initial_sp + = get_frame_register_unsigned (this_frame, fdata.alloca_reg); + cache->base_p = 1; return cache; } static void -rs6000_frame_this_id (struct frame_info *next_frame, void **this_cache, +rs6000_frame_this_id (struct frame_info *this_frame, void **this_cache, struct frame_id *this_id) { - struct rs6000_frame_cache *info = rs6000_frame_cache (next_frame, + struct rs6000_frame_cache *info = rs6000_frame_cache (this_frame, this_cache); - (*this_id) = frame_id_build (info->base, - frame_func_unwind (next_frame, NORMAL_FRAME)); + + if (!info->base_p) + { + (*this_id) = frame_id_build_unavailable_stack (info->pc); + return; + } + + /* This marks the outermost frame. */ + if (info->base == 0) + return; + + (*this_id) = frame_id_build (info->base, get_frame_func (this_frame)); } -static void -rs6000_frame_prev_register (struct frame_info *next_frame, - void **this_cache, - int regnum, int *optimizedp, - enum lval_type *lvalp, CORE_ADDR *addrp, - int *realnump, gdb_byte *valuep) +static struct value * +rs6000_frame_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) { - struct rs6000_frame_cache *info = rs6000_frame_cache (next_frame, + struct rs6000_frame_cache *info = rs6000_frame_cache (this_frame, this_cache); - trad_frame_get_prev_register (next_frame, info->saved_regs, regnum, - optimizedp, lvalp, addrp, realnump, valuep); + return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum); } static const struct frame_unwind rs6000_frame_unwind = { NORMAL_FRAME, + default_frame_unwind_stop_reason, rs6000_frame_this_id, - rs6000_frame_prev_register + rs6000_frame_prev_register, + NULL, + default_frame_sniffer }; -static const struct frame_unwind * -rs6000_frame_sniffer (struct frame_info *next_frame) +/* Allocate and initialize a frame cache for an epilogue frame. + SP is restored and prev-PC is stored in LR. */ + +static struct rs6000_frame_cache * +rs6000_epilogue_frame_cache (struct frame_info *this_frame, void **this_cache) { - return &rs6000_frame_unwind; -} + struct rs6000_frame_cache *cache; + struct gdbarch *gdbarch = get_frame_arch (this_frame); + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); - + if (*this_cache) + return (struct rs6000_frame_cache *) *this_cache; -static CORE_ADDR -rs6000_frame_base_address (struct frame_info *next_frame, - void **this_cache) -{ - struct rs6000_frame_cache *info = rs6000_frame_cache (next_frame, - this_cache); - return info->initial_sp; -} + cache = FRAME_OBSTACK_ZALLOC (struct rs6000_frame_cache); + (*this_cache) = cache; + cache->saved_regs = trad_frame_alloc_saved_regs (this_frame); -static const struct frame_base rs6000_frame_base = { - &rs6000_frame_unwind, - rs6000_frame_base_address, - rs6000_frame_base_address, - rs6000_frame_base_address -}; + try + { + /* At this point the stack looks as if we just entered the + function, and the return address is stored in LR. */ + CORE_ADDR sp, lr; -static const struct frame_base * -rs6000_frame_base_sniffer (struct frame_info *next_frame) -{ - return &rs6000_frame_base; -} + sp = get_frame_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch)); + lr = get_frame_register_unsigned (this_frame, tdep->ppc_lr_regnum); -/* DWARF-2 frame support. Used to handle the detection of - clobbered registers during function calls. */ + cache->base = sp; + cache->initial_sp = sp; -static void -ppc_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, - struct dwarf2_frame_state_reg *reg, - struct frame_info *next_frame) + trad_frame_set_value (cache->saved_regs, + gdbarch_pc_regnum (gdbarch), lr); + } + catch (const gdb_exception_error &ex) + { + if (ex.error != NOT_AVAILABLE_ERROR) + throw; + } + + return cache; +} + +/* Implementation of frame_unwind.this_id, as defined in frame_unwind.h. + Return the frame ID of an epilogue frame. */ + +static void +rs6000_epilogue_frame_this_id (struct frame_info *this_frame, + void **this_cache, struct frame_id *this_id) +{ + CORE_ADDR pc; + struct rs6000_frame_cache *info = + rs6000_epilogue_frame_cache (this_frame, this_cache); + + pc = get_frame_func (this_frame); + if (info->base == 0) + (*this_id) = frame_id_build_unavailable_stack (pc); + else + (*this_id) = frame_id_build (info->base, pc); +} + +/* Implementation of frame_unwind.prev_register, as defined in frame_unwind.h. + Return the register value of REGNUM in previous frame. */ + +static struct value * +rs6000_epilogue_frame_prev_register (struct frame_info *this_frame, + void **this_cache, int regnum) +{ + struct rs6000_frame_cache *info = + rs6000_epilogue_frame_cache (this_frame, this_cache); + return trad_frame_get_prev_register (this_frame, info->saved_regs, regnum); +} + +/* Implementation of frame_unwind.sniffer, as defined in frame_unwind.h. + Check whether this an epilogue frame. */ + +static int +rs6000_epilogue_frame_sniffer (const struct frame_unwind *self, + struct frame_info *this_frame, + void **this_prologue_cache) +{ + if (frame_relative_level (this_frame) == 0) + return rs6000_in_function_epilogue_frame_p (this_frame, + get_frame_arch (this_frame), + get_frame_pc (this_frame)); + else + return 0; +} + +/* Frame unwinder for epilogue frame. This is required for reverse step-over + a function without debug information. */ + +static const struct frame_unwind rs6000_epilogue_frame_unwind = +{ + NORMAL_FRAME, + default_frame_unwind_stop_reason, + rs6000_epilogue_frame_this_id, rs6000_epilogue_frame_prev_register, + NULL, + rs6000_epilogue_frame_sniffer +}; + + +static CORE_ADDR +rs6000_frame_base_address (struct frame_info *this_frame, void **this_cache) +{ + struct rs6000_frame_cache *info = rs6000_frame_cache (this_frame, + this_cache); + return info->initial_sp; +} + +static const struct frame_base rs6000_frame_base = { + &rs6000_frame_unwind, + rs6000_frame_base_address, + rs6000_frame_base_address, + rs6000_frame_base_address +}; + +static const struct frame_base * +rs6000_frame_base_sniffer (struct frame_info *this_frame) +{ + return &rs6000_frame_base; +} + +/* DWARF-2 frame support. Used to handle the detection of + clobbered registers during function calls. */ + +static void +ppc_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, + struct dwarf2_frame_state_reg *reg, + struct frame_info *this_frame) { struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); @@ -3216,35 +3806,2309 @@ ppc_dwarf2_frame_init_reg (struct gdbarch *gdbarch, int regnum, && regnum <= tdep->ppc_fp0_regnum + 31)) reg->how = DWARF2_FRAME_REG_SAME_VALUE; - /* Call-clobbered FP registers. */ - if ((regnum >= tdep->ppc_fp0_regnum - && regnum <= tdep->ppc_fp0_regnum + 13)) - reg->how = DWARF2_FRAME_REG_UNDEFINED; - } + /* Call-clobbered FP registers. */ + if ((regnum >= tdep->ppc_fp0_regnum + && regnum <= tdep->ppc_fp0_regnum + 13)) + reg->how = DWARF2_FRAME_REG_UNDEFINED; + } + + /* Deal with ALTIVEC registers, if supported. */ + if (tdep->ppc_vr0_regnum > 0 && tdep->ppc_vrsave_regnum > 0) + { + /* Call-saved Altivec registers. */ + if ((regnum >= tdep->ppc_vr0_regnum + 20 + && regnum <= tdep->ppc_vr0_regnum + 31) + || regnum == tdep->ppc_vrsave_regnum) + reg->how = DWARF2_FRAME_REG_SAME_VALUE; + + /* Call-clobbered Altivec registers. */ + if ((regnum >= tdep->ppc_vr0_regnum + && regnum <= tdep->ppc_vr0_regnum + 19)) + reg->how = DWARF2_FRAME_REG_UNDEFINED; + } + + /* Handle PC register and Stack Pointer correctly. */ + if (regnum == gdbarch_pc_regnum (gdbarch)) + reg->how = DWARF2_FRAME_REG_RA; + else if (regnum == gdbarch_sp_regnum (gdbarch)) + reg->how = DWARF2_FRAME_REG_CFA; +} + + +/* Return true if a .gnu_attributes section exists in BFD and it + indicates we are using SPE extensions OR if a .PPC.EMB.apuinfo + section exists in BFD and it indicates that SPE extensions are in + use. Check the .gnu.attributes section first, as the binary might be + compiled for SPE, but not actually using SPE instructions. */ + +static int +bfd_uses_spe_extensions (bfd *abfd) +{ + asection *sect; + gdb_byte *contents = NULL; + bfd_size_type size; + gdb_byte *ptr; + int success = 0; + + if (!abfd) + return 0; + +#ifdef HAVE_ELF + /* Using Tag_GNU_Power_ABI_Vector here is a bit of a hack, as the user + could be using the SPE vector abi without actually using any spe + bits whatsoever. But it's close enough for now. */ + int vector_abi = bfd_elf_get_obj_attr_int (abfd, OBJ_ATTR_GNU, + Tag_GNU_Power_ABI_Vector); + if (vector_abi == 3) + return 1; +#endif + + sect = bfd_get_section_by_name (abfd, ".PPC.EMB.apuinfo"); + if (!sect) + return 0; + + size = bfd_section_size (sect); + contents = (gdb_byte *) xmalloc (size); + if (!bfd_get_section_contents (abfd, sect, contents, 0, size)) + { + xfree (contents); + return 0; + } + + /* Parse the .PPC.EMB.apuinfo section. The layout is as follows: + + struct { + uint32 name_len; + uint32 data_len; + uint32 type; + char name[name_len rounded up to 4-byte alignment]; + char data[data_len]; + }; + + Technically, there's only supposed to be one such structure in a + given apuinfo section, but the linker is not always vigilant about + merging apuinfo sections from input files. Just go ahead and parse + them all, exiting early when we discover the binary uses SPE + insns. + + It's not specified in what endianness the information in this + section is stored. Assume that it's the endianness of the BFD. */ + ptr = contents; + while (1) + { + unsigned int name_len; + unsigned int data_len; + unsigned int type; + + /* If we can't read the first three fields, we're done. */ + if (size < 12) + break; + + name_len = bfd_get_32 (abfd, ptr); + name_len = (name_len + 3) & ~3U; /* Round to 4 bytes. */ + data_len = bfd_get_32 (abfd, ptr + 4); + type = bfd_get_32 (abfd, ptr + 8); + ptr += 12; + + /* The name must be "APUinfo\0". */ + if (name_len != 8 + && strcmp ((const char *) ptr, "APUinfo") != 0) + break; + ptr += name_len; + + /* The type must be 2. */ + if (type != 2) + break; + + /* The data is stored as a series of uint32. The upper half of + each uint32 indicates the particular APU used and the lower + half indicates the revision of that APU. We just care about + the upper half. */ + + /* Not 4-byte quantities. */ + if (data_len & 3U) + break; + + while (data_len) + { + unsigned int apuinfo = bfd_get_32 (abfd, ptr); + unsigned int apu = apuinfo >> 16; + ptr += 4; + data_len -= 4; + + /* The SPE APU is 0x100; the SPEFP APU is 0x101. Accept + either. */ + if (apu == 0x100 || apu == 0x101) + { + success = 1; + data_len = 0; + } + } + + if (success) + break; + } + + xfree (contents); + return success; +} + +/* These are macros for parsing instruction fields (I.1.6.28) */ + +#define PPC_FIELD(value, from, len) \ + (((value) >> (32 - (from) - (len))) & ((1 << (len)) - 1)) +#define PPC_SEXT(v, bs) \ + ((((CORE_ADDR) (v) & (((CORE_ADDR) 1 << (bs)) - 1)) \ + ^ ((CORE_ADDR) 1 << ((bs) - 1))) \ + - ((CORE_ADDR) 1 << ((bs) - 1))) +#define PPC_OP6(insn) PPC_FIELD (insn, 0, 6) +#define PPC_EXTOP(insn) PPC_FIELD (insn, 21, 10) +#define PPC_RT(insn) PPC_FIELD (insn, 6, 5) +#define PPC_RS(insn) PPC_FIELD (insn, 6, 5) +#define PPC_RA(insn) PPC_FIELD (insn, 11, 5) +#define PPC_RB(insn) PPC_FIELD (insn, 16, 5) +#define PPC_NB(insn) PPC_FIELD (insn, 16, 5) +#define PPC_VRT(insn) PPC_FIELD (insn, 6, 5) +#define PPC_FRT(insn) PPC_FIELD (insn, 6, 5) +#define PPC_SPR(insn) (PPC_FIELD (insn, 11, 5) \ + | (PPC_FIELD (insn, 16, 5) << 5)) +#define PPC_BO(insn) PPC_FIELD (insn, 6, 5) +#define PPC_T(insn) PPC_FIELD (insn, 6, 5) +#define PPC_D(insn) PPC_SEXT (PPC_FIELD (insn, 16, 16), 16) +#define PPC_DS(insn) PPC_SEXT (PPC_FIELD (insn, 16, 14), 14) +#define PPC_DQ(insn) PPC_SEXT (PPC_FIELD (insn, 16, 12), 12) +#define PPC_BIT(insn,n) ((insn & (1 << (31 - (n)))) ? 1 : 0) +#define PPC_OE(insn) PPC_BIT (insn, 21) +#define PPC_RC(insn) PPC_BIT (insn, 31) +#define PPC_Rc(insn) PPC_BIT (insn, 21) +#define PPC_LK(insn) PPC_BIT (insn, 31) +#define PPC_TX(insn) PPC_BIT (insn, 31) +#define PPC_LEV(insn) PPC_FIELD (insn, 20, 7) + +#define PPC_XT(insn) ((PPC_TX (insn) << 5) | PPC_T (insn)) +#define PPC_XER_NB(xer) (xer & 0x7f) + +/* Record Vector-Scalar Registers. + For VSR less than 32, it's represented by an FPR and an VSR-upper register. + Otherwise, it's just a VR register. Record them accordingly. */ + +static int +ppc_record_vsr (struct regcache *regcache, struct gdbarch_tdep *tdep, int vsr) +{ + if (vsr < 0 || vsr >= 64) + return -1; + + if (vsr >= 32) + { + if (tdep->ppc_vr0_regnum >= 0) + record_full_arch_list_add_reg (regcache, tdep->ppc_vr0_regnum + vsr - 32); + } + else + { + if (tdep->ppc_fp0_regnum >= 0) + record_full_arch_list_add_reg (regcache, tdep->ppc_fp0_regnum + vsr); + if (tdep->ppc_vsr0_upper_regnum >= 0) + record_full_arch_list_add_reg (regcache, + tdep->ppc_vsr0_upper_regnum + vsr); + } + + return 0; +} + +/* Parse and record instructions primary opcode-4 at ADDR. + Return 0 if successful. */ + +static int +ppc_process_record_op4 (struct gdbarch *gdbarch, struct regcache *regcache, + CORE_ADDR addr, uint32_t insn) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int ext = PPC_FIELD (insn, 21, 11); + int vra = PPC_FIELD (insn, 11, 5); + + switch (ext & 0x3f) + { + case 32: /* Vector Multiply-High-Add Signed Halfword Saturate */ + case 33: /* Vector Multiply-High-Round-Add Signed Halfword Saturate */ + case 39: /* Vector Multiply-Sum Unsigned Halfword Saturate */ + case 41: /* Vector Multiply-Sum Signed Halfword Saturate */ + record_full_arch_list_add_reg (regcache, PPC_VSCR_REGNUM); + /* FALL-THROUGH */ + case 42: /* Vector Select */ + case 43: /* Vector Permute */ + case 59: /* Vector Permute Right-indexed */ + case 44: /* Vector Shift Left Double by Octet Immediate */ + case 45: /* Vector Permute and Exclusive-OR */ + case 60: /* Vector Add Extended Unsigned Quadword Modulo */ + case 61: /* Vector Add Extended & write Carry Unsigned Quadword */ + case 62: /* Vector Subtract Extended Unsigned Quadword Modulo */ + case 63: /* Vector Subtract Extended & write Carry Unsigned Quadword */ + case 34: /* Vector Multiply-Low-Add Unsigned Halfword Modulo */ + case 35: /* Vector Multiply-Sum Unsigned Doubleword Modulo */ + case 36: /* Vector Multiply-Sum Unsigned Byte Modulo */ + case 37: /* Vector Multiply-Sum Mixed Byte Modulo */ + case 38: /* Vector Multiply-Sum Unsigned Halfword Modulo */ + case 40: /* Vector Multiply-Sum Signed Halfword Modulo */ + case 46: /* Vector Multiply-Add Single-Precision */ + case 47: /* Vector Negative Multiply-Subtract Single-Precision */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_vr0_regnum + PPC_VRT (insn)); + return 0; + + case 48: /* Multiply-Add High Doubleword */ + case 49: /* Multiply-Add High Doubleword Unsigned */ + case 51: /* Multiply-Add Low Doubleword */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + return 0; + } + + switch ((ext & 0x1ff)) + { + case 385: + if (vra != 0 /* Decimal Convert To Signed Quadword */ + && vra != 2 /* Decimal Convert From Signed Quadword */ + && vra != 4 /* Decimal Convert To Zoned */ + && vra != 5 /* Decimal Convert To National */ + && vra != 6 /* Decimal Convert From Zoned */ + && vra != 7 /* Decimal Convert From National */ + && vra != 31) /* Decimal Set Sign */ + break; + /* Fall through. */ + /* 5.16 Decimal Integer Arithmetic Instructions */ + case 1: /* Decimal Add Modulo */ + case 65: /* Decimal Subtract Modulo */ + + case 193: /* Decimal Shift */ + case 129: /* Decimal Unsigned Shift */ + case 449: /* Decimal Shift and Round */ + + case 257: /* Decimal Truncate */ + case 321: /* Decimal Unsigned Truncate */ + + /* Bit-21 should be set. */ + if (!PPC_BIT (insn, 21)) + break; + + record_full_arch_list_add_reg (regcache, + tdep->ppc_vr0_regnum + PPC_VRT (insn)); + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + return 0; + } + + /* Bit-21 is used for RC */ + switch (ext & 0x3ff) + { + case 6: /* Vector Compare Equal To Unsigned Byte */ + case 70: /* Vector Compare Equal To Unsigned Halfword */ + case 134: /* Vector Compare Equal To Unsigned Word */ + case 199: /* Vector Compare Equal To Unsigned Doubleword */ + case 774: /* Vector Compare Greater Than Signed Byte */ + case 838: /* Vector Compare Greater Than Signed Halfword */ + case 902: /* Vector Compare Greater Than Signed Word */ + case 967: /* Vector Compare Greater Than Signed Doubleword */ + case 518: /* Vector Compare Greater Than Unsigned Byte */ + case 646: /* Vector Compare Greater Than Unsigned Word */ + case 582: /* Vector Compare Greater Than Unsigned Halfword */ + case 711: /* Vector Compare Greater Than Unsigned Doubleword */ + case 966: /* Vector Compare Bounds Single-Precision */ + case 198: /* Vector Compare Equal To Single-Precision */ + case 454: /* Vector Compare Greater Than or Equal To Single-Precision */ + case 710: /* Vector Compare Greater Than Single-Precision */ + case 7: /* Vector Compare Not Equal Byte */ + case 71: /* Vector Compare Not Equal Halfword */ + case 135: /* Vector Compare Not Equal Word */ + case 263: /* Vector Compare Not Equal or Zero Byte */ + case 327: /* Vector Compare Not Equal or Zero Halfword */ + case 391: /* Vector Compare Not Equal or Zero Word */ + if (PPC_Rc (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, + tdep->ppc_vr0_regnum + PPC_VRT (insn)); + return 0; + } + + if (ext == 1538) + { + switch (vra) + { + case 0: /* Vector Count Leading Zero Least-Significant Bits + Byte */ + case 1: /* Vector Count Trailing Zero Least-Significant Bits + Byte */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + return 0; + + case 6: /* Vector Negate Word */ + case 7: /* Vector Negate Doubleword */ + case 8: /* Vector Parity Byte Word */ + case 9: /* Vector Parity Byte Doubleword */ + case 10: /* Vector Parity Byte Quadword */ + case 16: /* Vector Extend Sign Byte To Word */ + case 17: /* Vector Extend Sign Halfword To Word */ + case 24: /* Vector Extend Sign Byte To Doubleword */ + case 25: /* Vector Extend Sign Halfword To Doubleword */ + case 26: /* Vector Extend Sign Word To Doubleword */ + case 28: /* Vector Count Trailing Zeros Byte */ + case 29: /* Vector Count Trailing Zeros Halfword */ + case 30: /* Vector Count Trailing Zeros Word */ + case 31: /* Vector Count Trailing Zeros Doubleword */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_vr0_regnum + PPC_VRT (insn)); + return 0; + } + } + + switch (ext) + { + case 142: /* Vector Pack Unsigned Halfword Unsigned Saturate */ + case 206: /* Vector Pack Unsigned Word Unsigned Saturate */ + case 270: /* Vector Pack Signed Halfword Unsigned Saturate */ + case 334: /* Vector Pack Signed Word Unsigned Saturate */ + case 398: /* Vector Pack Signed Halfword Signed Saturate */ + case 462: /* Vector Pack Signed Word Signed Saturate */ + case 1230: /* Vector Pack Unsigned Doubleword Unsigned Saturate */ + case 1358: /* Vector Pack Signed Doubleword Unsigned Saturate */ + case 1486: /* Vector Pack Signed Doubleword Signed Saturate */ + case 512: /* Vector Add Unsigned Byte Saturate */ + case 576: /* Vector Add Unsigned Halfword Saturate */ + case 640: /* Vector Add Unsigned Word Saturate */ + case 768: /* Vector Add Signed Byte Saturate */ + case 832: /* Vector Add Signed Halfword Saturate */ + case 896: /* Vector Add Signed Word Saturate */ + case 1536: /* Vector Subtract Unsigned Byte Saturate */ + case 1600: /* Vector Subtract Unsigned Halfword Saturate */ + case 1664: /* Vector Subtract Unsigned Word Saturate */ + case 1792: /* Vector Subtract Signed Byte Saturate */ + case 1856: /* Vector Subtract Signed Halfword Saturate */ + case 1920: /* Vector Subtract Signed Word Saturate */ + + case 1544: /* Vector Sum across Quarter Unsigned Byte Saturate */ + case 1800: /* Vector Sum across Quarter Signed Byte Saturate */ + case 1608: /* Vector Sum across Quarter Signed Halfword Saturate */ + case 1672: /* Vector Sum across Half Signed Word Saturate */ + case 1928: /* Vector Sum across Signed Word Saturate */ + case 970: /* Vector Convert To Signed Fixed-Point Word Saturate */ + case 906: /* Vector Convert To Unsigned Fixed-Point Word Saturate */ + record_full_arch_list_add_reg (regcache, PPC_VSCR_REGNUM); + /* FALL-THROUGH */ + case 12: /* Vector Merge High Byte */ + case 14: /* Vector Pack Unsigned Halfword Unsigned Modulo */ + case 76: /* Vector Merge High Halfword */ + case 78: /* Vector Pack Unsigned Word Unsigned Modulo */ + case 140: /* Vector Merge High Word */ + case 268: /* Vector Merge Low Byte */ + case 332: /* Vector Merge Low Halfword */ + case 396: /* Vector Merge Low Word */ + case 526: /* Vector Unpack High Signed Byte */ + case 590: /* Vector Unpack High Signed Halfword */ + case 654: /* Vector Unpack Low Signed Byte */ + case 718: /* Vector Unpack Low Signed Halfword */ + case 782: /* Vector Pack Pixel */ + case 846: /* Vector Unpack High Pixel */ + case 974: /* Vector Unpack Low Pixel */ + case 1102: /* Vector Pack Unsigned Doubleword Unsigned Modulo */ + case 1614: /* Vector Unpack High Signed Word */ + case 1676: /* Vector Merge Odd Word */ + case 1742: /* Vector Unpack Low Signed Word */ + case 1932: /* Vector Merge Even Word */ + case 524: /* Vector Splat Byte */ + case 588: /* Vector Splat Halfword */ + case 652: /* Vector Splat Word */ + case 780: /* Vector Splat Immediate Signed Byte */ + case 844: /* Vector Splat Immediate Signed Halfword */ + case 908: /* Vector Splat Immediate Signed Word */ + case 452: /* Vector Shift Left */ + case 708: /* Vector Shift Right */ + case 1036: /* Vector Shift Left by Octet */ + case 1100: /* Vector Shift Right by Octet */ + case 0: /* Vector Add Unsigned Byte Modulo */ + case 64: /* Vector Add Unsigned Halfword Modulo */ + case 128: /* Vector Add Unsigned Word Modulo */ + case 192: /* Vector Add Unsigned Doubleword Modulo */ + case 256: /* Vector Add Unsigned Quadword Modulo */ + case 320: /* Vector Add & write Carry Unsigned Quadword */ + case 384: /* Vector Add and Write Carry-Out Unsigned Word */ + case 8: /* Vector Multiply Odd Unsigned Byte */ + case 72: /* Vector Multiply Odd Unsigned Halfword */ + case 136: /* Vector Multiply Odd Unsigned Word */ + case 264: /* Vector Multiply Odd Signed Byte */ + case 328: /* Vector Multiply Odd Signed Halfword */ + case 392: /* Vector Multiply Odd Signed Word */ + case 520: /* Vector Multiply Even Unsigned Byte */ + case 584: /* Vector Multiply Even Unsigned Halfword */ + case 648: /* Vector Multiply Even Unsigned Word */ + case 776: /* Vector Multiply Even Signed Byte */ + case 840: /* Vector Multiply Even Signed Halfword */ + case 904: /* Vector Multiply Even Signed Word */ + case 137: /* Vector Multiply Unsigned Word Modulo */ + case 1024: /* Vector Subtract Unsigned Byte Modulo */ + case 1088: /* Vector Subtract Unsigned Halfword Modulo */ + case 1152: /* Vector Subtract Unsigned Word Modulo */ + case 1216: /* Vector Subtract Unsigned Doubleword Modulo */ + case 1280: /* Vector Subtract Unsigned Quadword Modulo */ + case 1344: /* Vector Subtract & write Carry Unsigned Quadword */ + case 1408: /* Vector Subtract and Write Carry-Out Unsigned Word */ + case 1282: /* Vector Average Signed Byte */ + case 1346: /* Vector Average Signed Halfword */ + case 1410: /* Vector Average Signed Word */ + case 1026: /* Vector Average Unsigned Byte */ + case 1090: /* Vector Average Unsigned Halfword */ + case 1154: /* Vector Average Unsigned Word */ + case 258: /* Vector Maximum Signed Byte */ + case 322: /* Vector Maximum Signed Halfword */ + case 386: /* Vector Maximum Signed Word */ + case 450: /* Vector Maximum Signed Doubleword */ + case 2: /* Vector Maximum Unsigned Byte */ + case 66: /* Vector Maximum Unsigned Halfword */ + case 130: /* Vector Maximum Unsigned Word */ + case 194: /* Vector Maximum Unsigned Doubleword */ + case 770: /* Vector Minimum Signed Byte */ + case 834: /* Vector Minimum Signed Halfword */ + case 898: /* Vector Minimum Signed Word */ + case 962: /* Vector Minimum Signed Doubleword */ + case 514: /* Vector Minimum Unsigned Byte */ + case 578: /* Vector Minimum Unsigned Halfword */ + case 642: /* Vector Minimum Unsigned Word */ + case 706: /* Vector Minimum Unsigned Doubleword */ + case 1028: /* Vector Logical AND */ + case 1668: /* Vector Logical Equivalent */ + case 1092: /* Vector Logical AND with Complement */ + case 1412: /* Vector Logical NAND */ + case 1348: /* Vector Logical OR with Complement */ + case 1156: /* Vector Logical OR */ + case 1284: /* Vector Logical NOR */ + case 1220: /* Vector Logical XOR */ + case 4: /* Vector Rotate Left Byte */ + case 132: /* Vector Rotate Left Word VX-form */ + case 68: /* Vector Rotate Left Halfword */ + case 196: /* Vector Rotate Left Doubleword */ + case 260: /* Vector Shift Left Byte */ + case 388: /* Vector Shift Left Word */ + case 324: /* Vector Shift Left Halfword */ + case 1476: /* Vector Shift Left Doubleword */ + case 516: /* Vector Shift Right Byte */ + case 644: /* Vector Shift Right Word */ + case 580: /* Vector Shift Right Halfword */ + case 1732: /* Vector Shift Right Doubleword */ + case 772: /* Vector Shift Right Algebraic Byte */ + case 900: /* Vector Shift Right Algebraic Word */ + case 836: /* Vector Shift Right Algebraic Halfword */ + case 964: /* Vector Shift Right Algebraic Doubleword */ + case 10: /* Vector Add Single-Precision */ + case 74: /* Vector Subtract Single-Precision */ + case 1034: /* Vector Maximum Single-Precision */ + case 1098: /* Vector Minimum Single-Precision */ + case 842: /* Vector Convert From Signed Fixed-Point Word */ + case 778: /* Vector Convert From Unsigned Fixed-Point Word */ + case 714: /* Vector Round to Single-Precision Integer toward -Infinity */ + case 522: /* Vector Round to Single-Precision Integer Nearest */ + case 650: /* Vector Round to Single-Precision Integer toward +Infinity */ + case 586: /* Vector Round to Single-Precision Integer toward Zero */ + case 394: /* Vector 2 Raised to the Exponent Estimate Floating-Point */ + case 458: /* Vector Log Base 2 Estimate Floating-Point */ + case 266: /* Vector Reciprocal Estimate Single-Precision */ + case 330: /* Vector Reciprocal Square Root Estimate Single-Precision */ + case 1288: /* Vector AES Cipher */ + case 1289: /* Vector AES Cipher Last */ + case 1352: /* Vector AES Inverse Cipher */ + case 1353: /* Vector AES Inverse Cipher Last */ + case 1480: /* Vector AES SubBytes */ + case 1730: /* Vector SHA-512 Sigma Doubleword */ + case 1666: /* Vector SHA-256 Sigma Word */ + case 1032: /* Vector Polynomial Multiply-Sum Byte */ + case 1160: /* Vector Polynomial Multiply-Sum Word */ + case 1096: /* Vector Polynomial Multiply-Sum Halfword */ + case 1224: /* Vector Polynomial Multiply-Sum Doubleword */ + case 1292: /* Vector Gather Bits by Bytes by Doubleword */ + case 1794: /* Vector Count Leading Zeros Byte */ + case 1858: /* Vector Count Leading Zeros Halfword */ + case 1922: /* Vector Count Leading Zeros Word */ + case 1986: /* Vector Count Leading Zeros Doubleword */ + case 1795: /* Vector Population Count Byte */ + case 1859: /* Vector Population Count Halfword */ + case 1923: /* Vector Population Count Word */ + case 1987: /* Vector Population Count Doubleword */ + case 1356: /* Vector Bit Permute Quadword */ + case 1484: /* Vector Bit Permute Doubleword */ + case 513: /* Vector Multiply-by-10 Unsigned Quadword */ + case 1: /* Vector Multiply-by-10 & write Carry Unsigned + Quadword */ + case 577: /* Vector Multiply-by-10 Extended Unsigned Quadword */ + case 65: /* Vector Multiply-by-10 Extended & write Carry + Unsigned Quadword */ + case 1027: /* Vector Absolute Difference Unsigned Byte */ + case 1091: /* Vector Absolute Difference Unsigned Halfword */ + case 1155: /* Vector Absolute Difference Unsigned Word */ + case 1796: /* Vector Shift Right Variable */ + case 1860: /* Vector Shift Left Variable */ + case 133: /* Vector Rotate Left Word then Mask Insert */ + case 197: /* Vector Rotate Left Doubleword then Mask Insert */ + case 389: /* Vector Rotate Left Word then AND with Mask */ + case 453: /* Vector Rotate Left Doubleword then AND with Mask */ + case 525: /* Vector Extract Unsigned Byte */ + case 589: /* Vector Extract Unsigned Halfword */ + case 653: /* Vector Extract Unsigned Word */ + case 717: /* Vector Extract Doubleword */ + case 781: /* Vector Insert Byte */ + case 845: /* Vector Insert Halfword */ + case 909: /* Vector Insert Word */ + case 973: /* Vector Insert Doubleword */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_vr0_regnum + PPC_VRT (insn)); + return 0; + + case 1549: /* Vector Extract Unsigned Byte Left-Indexed */ + case 1613: /* Vector Extract Unsigned Halfword Left-Indexed */ + case 1677: /* Vector Extract Unsigned Word Left-Indexed */ + case 1805: /* Vector Extract Unsigned Byte Right-Indexed */ + case 1869: /* Vector Extract Unsigned Halfword Right-Indexed */ + case 1933: /* Vector Extract Unsigned Word Right-Indexed */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + return 0; + + case 1604: /* Move To Vector Status and Control Register */ + record_full_arch_list_add_reg (regcache, PPC_VSCR_REGNUM); + return 0; + case 1540: /* Move From Vector Status and Control Register */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_vr0_regnum + PPC_VRT (insn)); + return 0; + case 833: /* Decimal Copy Sign */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_vr0_regnum + PPC_VRT (insn)); + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + return 0; + } + + fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record %08x " + "at %s, 4-%d.\n", insn, paddress (gdbarch, addr), ext); + return -1; +} + +/* Parse and record instructions of primary opcode-19 at ADDR. + Return 0 if successful. */ + +static int +ppc_process_record_op19 (struct gdbarch *gdbarch, struct regcache *regcache, + CORE_ADDR addr, uint32_t insn) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int ext = PPC_EXTOP (insn); + + switch (ext & 0x01f) + { + case 2: /* Add PC Immediate Shifted */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + return 0; + } + + switch (ext) + { + case 0: /* Move Condition Register Field */ + case 33: /* Condition Register NOR */ + case 129: /* Condition Register AND with Complement */ + case 193: /* Condition Register XOR */ + case 225: /* Condition Register NAND */ + case 257: /* Condition Register AND */ + case 289: /* Condition Register Equivalent */ + case 417: /* Condition Register OR with Complement */ + case 449: /* Condition Register OR */ + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + return 0; + + case 16: /* Branch Conditional */ + case 560: /* Branch Conditional to Branch Target Address Register */ + if ((PPC_BO (insn) & 0x4) == 0) + record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum); + /* FALL-THROUGH */ + case 528: /* Branch Conditional to Count Register */ + if (PPC_LK (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum); + return 0; + + case 150: /* Instruction Synchronize */ + /* Do nothing. */ + return 0; + } + + fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record %08x " + "at %s, 19-%d.\n", insn, paddress (gdbarch, addr), ext); + return -1; +} + +/* Parse and record instructions of primary opcode-31 at ADDR. + Return 0 if successful. */ + +static int +ppc_process_record_op31 (struct gdbarch *gdbarch, struct regcache *regcache, + CORE_ADDR addr, uint32_t insn) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int ext = PPC_EXTOP (insn); + int tmp, nr, nb, i; + CORE_ADDR at_dcsz, ea = 0; + ULONGEST rb, ra, xer; + int size = 0; + + /* These instructions have OE bit. */ + switch (ext & 0x1ff) + { + /* These write RT and XER. Update CR if RC is set. */ + case 8: /* Subtract from carrying */ + case 10: /* Add carrying */ + case 136: /* Subtract from extended */ + case 138: /* Add extended */ + case 200: /* Subtract from zero extended */ + case 202: /* Add to zero extended */ + case 232: /* Subtract from minus one extended */ + case 234: /* Add to minus one extended */ + /* CA is always altered, but SO/OV are only altered when OE=1. + In any case, XER is always altered. */ + record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + return 0; + + /* These write RT. Update CR if RC is set and update XER if OE is set. */ + case 40: /* Subtract from */ + case 104: /* Negate */ + case 233: /* Multiply low doubleword */ + case 235: /* Multiply low word */ + case 266: /* Add */ + case 393: /* Divide Doubleword Extended Unsigned */ + case 395: /* Divide Word Extended Unsigned */ + case 425: /* Divide Doubleword Extended */ + case 427: /* Divide Word Extended */ + case 457: /* Divide Doubleword Unsigned */ + case 459: /* Divide Word Unsigned */ + case 489: /* Divide Doubleword */ + case 491: /* Divide Word */ + if (PPC_OE (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); + /* FALL-THROUGH */ + case 9: /* Multiply High Doubleword Unsigned */ + case 11: /* Multiply High Word Unsigned */ + case 73: /* Multiply High Doubleword */ + case 75: /* Multiply High Word */ + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + return 0; + } + + if ((ext & 0x1f) == 15) + { + /* Integer Select. bit[16:20] is used for BC. */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + return 0; + } + + if ((ext & 0xff) == 170) + { + /* Add Extended using alternate carry bits */ + record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + return 0; + } + + switch (ext) + { + case 78: /* Determine Leftmost Zero Byte */ + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + return 0; + + /* These only write RT. */ + case 19: /* Move from condition register */ + /* Move From One Condition Register Field */ + case 74: /* Add and Generate Sixes */ + case 74 | 0x200: /* Add and Generate Sixes (bit-21 dont-care) */ + case 302: /* Move From Branch History Rolling Buffer */ + case 339: /* Move From Special Purpose Register */ + case 371: /* Move From Time Base [Phased-Out] */ + case 309: /* Load Doubleword Monitored Indexed */ + case 128: /* Set Boolean */ + case 755: /* Deliver A Random Number */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + return 0; + + /* These only write to RA. */ + case 51: /* Move From VSR Doubleword */ + case 115: /* Move From VSR Word and Zero */ + case 122: /* Population count bytes */ + case 378: /* Population count words */ + case 506: /* Population count doublewords */ + case 154: /* Parity Word */ + case 186: /* Parity Doubleword */ + case 252: /* Bit Permute Doubleword */ + case 282: /* Convert Declets To Binary Coded Decimal */ + case 314: /* Convert Binary Coded Decimal To Declets */ + case 508: /* Compare bytes */ + case 307: /* Move From VSR Lower Doubleword */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn)); + return 0; + + /* These write CR and optional RA. */ + case 792: /* Shift Right Algebraic Word */ + case 794: /* Shift Right Algebraic Doubleword */ + case 824: /* Shift Right Algebraic Word Immediate */ + case 826: /* Shift Right Algebraic Doubleword Immediate (413) */ + case 826 | 1: /* Shift Right Algebraic Doubleword Immediate (413) */ + record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn)); + /* FALL-THROUGH */ + case 0: /* Compare */ + case 32: /* Compare logical */ + case 144: /* Move To Condition Register Fields */ + /* Move To One Condition Register Field */ + case 192: /* Compare Ranged Byte */ + case 224: /* Compare Equal Byte */ + case 576: /* Move XER to CR Extended */ + case 902: /* Paste (should always fail due to single-stepping and + the memory location might not be accessible, so + record only CR) */ + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + return 0; + + /* These write to RT. Update RA if 'update indexed.' */ + case 53: /* Load Doubleword with Update Indexed */ + case 119: /* Load Byte and Zero with Update Indexed */ + case 311: /* Load Halfword and Zero with Update Indexed */ + case 55: /* Load Word and Zero with Update Indexed */ + case 375: /* Load Halfword Algebraic with Update Indexed */ + case 373: /* Load Word Algebraic with Update Indexed */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn)); + /* FALL-THROUGH */ + case 21: /* Load Doubleword Indexed */ + case 52: /* Load Byte And Reserve Indexed */ + case 116: /* Load Halfword And Reserve Indexed */ + case 20: /* Load Word And Reserve Indexed */ + case 84: /* Load Doubleword And Reserve Indexed */ + case 87: /* Load Byte and Zero Indexed */ + case 279: /* Load Halfword and Zero Indexed */ + case 23: /* Load Word and Zero Indexed */ + case 343: /* Load Halfword Algebraic Indexed */ + case 341: /* Load Word Algebraic Indexed */ + case 790: /* Load Halfword Byte-Reverse Indexed */ + case 534: /* Load Word Byte-Reverse Indexed */ + case 532: /* Load Doubleword Byte-Reverse Indexed */ + case 582: /* Load Word Atomic */ + case 614: /* Load Doubleword Atomic */ + case 265: /* Modulo Unsigned Doubleword */ + case 777: /* Modulo Signed Doubleword */ + case 267: /* Modulo Unsigned Word */ + case 779: /* Modulo Signed Word */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + return 0; + + case 597: /* Load String Word Immediate */ + case 533: /* Load String Word Indexed */ + if (ext == 597) + { + nr = PPC_NB (insn); + if (nr == 0) + nr = 32; + } + else + { + regcache_raw_read_unsigned (regcache, tdep->ppc_xer_regnum, &xer); + nr = PPC_XER_NB (xer); + } + + nr = (nr + 3) >> 2; + + /* If n=0, the contents of register RT are undefined. */ + if (nr == 0) + nr = 1; + + for (i = 0; i < nr; i++) + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + + ((PPC_RT (insn) + i) & 0x1f)); + return 0; + + case 276: /* Load Quadword And Reserve Indexed */ + tmp = tdep->ppc_gp0_regnum + (PPC_RT (insn) & ~1); + record_full_arch_list_add_reg (regcache, tmp); + record_full_arch_list_add_reg (regcache, tmp + 1); + return 0; + + /* These write VRT. */ + case 6: /* Load Vector for Shift Left Indexed */ + case 38: /* Load Vector for Shift Right Indexed */ + case 7: /* Load Vector Element Byte Indexed */ + case 39: /* Load Vector Element Halfword Indexed */ + case 71: /* Load Vector Element Word Indexed */ + case 103: /* Load Vector Indexed */ + case 359: /* Load Vector Indexed LRU */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_vr0_regnum + PPC_VRT (insn)); + return 0; + + /* These write FRT. Update RA if 'update indexed.' */ + case 567: /* Load Floating-Point Single with Update Indexed */ + case 631: /* Load Floating-Point Double with Update Indexed */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn)); + /* FALL-THROUGH */ + case 535: /* Load Floating-Point Single Indexed */ + case 599: /* Load Floating-Point Double Indexed */ + case 855: /* Load Floating-Point as Integer Word Algebraic Indexed */ + case 887: /* Load Floating-Point as Integer Word and Zero Indexed */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_fp0_regnum + PPC_FRT (insn)); + return 0; + + case 791: /* Load Floating-Point Double Pair Indexed */ + tmp = tdep->ppc_fp0_regnum + (PPC_FRT (insn) & ~1); + record_full_arch_list_add_reg (regcache, tmp); + record_full_arch_list_add_reg (regcache, tmp + 1); + return 0; + + case 179: /* Move To VSR Doubleword */ + case 211: /* Move To VSR Word Algebraic */ + case 243: /* Move To VSR Word and Zero */ + case 588: /* Load VSX Scalar Doubleword Indexed */ + case 524: /* Load VSX Scalar Single-Precision Indexed */ + case 76: /* Load VSX Scalar as Integer Word Algebraic Indexed */ + case 12: /* Load VSX Scalar as Integer Word and Zero Indexed */ + case 844: /* Load VSX Vector Doubleword*2 Indexed */ + case 332: /* Load VSX Vector Doubleword & Splat Indexed */ + case 780: /* Load VSX Vector Word*4 Indexed */ + case 268: /* Load VSX Vector Indexed */ + case 364: /* Load VSX Vector Word & Splat Indexed */ + case 812: /* Load VSX Vector Halfword*8 Indexed */ + case 876: /* Load VSX Vector Byte*16 Indexed */ + case 269: /* Load VSX Vector with Length */ + case 301: /* Load VSX Vector Left-justified with Length */ + case 781: /* Load VSX Scalar as Integer Byte & Zero Indexed */ + case 813: /* Load VSX Scalar as Integer Halfword & Zero Indexed */ + case 403: /* Move To VSR Word & Splat */ + case 435: /* Move To VSR Double Doubleword */ + ppc_record_vsr (regcache, tdep, PPC_XT (insn)); + return 0; + + /* These write RA. Update CR if RC is set. */ + case 24: /* Shift Left Word */ + case 26: /* Count Leading Zeros Word */ + case 27: /* Shift Left Doubleword */ + case 28: /* AND */ + case 58: /* Count Leading Zeros Doubleword */ + case 60: /* AND with Complement */ + case 124: /* NOR */ + case 284: /* Equivalent */ + case 316: /* XOR */ + case 476: /* NAND */ + case 412: /* OR with Complement */ + case 444: /* OR */ + case 536: /* Shift Right Word */ + case 539: /* Shift Right Doubleword */ + case 922: /* Extend Sign Halfword */ + case 954: /* Extend Sign Byte */ + case 986: /* Extend Sign Word */ + case 538: /* Count Trailing Zeros Word */ + case 570: /* Count Trailing Zeros Doubleword */ + case 890: /* Extend-Sign Word and Shift Left Immediate (445) */ + case 890 | 1: /* Extend-Sign Word and Shift Left Immediate (445) */ + + if (ext == 444 && tdep->ppc_ppr_regnum >= 0 + && (PPC_RS (insn) == PPC_RA (insn)) + && (PPC_RA (insn) == PPC_RB (insn)) + && !PPC_RC (insn)) + { + /* or Rx,Rx,Rx alters PRI in PPR. */ + record_full_arch_list_add_reg (regcache, tdep->ppc_ppr_regnum); + return 0; + } + + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn)); + return 0; + + /* Store memory. */ + case 181: /* Store Doubleword with Update Indexed */ + case 183: /* Store Word with Update Indexed */ + case 247: /* Store Byte with Update Indexed */ + case 439: /* Store Half Word with Update Indexed */ + case 695: /* Store Floating-Point Single with Update Indexed */ + case 759: /* Store Floating-Point Double with Update Indexed */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn)); + /* FALL-THROUGH */ + case 135: /* Store Vector Element Byte Indexed */ + case 167: /* Store Vector Element Halfword Indexed */ + case 199: /* Store Vector Element Word Indexed */ + case 231: /* Store Vector Indexed */ + case 487: /* Store Vector Indexed LRU */ + case 716: /* Store VSX Scalar Doubleword Indexed */ + case 140: /* Store VSX Scalar as Integer Word Indexed */ + case 652: /* Store VSX Scalar Single-Precision Indexed */ + case 972: /* Store VSX Vector Doubleword*2 Indexed */ + case 908: /* Store VSX Vector Word*4 Indexed */ + case 149: /* Store Doubleword Indexed */ + case 151: /* Store Word Indexed */ + case 215: /* Store Byte Indexed */ + case 407: /* Store Half Word Indexed */ + case 694: /* Store Byte Conditional Indexed */ + case 726: /* Store Halfword Conditional Indexed */ + case 150: /* Store Word Conditional Indexed */ + case 214: /* Store Doubleword Conditional Indexed */ + case 182: /* Store Quadword Conditional Indexed */ + case 662: /* Store Word Byte-Reverse Indexed */ + case 918: /* Store Halfword Byte-Reverse Indexed */ + case 660: /* Store Doubleword Byte-Reverse Indexed */ + case 663: /* Store Floating-Point Single Indexed */ + case 727: /* Store Floating-Point Double Indexed */ + case 919: /* Store Floating-Point Double Pair Indexed */ + case 983: /* Store Floating-Point as Integer Word Indexed */ + case 396: /* Store VSX Vector Indexed */ + case 940: /* Store VSX Vector Halfword*8 Indexed */ + case 1004: /* Store VSX Vector Byte*16 Indexed */ + case 909: /* Store VSX Scalar as Integer Byte Indexed */ + case 941: /* Store VSX Scalar as Integer Halfword Indexed */ + if (ext == 694 || ext == 726 || ext == 150 || ext == 214 || ext == 182) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + + ra = 0; + if (PPC_RA (insn) != 0) + regcache_raw_read_unsigned (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn), &ra); + regcache_raw_read_unsigned (regcache, + tdep->ppc_gp0_regnum + PPC_RB (insn), &rb); + ea = ra + rb; + + switch (ext) + { + case 183: /* Store Word with Update Indexed */ + case 199: /* Store Vector Element Word Indexed */ + case 140: /* Store VSX Scalar as Integer Word Indexed */ + case 652: /* Store VSX Scalar Single-Precision Indexed */ + case 151: /* Store Word Indexed */ + case 150: /* Store Word Conditional Indexed */ + case 662: /* Store Word Byte-Reverse Indexed */ + case 663: /* Store Floating-Point Single Indexed */ + case 695: /* Store Floating-Point Single with Update Indexed */ + case 983: /* Store Floating-Point as Integer Word Indexed */ + size = 4; + break; + case 247: /* Store Byte with Update Indexed */ + case 135: /* Store Vector Element Byte Indexed */ + case 215: /* Store Byte Indexed */ + case 694: /* Store Byte Conditional Indexed */ + case 909: /* Store VSX Scalar as Integer Byte Indexed */ + size = 1; + break; + case 439: /* Store Halfword with Update Indexed */ + case 167: /* Store Vector Element Halfword Indexed */ + case 407: /* Store Halfword Indexed */ + case 726: /* Store Halfword Conditional Indexed */ + case 918: /* Store Halfword Byte-Reverse Indexed */ + case 941: /* Store VSX Scalar as Integer Halfword Indexed */ + size = 2; + break; + case 181: /* Store Doubleword with Update Indexed */ + case 716: /* Store VSX Scalar Doubleword Indexed */ + case 149: /* Store Doubleword Indexed */ + case 214: /* Store Doubleword Conditional Indexed */ + case 660: /* Store Doubleword Byte-Reverse Indexed */ + case 727: /* Store Floating-Point Double Indexed */ + case 759: /* Store Floating-Point Double with Update Indexed */ + size = 8; + break; + case 972: /* Store VSX Vector Doubleword*2 Indexed */ + case 908: /* Store VSX Vector Word*4 Indexed */ + case 182: /* Store Quadword Conditional Indexed */ + case 231: /* Store Vector Indexed */ + case 487: /* Store Vector Indexed LRU */ + case 919: /* Store Floating-Point Double Pair Indexed */ + case 396: /* Store VSX Vector Indexed */ + case 940: /* Store VSX Vector Halfword*8 Indexed */ + case 1004: /* Store VSX Vector Byte*16 Indexed */ + size = 16; + break; + default: + gdb_assert (0); + } + + /* Align address for Store Vector instructions. */ + switch (ext) + { + case 167: /* Store Vector Element Halfword Indexed */ + addr = addr & ~0x1ULL; + break; + + case 199: /* Store Vector Element Word Indexed */ + addr = addr & ~0x3ULL; + break; + + case 231: /* Store Vector Indexed */ + case 487: /* Store Vector Indexed LRU */ + addr = addr & ~0xfULL; + break; + } + + record_full_arch_list_add_mem (addr, size); + return 0; + + case 397: /* Store VSX Vector with Length */ + case 429: /* Store VSX Vector Left-justified with Length */ + ra = 0; + if (PPC_RA (insn) != 0) + regcache_raw_read_unsigned (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn), &ra); + ea = ra; + regcache_raw_read_unsigned (regcache, + tdep->ppc_gp0_regnum + PPC_RB (insn), &rb); + /* Store up to 16 bytes. */ + nb = (rb & 0xff) > 16 ? 16 : (rb & 0xff); + if (nb > 0) + record_full_arch_list_add_mem (ea, nb); + return 0; + + case 710: /* Store Word Atomic */ + case 742: /* Store Doubleword Atomic */ + ra = 0; + if (PPC_RA (insn) != 0) + regcache_raw_read_unsigned (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn), &ra); + ea = ra; + switch (ext) + { + case 710: /* Store Word Atomic */ + size = 8; + break; + case 742: /* Store Doubleword Atomic */ + size = 16; + break; + default: + gdb_assert (0); + } + record_full_arch_list_add_mem (ea, size); + return 0; + + case 725: /* Store String Word Immediate */ + ra = 0; + if (PPC_RA (insn) != 0) + regcache_raw_read_unsigned (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn), &ra); + ea += ra; + + nb = PPC_NB (insn); + if (nb == 0) + nb = 32; + + record_full_arch_list_add_mem (ea, nb); + + return 0; + + case 661: /* Store String Word Indexed */ + ra = 0; + if (PPC_RA (insn) != 0) + regcache_raw_read_unsigned (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn), &ra); + ea += ra; + + regcache_raw_read_unsigned (regcache, tdep->ppc_xer_regnum, &xer); + nb = PPC_XER_NB (xer); + + if (nb != 0) + { + regcache_raw_read_unsigned (regcache, + tdep->ppc_gp0_regnum + PPC_RB (insn), + &rb); + ea += rb; + record_full_arch_list_add_mem (ea, nb); + } + + return 0; + + case 467: /* Move To Special Purpose Register */ + switch (PPC_SPR (insn)) + { + case 1: /* XER */ + record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); + return 0; + case 3: /* DSCR */ + if (tdep->ppc_dscr_regnum >= 0) + record_full_arch_list_add_reg (regcache, tdep->ppc_dscr_regnum); + return 0; + case 8: /* LR */ + record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum); + return 0; + case 9: /* CTR */ + record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum); + return 0; + case 256: /* VRSAVE */ + record_full_arch_list_add_reg (regcache, tdep->ppc_vrsave_regnum); + return 0; + case 815: /* TAR */ + if (tdep->ppc_tar_regnum >= 0) + record_full_arch_list_add_reg (regcache, tdep->ppc_tar_regnum); + return 0; + case 896: + case 898: /* PPR */ + if (tdep->ppc_ppr_regnum >= 0) + record_full_arch_list_add_reg (regcache, tdep->ppc_ppr_regnum); + return 0; + } + + goto UNKNOWN_OP; + + case 147: /* Move To Split Little Endian */ + record_full_arch_list_add_reg (regcache, tdep->ppc_ps_regnum); + return 0; + + case 512: /* Move to Condition Register from XER */ + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); + return 0; + + case 4: /* Trap Word */ + case 68: /* Trap Doubleword */ + case 430: /* Clear BHRB */ + case 598: /* Synchronize */ + case 62: /* Wait for Interrupt */ + case 30: /* Wait */ + case 22: /* Instruction Cache Block Touch */ + case 854: /* Enforce In-order Execution of I/O */ + case 246: /* Data Cache Block Touch for Store */ + case 54: /* Data Cache Block Store */ + case 86: /* Data Cache Block Flush */ + case 278: /* Data Cache Block Touch */ + case 758: /* Data Cache Block Allocate */ + case 982: /* Instruction Cache Block Invalidate */ + case 774: /* Copy */ + case 838: /* CP_Abort */ + return 0; + + case 654: /* Transaction Begin */ + case 686: /* Transaction End */ + case 750: /* Transaction Suspend or Resume */ + case 782: /* Transaction Abort Word Conditional */ + case 814: /* Transaction Abort Doubleword Conditional */ + case 846: /* Transaction Abort Word Conditional Immediate */ + case 878: /* Transaction Abort Doubleword Conditional Immediate */ + case 910: /* Transaction Abort */ + record_full_arch_list_add_reg (regcache, tdep->ppc_ps_regnum); + /* FALL-THROUGH */ + case 718: /* Transaction Check */ + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + return 0; + + case 1014: /* Data Cache Block set to Zero */ + if (target_auxv_search (current_top_target (), AT_DCACHEBSIZE, &at_dcsz) <= 0 + || at_dcsz == 0) + at_dcsz = 128; /* Assume 128-byte cache line size (POWER8) */ + + ra = 0; + if (PPC_RA (insn) != 0) + regcache_raw_read_unsigned (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn), &ra); + regcache_raw_read_unsigned (regcache, + tdep->ppc_gp0_regnum + PPC_RB (insn), &rb); + ea = (ra + rb) & ~((ULONGEST) (at_dcsz - 1)); + record_full_arch_list_add_mem (ea, at_dcsz); + return 0; + } + +UNKNOWN_OP: + fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record %08x " + "at %s, 31-%d.\n", insn, paddress (gdbarch, addr), ext); + return -1; +} + +/* Parse and record instructions of primary opcode-59 at ADDR. + Return 0 if successful. */ + +static int +ppc_process_record_op59 (struct gdbarch *gdbarch, struct regcache *regcache, + CORE_ADDR addr, uint32_t insn) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int ext = PPC_EXTOP (insn); + + switch (ext & 0x1f) + { + case 18: /* Floating Divide */ + case 20: /* Floating Subtract */ + case 21: /* Floating Add */ + case 22: /* Floating Square Root */ + case 24: /* Floating Reciprocal Estimate */ + case 25: /* Floating Multiply */ + case 26: /* Floating Reciprocal Square Root Estimate */ + case 28: /* Floating Multiply-Subtract */ + case 29: /* Floating Multiply-Add */ + case 30: /* Floating Negative Multiply-Subtract */ + case 31: /* Floating Negative Multiply-Add */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_fp0_regnum + PPC_FRT (insn)); + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + + return 0; + } + + switch (ext) + { + case 2: /* DFP Add */ + case 3: /* DFP Quantize */ + case 34: /* DFP Multiply */ + case 35: /* DFP Reround */ + case 67: /* DFP Quantize Immediate */ + case 99: /* DFP Round To FP Integer With Inexact */ + case 227: /* DFP Round To FP Integer Without Inexact */ + case 258: /* DFP Convert To DFP Long! */ + case 290: /* DFP Convert To Fixed */ + case 514: /* DFP Subtract */ + case 546: /* DFP Divide */ + case 770: /* DFP Round To DFP Short! */ + case 802: /* DFP Convert From Fixed */ + case 834: /* DFP Encode BCD To DPD */ + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, + tdep->ppc_fp0_regnum + PPC_FRT (insn)); + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + return 0; + + case 130: /* DFP Compare Ordered */ + case 162: /* DFP Test Exponent */ + case 194: /* DFP Test Data Class */ + case 226: /* DFP Test Data Group */ + case 642: /* DFP Compare Unordered */ + case 674: /* DFP Test Significance */ + case 675: /* DFP Test Significance Immediate */ + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + return 0; + + case 66: /* DFP Shift Significand Left Immediate */ + case 98: /* DFP Shift Significand Right Immediate */ + case 322: /* DFP Decode DPD To BCD */ + case 354: /* DFP Extract Biased Exponent */ + case 866: /* DFP Insert Biased Exponent */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_fp0_regnum + PPC_FRT (insn)); + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + return 0; + + case 846: /* Floating Convert From Integer Doubleword Single */ + case 974: /* Floating Convert From Integer Doubleword Unsigned + Single */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_fp0_regnum + PPC_FRT (insn)); + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + + return 0; + } + + fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record %08x " + "at %s, 59-%d.\n", insn, paddress (gdbarch, addr), ext); + return -1; +} + +/* Parse and record instructions of primary opcode-60 at ADDR. + Return 0 if successful. */ + +static int +ppc_process_record_op60 (struct gdbarch *gdbarch, struct regcache *regcache, + CORE_ADDR addr, uint32_t insn) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int ext = PPC_EXTOP (insn); + + switch (ext >> 2) + { + case 0: /* VSX Scalar Add Single-Precision */ + case 32: /* VSX Scalar Add Double-Precision */ + case 24: /* VSX Scalar Divide Single-Precision */ + case 56: /* VSX Scalar Divide Double-Precision */ + case 176: /* VSX Scalar Copy Sign Double-Precision */ + case 33: /* VSX Scalar Multiply-Add Double-Precision */ + case 41: /* ditto */ + case 1: /* VSX Scalar Multiply-Add Single-Precision */ + case 9: /* ditto */ + case 160: /* VSX Scalar Maximum Double-Precision */ + case 168: /* VSX Scalar Minimum Double-Precision */ + case 49: /* VSX Scalar Multiply-Subtract Double-Precision */ + case 57: /* ditto */ + case 17: /* VSX Scalar Multiply-Subtract Single-Precision */ + case 25: /* ditto */ + case 48: /* VSX Scalar Multiply Double-Precision */ + case 16: /* VSX Scalar Multiply Single-Precision */ + case 161: /* VSX Scalar Negative Multiply-Add Double-Precision */ + case 169: /* ditto */ + case 129: /* VSX Scalar Negative Multiply-Add Single-Precision */ + case 137: /* ditto */ + case 177: /* VSX Scalar Negative Multiply-Subtract Double-Precision */ + case 185: /* ditto */ + case 145: /* VSX Scalar Negative Multiply-Subtract Single-Precision */ + case 153: /* ditto */ + case 40: /* VSX Scalar Subtract Double-Precision */ + case 8: /* VSX Scalar Subtract Single-Precision */ + case 96: /* VSX Vector Add Double-Precision */ + case 64: /* VSX Vector Add Single-Precision */ + case 120: /* VSX Vector Divide Double-Precision */ + case 88: /* VSX Vector Divide Single-Precision */ + case 97: /* VSX Vector Multiply-Add Double-Precision */ + case 105: /* ditto */ + case 65: /* VSX Vector Multiply-Add Single-Precision */ + case 73: /* ditto */ + case 224: /* VSX Vector Maximum Double-Precision */ + case 192: /* VSX Vector Maximum Single-Precision */ + case 232: /* VSX Vector Minimum Double-Precision */ + case 200: /* VSX Vector Minimum Single-Precision */ + case 113: /* VSX Vector Multiply-Subtract Double-Precision */ + case 121: /* ditto */ + case 81: /* VSX Vector Multiply-Subtract Single-Precision */ + case 89: /* ditto */ + case 112: /* VSX Vector Multiply Double-Precision */ + case 80: /* VSX Vector Multiply Single-Precision */ + case 225: /* VSX Vector Negative Multiply-Add Double-Precision */ + case 233: /* ditto */ + case 193: /* VSX Vector Negative Multiply-Add Single-Precision */ + case 201: /* ditto */ + case 241: /* VSX Vector Negative Multiply-Subtract Double-Precision */ + case 249: /* ditto */ + case 209: /* VSX Vector Negative Multiply-Subtract Single-Precision */ + case 217: /* ditto */ + case 104: /* VSX Vector Subtract Double-Precision */ + case 72: /* VSX Vector Subtract Single-Precision */ + case 128: /* VSX Scalar Maximum Type-C Double-Precision */ + case 136: /* VSX Scalar Minimum Type-C Double-Precision */ + case 144: /* VSX Scalar Maximum Type-J Double-Precision */ + case 152: /* VSX Scalar Minimum Type-J Double-Precision */ + case 3: /* VSX Scalar Compare Equal Double-Precision */ + case 11: /* VSX Scalar Compare Greater Than Double-Precision */ + case 19: /* VSX Scalar Compare Greater Than or Equal + Double-Precision */ + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + /* FALL-THROUGH */ + case 240: /* VSX Vector Copy Sign Double-Precision */ + case 208: /* VSX Vector Copy Sign Single-Precision */ + case 130: /* VSX Logical AND */ + case 138: /* VSX Logical AND with Complement */ + case 186: /* VSX Logical Equivalence */ + case 178: /* VSX Logical NAND */ + case 170: /* VSX Logical OR with Complement */ + case 162: /* VSX Logical NOR */ + case 146: /* VSX Logical OR */ + case 154: /* VSX Logical XOR */ + case 18: /* VSX Merge High Word */ + case 50: /* VSX Merge Low Word */ + case 10: /* VSX Permute Doubleword Immediate (DM=0) */ + case 10 | 0x20: /* VSX Permute Doubleword Immediate (DM=1) */ + case 10 | 0x40: /* VSX Permute Doubleword Immediate (DM=2) */ + case 10 | 0x60: /* VSX Permute Doubleword Immediate (DM=3) */ + case 2: /* VSX Shift Left Double by Word Immediate (SHW=0) */ + case 2 | 0x20: /* VSX Shift Left Double by Word Immediate (SHW=1) */ + case 2 | 0x40: /* VSX Shift Left Double by Word Immediate (SHW=2) */ + case 2 | 0x60: /* VSX Shift Left Double by Word Immediate (SHW=3) */ + case 216: /* VSX Vector Insert Exponent Single-Precision */ + case 248: /* VSX Vector Insert Exponent Double-Precision */ + case 26: /* VSX Vector Permute */ + case 58: /* VSX Vector Permute Right-indexed */ + case 213: /* VSX Vector Test Data Class Single-Precision (DC=0) */ + case 213 | 0x8: /* VSX Vector Test Data Class Single-Precision (DC=1) */ + case 245: /* VSX Vector Test Data Class Double-Precision (DC=0) */ + case 245 | 0x8: /* VSX Vector Test Data Class Double-Precision (DC=1) */ + ppc_record_vsr (regcache, tdep, PPC_XT (insn)); + return 0; + + case 61: /* VSX Scalar Test for software Divide Double-Precision */ + case 125: /* VSX Vector Test for software Divide Double-Precision */ + case 93: /* VSX Vector Test for software Divide Single-Precision */ + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + return 0; + + case 35: /* VSX Scalar Compare Unordered Double-Precision */ + case 43: /* VSX Scalar Compare Ordered Double-Precision */ + case 59: /* VSX Scalar Compare Exponents Double-Precision */ + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + return 0; + } + + switch ((ext >> 2) & 0x7f) /* Mask out Rc-bit. */ + { + case 99: /* VSX Vector Compare Equal To Double-Precision */ + case 67: /* VSX Vector Compare Equal To Single-Precision */ + case 115: /* VSX Vector Compare Greater Than or + Equal To Double-Precision */ + case 83: /* VSX Vector Compare Greater Than or + Equal To Single-Precision */ + case 107: /* VSX Vector Compare Greater Than Double-Precision */ + case 75: /* VSX Vector Compare Greater Than Single-Precision */ + if (PPC_Rc (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + ppc_record_vsr (regcache, tdep, PPC_XT (insn)); + return 0; + } + + switch (ext >> 1) + { + case 265: /* VSX Scalar round Double-Precision to + Single-Precision and Convert to + Single-Precision format */ + case 344: /* VSX Scalar truncate Double-Precision to + Integer and Convert to Signed Integer + Doubleword format with Saturate */ + case 88: /* VSX Scalar truncate Double-Precision to + Integer and Convert to Signed Integer Word + Format with Saturate */ + case 328: /* VSX Scalar truncate Double-Precision integer + and Convert to Unsigned Integer Doubleword + Format with Saturate */ + case 72: /* VSX Scalar truncate Double-Precision to + Integer and Convert to Unsigned Integer Word + Format with Saturate */ + case 329: /* VSX Scalar Convert Single-Precision to + Double-Precision format */ + case 376: /* VSX Scalar Convert Signed Integer + Doubleword to floating-point format and + Round to Double-Precision format */ + case 312: /* VSX Scalar Convert Signed Integer + Doubleword to floating-point format and + round to Single-Precision */ + case 360: /* VSX Scalar Convert Unsigned Integer + Doubleword to floating-point format and + Round to Double-Precision format */ + case 296: /* VSX Scalar Convert Unsigned Integer + Doubleword to floating-point format and + Round to Single-Precision */ + case 73: /* VSX Scalar Round to Double-Precision Integer + Using Round to Nearest Away */ + case 107: /* VSX Scalar Round to Double-Precision Integer + Exact using Current rounding mode */ + case 121: /* VSX Scalar Round to Double-Precision Integer + Using Round toward -Infinity */ + case 105: /* VSX Scalar Round to Double-Precision Integer + Using Round toward +Infinity */ + case 89: /* VSX Scalar Round to Double-Precision Integer + Using Round toward Zero */ + case 90: /* VSX Scalar Reciprocal Estimate Double-Precision */ + case 26: /* VSX Scalar Reciprocal Estimate Single-Precision */ + case 281: /* VSX Scalar Round to Single-Precision */ + case 74: /* VSX Scalar Reciprocal Square Root Estimate + Double-Precision */ + case 10: /* VSX Scalar Reciprocal Square Root Estimate + Single-Precision */ + case 75: /* VSX Scalar Square Root Double-Precision */ + case 11: /* VSX Scalar Square Root Single-Precision */ + case 393: /* VSX Vector round Double-Precision to + Single-Precision and Convert to + Single-Precision format */ + case 472: /* VSX Vector truncate Double-Precision to + Integer and Convert to Signed Integer + Doubleword format with Saturate */ + case 216: /* VSX Vector truncate Double-Precision to + Integer and Convert to Signed Integer Word + Format with Saturate */ + case 456: /* VSX Vector truncate Double-Precision to + Integer and Convert to Unsigned Integer + Doubleword format with Saturate */ + case 200: /* VSX Vector truncate Double-Precision to + Integer and Convert to Unsigned Integer Word + Format with Saturate */ + case 457: /* VSX Vector Convert Single-Precision to + Double-Precision format */ + case 408: /* VSX Vector truncate Single-Precision to + Integer and Convert to Signed Integer + Doubleword format with Saturate */ + case 152: /* VSX Vector truncate Single-Precision to + Integer and Convert to Signed Integer Word + Format with Saturate */ + case 392: /* VSX Vector truncate Single-Precision to + Integer and Convert to Unsigned Integer + Doubleword format with Saturate */ + case 136: /* VSX Vector truncate Single-Precision to + Integer and Convert to Unsigned Integer Word + Format with Saturate */ + case 504: /* VSX Vector Convert and round Signed Integer + Doubleword to Double-Precision format */ + case 440: /* VSX Vector Convert and round Signed Integer + Doubleword to Single-Precision format */ + case 248: /* VSX Vector Convert Signed Integer Word to + Double-Precision format */ + case 184: /* VSX Vector Convert and round Signed Integer + Word to Single-Precision format */ + case 488: /* VSX Vector Convert and round Unsigned + Integer Doubleword to Double-Precision format */ + case 424: /* VSX Vector Convert and round Unsigned + Integer Doubleword to Single-Precision format */ + case 232: /* VSX Vector Convert and round Unsigned + Integer Word to Double-Precision format */ + case 168: /* VSX Vector Convert and round Unsigned + Integer Word to Single-Precision format */ + case 201: /* VSX Vector Round to Double-Precision + Integer using round to Nearest Away */ + case 235: /* VSX Vector Round to Double-Precision + Integer Exact using Current rounding mode */ + case 249: /* VSX Vector Round to Double-Precision + Integer using round toward -Infinity */ + case 233: /* VSX Vector Round to Double-Precision + Integer using round toward +Infinity */ + case 217: /* VSX Vector Round to Double-Precision + Integer using round toward Zero */ + case 218: /* VSX Vector Reciprocal Estimate Double-Precision */ + case 154: /* VSX Vector Reciprocal Estimate Single-Precision */ + case 137: /* VSX Vector Round to Single-Precision Integer + Using Round to Nearest Away */ + case 171: /* VSX Vector Round to Single-Precision Integer + Exact Using Current rounding mode */ + case 185: /* VSX Vector Round to Single-Precision Integer + Using Round toward -Infinity */ + case 169: /* VSX Vector Round to Single-Precision Integer + Using Round toward +Infinity */ + case 153: /* VSX Vector Round to Single-Precision Integer + Using round toward Zero */ + case 202: /* VSX Vector Reciprocal Square Root Estimate + Double-Precision */ + case 138: /* VSX Vector Reciprocal Square Root Estimate + Single-Precision */ + case 203: /* VSX Vector Square Root Double-Precision */ + case 139: /* VSX Vector Square Root Single-Precision */ + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + /* FALL-THROUGH */ + case 345: /* VSX Scalar Absolute Value Double-Precision */ + case 267: /* VSX Scalar Convert Scalar Single-Precision to + Vector Single-Precision format Non-signalling */ + case 331: /* VSX Scalar Convert Single-Precision to + Double-Precision format Non-signalling */ + case 361: /* VSX Scalar Negative Absolute Value Double-Precision */ + case 377: /* VSX Scalar Negate Double-Precision */ + case 473: /* VSX Vector Absolute Value Double-Precision */ + case 409: /* VSX Vector Absolute Value Single-Precision */ + case 489: /* VSX Vector Negative Absolute Value Double-Precision */ + case 425: /* VSX Vector Negative Absolute Value Single-Precision */ + case 505: /* VSX Vector Negate Double-Precision */ + case 441: /* VSX Vector Negate Single-Precision */ + case 164: /* VSX Splat Word */ + case 165: /* VSX Vector Extract Unsigned Word */ + case 181: /* VSX Vector Insert Word */ + ppc_record_vsr (regcache, tdep, PPC_XT (insn)); + return 0; + + case 298: /* VSX Scalar Test Data Class Single-Precision */ + case 362: /* VSX Scalar Test Data Class Double-Precision */ + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + /* FALL-THROUGH */ + case 106: /* VSX Scalar Test for software Square Root + Double-Precision */ + case 234: /* VSX Vector Test for software Square Root + Double-Precision */ + case 170: /* VSX Vector Test for software Square Root + Single-Precision */ + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + return 0; + + case 347: + switch (PPC_FIELD (insn, 11, 5)) + { + case 0: /* VSX Scalar Extract Exponent Double-Precision */ + case 1: /* VSX Scalar Extract Significand Double-Precision */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + return 0; + case 16: /* VSX Scalar Convert Half-Precision format to + Double-Precision format */ + case 17: /* VSX Scalar round & Convert Double-Precision format + to Half-Precision format */ + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + ppc_record_vsr (regcache, tdep, PPC_XT (insn)); + return 0; + } + break; + + case 475: + switch (PPC_FIELD (insn, 11, 5)) + { + case 24: /* VSX Vector Convert Half-Precision format to + Single-Precision format */ + case 25: /* VSX Vector round and Convert Single-Precision format + to Half-Precision format */ + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + /* FALL-THROUGH */ + case 0: /* VSX Vector Extract Exponent Double-Precision */ + case 1: /* VSX Vector Extract Significand Double-Precision */ + case 7: /* VSX Vector Byte-Reverse Halfword */ + case 8: /* VSX Vector Extract Exponent Single-Precision */ + case 9: /* VSX Vector Extract Significand Single-Precision */ + case 15: /* VSX Vector Byte-Reverse Word */ + case 23: /* VSX Vector Byte-Reverse Doubleword */ + case 31: /* VSX Vector Byte-Reverse Quadword */ + ppc_record_vsr (regcache, tdep, PPC_XT (insn)); + return 0; + } + break; + } + + switch (ext) + { + case 360: /* VSX Vector Splat Immediate Byte */ + if (PPC_FIELD (insn, 11, 2) == 0) + { + ppc_record_vsr (regcache, tdep, PPC_XT (insn)); + return 0; + } + break; + case 918: /* VSX Scalar Insert Exponent Double-Precision */ + ppc_record_vsr (regcache, tdep, PPC_XT (insn)); + return 0; + } + + if (((ext >> 3) & 0x3) == 3) /* VSX Select */ + { + ppc_record_vsr (regcache, tdep, PPC_XT (insn)); + return 0; + } + + fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record %08x " + "at %s, 60-%d.\n", insn, paddress (gdbarch, addr), ext); + return -1; +} + +/* Parse and record instructions of primary opcode-61 at ADDR. + Return 0 if successful. */ + +static int +ppc_process_record_op61 (struct gdbarch *gdbarch, struct regcache *regcache, + CORE_ADDR addr, uint32_t insn) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + ULONGEST ea = 0; + int size; + + switch (insn & 0x3) + { + case 0: /* Store Floating-Point Double Pair */ + case 2: /* Store VSX Scalar Doubleword */ + case 3: /* Store VSX Scalar Single */ + if (PPC_RA (insn) != 0) + regcache_raw_read_unsigned (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn), + &ea); + ea += PPC_DS (insn) << 2; + switch (insn & 0x3) + { + case 0: /* Store Floating-Point Double Pair */ + size = 16; + break; + case 2: /* Store VSX Scalar Doubleword */ + size = 8; + break; + case 3: /* Store VSX Scalar Single */ + size = 4; + break; + default: + gdb_assert (0); + } + record_full_arch_list_add_mem (ea, size); + return 0; + } + + switch (insn & 0x7) + { + case 1: /* Load VSX Vector */ + ppc_record_vsr (regcache, tdep, PPC_XT (insn)); + return 0; + case 5: /* Store VSX Vector */ + if (PPC_RA (insn) != 0) + regcache_raw_read_unsigned (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn), + &ea); + ea += PPC_DQ (insn) << 4; + record_full_arch_list_add_mem (ea, 16); + return 0; + } + + fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record %08x " + "at %s.\n", insn, paddress (gdbarch, addr)); + return -1; +} + +/* Parse and record instructions of primary opcode-63 at ADDR. + Return 0 if successful. */ + +static int +ppc_process_record_op63 (struct gdbarch *gdbarch, struct regcache *regcache, + CORE_ADDR addr, uint32_t insn) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + int ext = PPC_EXTOP (insn); + int tmp; + + switch (ext & 0x1f) + { + case 18: /* Floating Divide */ + case 20: /* Floating Subtract */ + case 21: /* Floating Add */ + case 22: /* Floating Square Root */ + case 24: /* Floating Reciprocal Estimate */ + case 25: /* Floating Multiply */ + case 26: /* Floating Reciprocal Square Root Estimate */ + case 28: /* Floating Multiply-Subtract */ + case 29: /* Floating Multiply-Add */ + case 30: /* Floating Negative Multiply-Subtract */ + case 31: /* Floating Negative Multiply-Add */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_fp0_regnum + PPC_FRT (insn)); + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + return 0; + + case 23: /* Floating Select */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_fp0_regnum + PPC_FRT (insn)); + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + return 0; + } + + switch (ext & 0xff) + { + case 5: /* VSX Scalar Round to Quad-Precision Integer */ + case 37: /* VSX Scalar Round Quad-Precision to Double-Extended + Precision */ + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + ppc_record_vsr (regcache, tdep, PPC_VRT (insn) + 32); + return 0; + } + + switch (ext) + { + case 2: /* DFP Add Quad */ + case 3: /* DFP Quantize Quad */ + case 34: /* DFP Multiply Quad */ + case 35: /* DFP Reround Quad */ + case 67: /* DFP Quantize Immediate Quad */ + case 99: /* DFP Round To FP Integer With Inexact Quad */ + case 227: /* DFP Round To FP Integer Without Inexact Quad */ + case 258: /* DFP Convert To DFP Extended Quad */ + case 514: /* DFP Subtract Quad */ + case 546: /* DFP Divide Quad */ + case 770: /* DFP Round To DFP Long Quad */ + case 802: /* DFP Convert From Fixed Quad */ + case 834: /* DFP Encode BCD To DPD Quad */ + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + tmp = tdep->ppc_fp0_regnum + (PPC_FRT (insn) & ~1); + record_full_arch_list_add_reg (regcache, tmp); + record_full_arch_list_add_reg (regcache, tmp + 1); + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + return 0; + + case 130: /* DFP Compare Ordered Quad */ + case 162: /* DFP Test Exponent Quad */ + case 194: /* DFP Test Data Class Quad */ + case 226: /* DFP Test Data Group Quad */ + case 642: /* DFP Compare Unordered Quad */ + case 674: /* DFP Test Significance Quad */ + case 675: /* DFP Test Significance Immediate Quad */ + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + return 0; + + case 66: /* DFP Shift Significand Left Immediate Quad */ + case 98: /* DFP Shift Significand Right Immediate Quad */ + case 322: /* DFP Decode DPD To BCD Quad */ + case 866: /* DFP Insert Biased Exponent Quad */ + tmp = tdep->ppc_fp0_regnum + (PPC_FRT (insn) & ~1); + record_full_arch_list_add_reg (regcache, tmp); + record_full_arch_list_add_reg (regcache, tmp + 1); + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + return 0; + + case 290: /* DFP Convert To Fixed Quad */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_fp0_regnum + PPC_FRT (insn)); + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + return 0; + + case 354: /* DFP Extract Biased Exponent Quad */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_fp0_regnum + PPC_FRT (insn)); + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + return 0; + + case 12: /* Floating Round to Single-Precision */ + case 14: /* Floating Convert To Integer Word */ + case 15: /* Floating Convert To Integer Word + with round toward Zero */ + case 142: /* Floating Convert To Integer Word Unsigned */ + case 143: /* Floating Convert To Integer Word Unsigned + with round toward Zero */ + case 392: /* Floating Round to Integer Nearest */ + case 424: /* Floating Round to Integer Toward Zero */ + case 456: /* Floating Round to Integer Plus */ + case 488: /* Floating Round to Integer Minus */ + case 814: /* Floating Convert To Integer Doubleword */ + case 815: /* Floating Convert To Integer Doubleword + with round toward Zero */ + case 846: /* Floating Convert From Integer Doubleword */ + case 942: /* Floating Convert To Integer Doubleword Unsigned */ + case 943: /* Floating Convert To Integer Doubleword Unsigned + with round toward Zero */ + case 974: /* Floating Convert From Integer Doubleword Unsigned */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_fp0_regnum + PPC_FRT (insn)); + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + return 0; + + case 583: + switch (PPC_FIELD (insn, 11, 5)) + { + case 1: /* Move From FPSCR & Clear Enables */ + case 20: /* Move From FPSCR Control & set DRN */ + case 21: /* Move From FPSCR Control & set DRN Immediate */ + case 22: /* Move From FPSCR Control & set RN */ + case 23: /* Move From FPSCR Control & set RN Immediate */ + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + /* Fall through. */ + case 0: /* Move From FPSCR */ + case 24: /* Move From FPSCR Lightweight */ + if (PPC_FIELD (insn, 11, 5) == 0 && PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, + tdep->ppc_fp0_regnum + + PPC_FRT (insn)); + return 0; + } + break; + + case 8: /* Floating Copy Sign */ + case 40: /* Floating Negate */ + case 72: /* Floating Move Register */ + case 136: /* Floating Negative Absolute Value */ + case 264: /* Floating Absolute Value */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_fp0_regnum + PPC_FRT (insn)); + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + return 0; + + case 838: /* Floating Merge Odd Word */ + case 966: /* Floating Merge Even Word */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_fp0_regnum + PPC_FRT (insn)); + return 0; + + case 38: /* Move To FPSCR Bit 1 */ + case 70: /* Move To FPSCR Bit 0 */ + case 134: /* Move To FPSCR Field Immediate */ + case 711: /* Move To FPSCR Fields */ + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + return 0; + + case 0: /* Floating Compare Unordered */ + case 32: /* Floating Compare Ordered */ + case 64: /* Move to Condition Register from FPSCR */ + case 132: /* VSX Scalar Compare Ordered Quad-Precision */ + case 164: /* VSX Scalar Compare Exponents Quad-Precision */ + case 644: /* VSX Scalar Compare Unordered Quad-Precision */ + case 708: /* VSX Scalar Test Data Class Quad-Precision */ + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + /* FALL-THROUGH */ + case 128: /* Floating Test for software Divide */ + case 160: /* Floating Test for software Square Root */ + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + return 0; + + case 4: /* VSX Scalar Add Quad-Precision */ + case 36: /* VSX Scalar Multiply Quad-Precision */ + case 388: /* VSX Scalar Multiply-Add Quad-Precision */ + case 420: /* VSX Scalar Multiply-Subtract Quad-Precision */ + case 452: /* VSX Scalar Negative Multiply-Add Quad-Precision */ + case 484: /* VSX Scalar Negative Multiply-Subtract + Quad-Precision */ + case 516: /* VSX Scalar Subtract Quad-Precision */ + case 548: /* VSX Scalar Divide Quad-Precision */ + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + /* FALL-THROUGH */ + case 100: /* VSX Scalar Copy Sign Quad-Precision */ + case 868: /* VSX Scalar Insert Exponent Quad-Precision */ + ppc_record_vsr (regcache, tdep, PPC_VRT (insn) + 32); + return 0; + + case 804: + switch (PPC_FIELD (insn, 11, 5)) + { + case 27: /* VSX Scalar Square Root Quad-Precision */ + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + /* FALL-THROUGH */ + case 0: /* VSX Scalar Absolute Quad-Precision */ + case 2: /* VSX Scalar Extract Exponent Quad-Precision */ + case 8: /* VSX Scalar Negative Absolute Quad-Precision */ + case 16: /* VSX Scalar Negate Quad-Precision */ + case 18: /* VSX Scalar Extract Significand Quad-Precision */ + ppc_record_vsr (regcache, tdep, PPC_VRT (insn) + 32); + return 0; + } + break; + + case 836: + switch (PPC_FIELD (insn, 11, 5)) + { + case 1: /* VSX Scalar truncate & Convert Quad-Precision format + to Unsigned Word format */ + case 2: /* VSX Scalar Convert Unsigned Doubleword format to + Quad-Precision format */ + case 9: /* VSX Scalar truncate & Convert Quad-Precision format + to Signed Word format */ + case 10: /* VSX Scalar Convert Signed Doubleword format to + Quad-Precision format */ + case 17: /* VSX Scalar truncate & Convert Quad-Precision format + to Unsigned Doubleword format */ + case 20: /* VSX Scalar round & Convert Quad-Precision format to + Double-Precision format */ + case 22: /* VSX Scalar Convert Double-Precision format to + Quad-Precision format */ + case 25: /* VSX Scalar truncate & Convert Quad-Precision format + to Signed Doubleword format */ + record_full_arch_list_add_reg (regcache, tdep->ppc_fpscr_regnum); + ppc_record_vsr (regcache, tdep, PPC_VRT (insn) + 32); + return 0; + } + } + + fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record %08x " + "at %s, 63-%d.\n", insn, paddress (gdbarch, addr), ext); + return -1; +} + +/* Parse the current instruction and record the values of the registers and + memory that will be changed in current instruction to "record_arch_list". + Return -1 if something wrong. */ + +int +ppc_process_record (struct gdbarch *gdbarch, struct regcache *regcache, + CORE_ADDR addr) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + uint32_t insn; + int op6, tmp, i; + + insn = read_memory_unsigned_integer (addr, 4, byte_order); + op6 = PPC_OP6 (insn); + + switch (op6) + { + case 2: /* Trap Doubleword Immediate */ + case 3: /* Trap Word Immediate */ + /* Do nothing. */ + break; + + case 4: + if (ppc_process_record_op4 (gdbarch, regcache, addr, insn) != 0) + return -1; + break; + + case 17: /* System call */ + if (PPC_LEV (insn) != 0) + goto UNKNOWN_OP; + + if (tdep->ppc_syscall_record != NULL) + { + if (tdep->ppc_syscall_record (regcache) != 0) + return -1; + } + else + { + printf_unfiltered (_("no syscall record support\n")); + return -1; + } + break; + + case 7: /* Multiply Low Immediate */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + break; + + case 8: /* Subtract From Immediate Carrying */ + record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + break; + + case 10: /* Compare Logical Immediate */ + case 11: /* Compare Immediate */ + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + break; + + case 13: /* Add Immediate Carrying and Record */ + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + /* FALL-THROUGH */ + case 12: /* Add Immediate Carrying */ + record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum); + /* FALL-THROUGH */ + case 14: /* Add Immediate */ + case 15: /* Add Immediate Shifted */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + break; + + case 16: /* Branch Conditional */ + if ((PPC_BO (insn) & 0x4) == 0) + record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum); + /* FALL-THROUGH */ + case 18: /* Branch */ + if (PPC_LK (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum); + break; + + case 19: + if (ppc_process_record_op19 (gdbarch, regcache, addr, insn) != 0) + return -1; + break; + + case 20: /* Rotate Left Word Immediate then Mask Insert */ + case 21: /* Rotate Left Word Immediate then AND with Mask */ + case 23: /* Rotate Left Word then AND with Mask */ + case 30: /* Rotate Left Doubleword Immediate then Clear Left */ + /* Rotate Left Doubleword Immediate then Clear Right */ + /* Rotate Left Doubleword Immediate then Clear */ + /* Rotate Left Doubleword then Clear Left */ + /* Rotate Left Doubleword then Clear Right */ + /* Rotate Left Doubleword Immediate then Mask Insert */ + if (PPC_RC (insn)) + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn)); + break; + + case 28: /* AND Immediate */ + case 29: /* AND Immediate Shifted */ + record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum); + /* FALL-THROUGH */ + case 24: /* OR Immediate */ + case 25: /* OR Immediate Shifted */ + case 26: /* XOR Immediate */ + case 27: /* XOR Immediate Shifted */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn)); + break; + + case 31: + if (ppc_process_record_op31 (gdbarch, regcache, addr, insn) != 0) + return -1; + break; + + case 33: /* Load Word and Zero with Update */ + case 35: /* Load Byte and Zero with Update */ + case 41: /* Load Halfword and Zero with Update */ + case 43: /* Load Halfword Algebraic with Update */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn)); + /* FALL-THROUGH */ + case 32: /* Load Word and Zero */ + case 34: /* Load Byte and Zero */ + case 40: /* Load Halfword and Zero */ + case 42: /* Load Halfword Algebraic */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + break; + + case 46: /* Load Multiple Word */ + for (i = PPC_RT (insn); i < 32; i++) + record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + i); + break; + + case 56: /* Load Quadword */ + tmp = tdep->ppc_gp0_regnum + (PPC_RT (insn) & ~1); + record_full_arch_list_add_reg (regcache, tmp); + record_full_arch_list_add_reg (regcache, tmp + 1); + break; + + case 49: /* Load Floating-Point Single with Update */ + case 51: /* Load Floating-Point Double with Update */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn)); + /* FALL-THROUGH */ + case 48: /* Load Floating-Point Single */ + case 50: /* Load Floating-Point Double */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_fp0_regnum + PPC_FRT (insn)); + break; + + case 47: /* Store Multiple Word */ + { + ULONGEST iaddr = 0; + + if (PPC_RA (insn) != 0) + regcache_raw_read_unsigned (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn), + &iaddr); + + iaddr += PPC_D (insn); + record_full_arch_list_add_mem (iaddr, 4 * (32 - PPC_RS (insn))); + } + break; + + case 37: /* Store Word with Update */ + case 39: /* Store Byte with Update */ + case 45: /* Store Halfword with Update */ + case 53: /* Store Floating-Point Single with Update */ + case 55: /* Store Floating-Point Double with Update */ + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn)); + /* FALL-THROUGH */ + case 36: /* Store Word */ + case 38: /* Store Byte */ + case 44: /* Store Halfword */ + case 52: /* Store Floating-Point Single */ + case 54: /* Store Floating-Point Double */ + { + ULONGEST iaddr = 0; + int size = -1; + + if (PPC_RA (insn) != 0) + regcache_raw_read_unsigned (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn), + &iaddr); + iaddr += PPC_D (insn); + + if (op6 == 36 || op6 == 37 || op6 == 52 || op6 == 53) + size = 4; + else if (op6 == 54 || op6 == 55) + size = 8; + else if (op6 == 44 || op6 == 45) + size = 2; + else if (op6 == 38 || op6 == 39) + size = 1; + else + gdb_assert (0); + + record_full_arch_list_add_mem (iaddr, size); + } + break; + + case 57: + switch (insn & 0x3) + { + case 0: /* Load Floating-Point Double Pair */ + tmp = tdep->ppc_fp0_regnum + (PPC_RT (insn) & ~1); + record_full_arch_list_add_reg (regcache, tmp); + record_full_arch_list_add_reg (regcache, tmp + 1); + break; + case 2: /* Load VSX Scalar Doubleword */ + case 3: /* Load VSX Scalar Single */ + ppc_record_vsr (regcache, tdep, PPC_VRT (insn) + 32); + break; + default: + goto UNKNOWN_OP; + } + break; + + case 58: /* Load Doubleword */ + /* Load Doubleword with Update */ + /* Load Word Algebraic */ + if (PPC_FIELD (insn, 30, 2) > 2) + goto UNKNOWN_OP; + + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RT (insn)); + if (PPC_BIT (insn, 31)) + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn)); + break; + + case 59: + if (ppc_process_record_op59 (gdbarch, regcache, addr, insn) != 0) + return -1; + break; + + case 60: + if (ppc_process_record_op60 (gdbarch, regcache, addr, insn) != 0) + return -1; + break; + + case 61: + if (ppc_process_record_op61 (gdbarch, regcache, addr, insn) != 0) + return -1; + break; + + case 62: /* Store Doubleword */ + /* Store Doubleword with Update */ + /* Store Quadword with Update */ + { + ULONGEST iaddr = 0; + int size; + int sub2 = PPC_FIELD (insn, 30, 2); + + if (sub2 > 2) + goto UNKNOWN_OP; + + if (PPC_RA (insn) != 0) + regcache_raw_read_unsigned (regcache, + tdep->ppc_gp0_regnum + PPC_RA (insn), + &iaddr); + + size = (sub2 == 2) ? 16 : 8; - /* Deal with ALTIVEC registers, if supported. */ - if (tdep->ppc_vr0_regnum > 0 && tdep->ppc_vrsave_regnum > 0) - { - /* Call-saved Altivec registers. */ - if ((regnum >= tdep->ppc_vr0_regnum + 20 - && regnum <= tdep->ppc_vr0_regnum + 31) - || regnum == tdep->ppc_vrsave_regnum) - reg->how = DWARF2_FRAME_REG_SAME_VALUE; + iaddr += PPC_DS (insn) << 2; + record_full_arch_list_add_mem (iaddr, size); - /* Call-clobbered Altivec registers. */ - if ((regnum >= tdep->ppc_vr0_regnum - && regnum <= tdep->ppc_vr0_regnum + 19)) - reg->how = DWARF2_FRAME_REG_UNDEFINED; + if (op6 == 62 && sub2 == 1) + record_full_arch_list_add_reg (regcache, + tdep->ppc_gp0_regnum + + PPC_RA (insn)); + + break; + } + + case 63: + if (ppc_process_record_op63 (gdbarch, regcache, addr, insn) != 0) + return -1; + break; + + default: +UNKNOWN_OP: + fprintf_unfiltered (gdb_stdlog, "Warning: Don't know how to record %08x " + "at %s, %d.\n", insn, paddress (gdbarch, addr), op6); + return -1; } - /* Handle PC register and Stack Pointer correctly. */ - if (regnum == gdbarch_pc_regnum (gdbarch)) - reg->how = DWARF2_FRAME_REG_RA; - else if (regnum == gdbarch_sp_regnum (gdbarch)) - reg->how = DWARF2_FRAME_REG_CFA; + if (record_full_arch_list_add_reg (regcache, PPC_PC_REGNUM)) + return -1; + if (record_full_arch_list_add_end ()) + return -1; + return 0; } - /* Initialize the current architecture based on INFO. If possible, re-use an architecture from ARCHES, which is a list of architectures already created during this debugging session. @@ -3261,16 +6125,22 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) enum bfd_architecture arch; unsigned long mach; bfd abfd; - int sysv_abi; - asection *sect; enum auto_boolean soft_float_flag = powerpc_soft_float_global; int soft_float; + enum powerpc_long_double_abi long_double_abi = POWERPC_LONG_DOUBLE_AUTO; enum powerpc_vector_abi vector_abi = powerpc_vector_abi_global; - int have_fpu = 1, have_spe = 0, have_mq = 0, have_altivec = 0, have_dfp = 0; + enum powerpc_elf_abi elf_abi = POWERPC_ELF_AUTO; + int have_fpu = 0, have_spe = 0, have_mq = 0, have_altivec = 0; + int have_dfp = 0, have_vsx = 0, have_ppr = 0, have_dscr = 0; + int have_tar = 0, have_ebb = 0, have_pmu = 0, have_htm_spr = 0; + int have_htm_core = 0, have_htm_fpu = 0, have_htm_altivec = 0; + int have_htm_vsx = 0, have_htm_ppr = 0, have_htm_dscr = 0; + int have_htm_tar = 0; int tdesc_wordsize = -1; const struct target_desc *tdesc = info.target_desc; struct tdesc_arch_data *tdesc_data = NULL; int num_pseudoregs = 0; + int cur_reg; from_xcoff_exec = info.abfd && info.abfd->format == bfd_object && bfd_get_flavour (info.abfd) == bfd_target_xcoff_flavour; @@ -3278,8 +6148,6 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) from_elf_exec = info.abfd && info.abfd->format == bfd_object && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour; - sysv_abi = info.abfd && bfd_get_flavour (info.abfd) == bfd_target_elf_flavour; - /* Check word size. If INFO is from a binary file, infer it from that, else choose a likely default. */ if (from_xcoff_exec) @@ -3301,50 +6169,37 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) else { if (info.bfd_arch_info != NULL && info.bfd_arch_info->bits_per_word != 0) - wordsize = info.bfd_arch_info->bits_per_word / - info.bfd_arch_info->bits_per_byte; + wordsize = (info.bfd_arch_info->bits_per_word + / info.bfd_arch_info->bits_per_byte); else wordsize = 4; } - if (!from_xcoff_exec) - { - arch = info.bfd_arch_info->arch; - mach = info.bfd_arch_info->mach; - } - else - { - arch = bfd_arch_powerpc; - bfd_default_set_arch_mach (&abfd, arch, 0); - info.bfd_arch_info = bfd_get_arch_info (&abfd); - mach = info.bfd_arch_info->mach; - } + /* Get the architecture and machine from the BFD. */ + arch = info.bfd_arch_info->arch; + mach = info.bfd_arch_info->mach; /* For e500 executables, the apuinfo section is of help here. Such section contains the identifier and revision number of each Application-specific Processing Unit that is present on the chip. The content of the section is determined by the assembler which looks at each instruction and determines which unit (and - which version of it) can execute it. In our case we just look for - the existance of the section. */ + which version of it) can execute it. Grovel through the section + looking for relevant e500 APUs. */ - if (info.abfd) + if (bfd_uses_spe_extensions (info.abfd)) { - sect = bfd_get_section_by_name (info.abfd, ".PPC.EMB.apuinfo"); - if (sect) - { - arch = info.bfd_arch_info->arch; - mach = bfd_mach_ppc_e500; - bfd_default_set_arch_mach (&abfd, arch, mach); - info.bfd_arch_info = bfd_get_arch_info (&abfd); - } + arch = info.bfd_arch_info->arch; + mach = bfd_mach_ppc_e500; + bfd_default_set_arch_mach (&abfd, arch, mach); + info.bfd_arch_info = bfd_get_arch_info (&abfd); } /* Find a default target description which describes our register layout, if we do not already have one. */ if (! tdesc_has_registers (tdesc)) { - const struct variant *v; + const struct ppc_variant *v; /* Choose variant. */ v = find_variant_by_arch (arch, mach); @@ -3365,10 +6220,6 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) "r16", "r17", "r18", "r19", "r20", "r21", "r22", "r23", "r24", "r25", "r26", "r27", "r28", "r29", "r30", "r31" }; - static const char *const segment_regs[] = { - "sr0", "sr1", "sr2", "sr3", "sr4", "sr5", "sr6", "sr7", - "sr8", "sr9", "sr10", "sr11", "sr12", "sr13", "sr14", "sr15" - }; const struct tdesc_feature *feature; int i, valid_p; static const char *const msr_names[] = { "msr", "ps" }; @@ -3401,128 +6252,473 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) valid_p &= tdesc_numbered_register_choices (feature, tdesc_data, PPC_CTR_REGNUM, ctr_names); - if (!valid_p) + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + + have_mq = tdesc_numbered_register (feature, tdesc_data, PPC_MQ_REGNUM, + "mq"); + + tdesc_wordsize = tdesc_register_bitsize (feature, "pc") / 8; + if (wordsize == -1) + wordsize = tdesc_wordsize; + + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.power.fpu"); + if (feature != NULL) + { + static const char *const fprs[] = { + "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", + "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", + "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", + "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" + }; + valid_p = 1; + for (i = 0; i < ppc_num_fprs; i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_F0_REGNUM + i, fprs[i]); + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_FPSCR_REGNUM, "fpscr"); + + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + have_fpu = 1; + + /* The fpscr register was expanded in isa 2.05 to 64 bits + along with the addition of the decimal floating point + facility. */ + if (tdesc_register_bitsize (feature, "fpscr") > 32) + have_dfp = 1; + } + else + have_fpu = 0; + + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.power.altivec"); + if (feature != NULL) + { + static const char *const vector_regs[] = { + "vr0", "vr1", "vr2", "vr3", "vr4", "vr5", "vr6", "vr7", + "vr8", "vr9", "vr10", "vr11", "vr12", "vr13", "vr14", "vr15", + "vr16", "vr17", "vr18", "vr19", "vr20", "vr21", "vr22", "vr23", + "vr24", "vr25", "vr26", "vr27", "vr28", "vr29", "vr30", "vr31" + }; + + valid_p = 1; + for (i = 0; i < ppc_num_gprs; i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_VR0_REGNUM + i, + vector_regs[i]); + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_VSCR_REGNUM, "vscr"); + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_VRSAVE_REGNUM, "vrsave"); + + if (have_spe || !valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + have_altivec = 1; + } + else + have_altivec = 0; + + /* Check for POWER7 VSX registers support. */ + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.power.vsx"); + + if (feature != NULL) + { + static const char *const vsx_regs[] = { + "vs0h", "vs1h", "vs2h", "vs3h", "vs4h", "vs5h", + "vs6h", "vs7h", "vs8h", "vs9h", "vs10h", "vs11h", + "vs12h", "vs13h", "vs14h", "vs15h", "vs16h", "vs17h", + "vs18h", "vs19h", "vs20h", "vs21h", "vs22h", "vs23h", + "vs24h", "vs25h", "vs26h", "vs27h", "vs28h", "vs29h", + "vs30h", "vs31h" + }; + + valid_p = 1; + + for (i = 0; i < ppc_num_vshrs; i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_VSR0_UPPER_REGNUM + i, + vsx_regs[i]); + + if (!valid_p || !have_fpu || !have_altivec) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + + have_vsx = 1; + } + else + have_vsx = 0; + + /* On machines supporting the SPE APU, the general-purpose registers + are 64 bits long. There are SIMD vector instructions to treat them + as pairs of floats, but the rest of the instruction set treats them + as 32-bit registers, and only operates on their lower halves. + + In the GDB regcache, we treat their high and low halves as separate + registers. The low halves we present as the general-purpose + registers, and then we have pseudo-registers that stitch together + the upper and lower halves and present them as pseudo-registers. + + Thus, the target description is expected to supply the upper + halves separately. */ + + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.power.spe"); + if (feature != NULL) + { + static const char *const upper_spe[] = { + "ev0h", "ev1h", "ev2h", "ev3h", + "ev4h", "ev5h", "ev6h", "ev7h", + "ev8h", "ev9h", "ev10h", "ev11h", + "ev12h", "ev13h", "ev14h", "ev15h", + "ev16h", "ev17h", "ev18h", "ev19h", + "ev20h", "ev21h", "ev22h", "ev23h", + "ev24h", "ev25h", "ev26h", "ev27h", + "ev28h", "ev29h", "ev30h", "ev31h" + }; + + valid_p = 1; + for (i = 0; i < ppc_num_gprs; i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_SPE_UPPER_GP0_REGNUM + i, + upper_spe[i]); + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_SPE_ACC_REGNUM, "acc"); + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_SPE_FSCR_REGNUM, "spefscr"); + + if (have_mq || have_fpu || !valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + have_spe = 1; + } + else + have_spe = 0; + + /* Program Priority Register. */ + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.power.ppr"); + if (feature != NULL) + { + valid_p = 1; + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_PPR_REGNUM, "ppr"); + + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + have_ppr = 1; + } + else + have_ppr = 0; + + /* Data Stream Control Register. */ + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.power.dscr"); + if (feature != NULL) + { + valid_p = 1; + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_DSCR_REGNUM, "dscr"); + + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + have_dscr = 1; + } + else + have_dscr = 0; + + /* Target Address Register. */ + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.power.tar"); + if (feature != NULL) + { + valid_p = 1; + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_TAR_REGNUM, "tar"); + + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + have_tar = 1; + } + else + have_tar = 0; + + /* Event-based Branching Registers. */ + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.power.ebb"); + if (feature != NULL) + { + static const char *const ebb_regs[] = { + "bescr", "ebbhr", "ebbrr" + }; + + valid_p = 1; + for (i = 0; i < ARRAY_SIZE (ebb_regs); i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_BESCR_REGNUM + i, + ebb_regs[i]); + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + have_ebb = 1; + } + else + have_ebb = 0; + + /* Subset of the ISA 2.07 Performance Monitor Registers provided + by Linux. */ + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.power.linux.pmu"); + if (feature != NULL) + { + valid_p = 1; + + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_MMCR0_REGNUM, + "mmcr0"); + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_MMCR2_REGNUM, + "mmcr2"); + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_SIAR_REGNUM, + "siar"); + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_SDAR_REGNUM, + "sdar"); + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_SIER_REGNUM, + "sier"); + + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + have_pmu = 1; + } + else + have_pmu = 0; + + /* Hardware Transactional Memory Registers. */ + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.power.htm.spr"); + if (feature != NULL) { - tdesc_data_cleanup (tdesc_data); - return NULL; - } + static const char *const tm_spr_regs[] = { + "tfhar", "texasr", "tfiar" + }; - have_mq = tdesc_numbered_register (feature, tdesc_data, PPC_MQ_REGNUM, - "mq"); + valid_p = 1; + for (i = 0; i < ARRAY_SIZE (tm_spr_regs); i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_TFHAR_REGNUM + i, + tm_spr_regs[i]); + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } - tdesc_wordsize = tdesc_register_size (feature, "pc") / 8; - if (wordsize == -1) - wordsize = tdesc_wordsize; + have_htm_spr = 1; + } + else + have_htm_spr = 0; feature = tdesc_find_feature (tdesc, - "org.gnu.gdb.power.fpu"); + "org.gnu.gdb.power.htm.core"); if (feature != NULL) { - static const char *const fprs[] = { - "f0", "f1", "f2", "f3", "f4", "f5", "f6", "f7", - "f8", "f9", "f10", "f11", "f12", "f13", "f14", "f15", - "f16", "f17", "f18", "f19", "f20", "f21", "f22", "f23", - "f24", "f25", "f26", "f27", "f28", "f29", "f30", "f31" + static const char *const cgprs[] = { + "cr0", "cr1", "cr2", "cr3", "cr4", "cr5", "cr6", "cr7", + "cr8", "cr9", "cr10", "cr11", "cr12", "cr13", "cr14", + "cr15", "cr16", "cr17", "cr18", "cr19", "cr20", "cr21", + "cr22", "cr23", "cr24", "cr25", "cr26", "cr27", "cr28", + "cr29", "cr30", "cr31", "ccr", "cxer", "clr", "cctr" }; + valid_p = 1; - for (i = 0; i < ppc_num_fprs; i++) - valid_p &= tdesc_numbered_register (feature, tdesc_data, - PPC_F0_REGNUM + i, fprs[i]); - valid_p &= tdesc_numbered_register (feature, tdesc_data, - PPC_FPSCR_REGNUM, "fpscr"); + for (i = 0; i < ARRAY_SIZE (cgprs); i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_CR0_REGNUM + i, + cgprs[i]); if (!valid_p) { tdesc_data_cleanup (tdesc_data); return NULL; } - have_fpu = 1; + + have_htm_core = 1; } else - have_fpu = 0; - - /* The DFP pseudo-registers will be available when there are floating - point registers. */ - have_dfp = have_fpu; + have_htm_core = 0; feature = tdesc_find_feature (tdesc, - "org.gnu.gdb.power.altivec"); + "org.gnu.gdb.power.htm.fpu"); if (feature != NULL) { - static const char *const vector_regs[] = { - "vr0", "vr1", "vr2", "vr3", "vr4", "vr5", "vr6", "vr7", - "vr8", "vr9", "vr10", "vr11", "vr12", "vr13", "vr14", "vr15", - "vr16", "vr17", "vr18", "vr19", "vr20", "vr21", "vr22", "vr23", - "vr24", "vr25", "vr26", "vr27", "vr28", "vr29", "vr30", "vr31" + valid_p = 1; + + static const char *const cfprs[] = { + "cf0", "cf1", "cf2", "cf3", "cf4", "cf5", "cf6", "cf7", + "cf8", "cf9", "cf10", "cf11", "cf12", "cf13", "cf14", "cf15", + "cf16", "cf17", "cf18", "cf19", "cf20", "cf21", "cf22", + "cf23", "cf24", "cf25", "cf26", "cf27", "cf28", "cf29", + "cf30", "cf31", "cfpscr" }; - valid_p = 1; - for (i = 0; i < ppc_num_gprs; i++) + for (i = 0; i < ARRAY_SIZE (cfprs); i++) valid_p &= tdesc_numbered_register (feature, tdesc_data, - PPC_VR0_REGNUM + i, - vector_regs[i]); - valid_p &= tdesc_numbered_register (feature, tdesc_data, - PPC_VSCR_REGNUM, "vscr"); - valid_p &= tdesc_numbered_register (feature, tdesc_data, - PPC_VRSAVE_REGNUM, "vrsave"); + PPC_CF0_REGNUM + i, + cfprs[i]); - if (have_spe || !valid_p) + if (!valid_p) { tdesc_data_cleanup (tdesc_data); return NULL; } - have_altivec = 1; + have_htm_fpu = 1; } else - have_altivec = 0; + have_htm_fpu = 0; - /* On machines supporting the SPE APU, the general-purpose registers - are 64 bits long. There are SIMD vector instructions to treat them - as pairs of floats, but the rest of the instruction set treats them - as 32-bit registers, and only operates on their lower halves. + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.power.htm.altivec"); + if (feature != NULL) + { + valid_p = 1; - In the GDB regcache, we treat their high and low halves as separate - registers. The low halves we present as the general-purpose - registers, and then we have pseudo-registers that stitch together - the upper and lower halves and present them as pseudo-registers. + static const char *const cvmx[] = { + "cvr0", "cvr1", "cvr2", "cvr3", "cvr4", "cvr5", "cvr6", + "cvr7", "cvr8", "cvr9", "cvr10", "cvr11", "cvr12", "cvr13", + "cvr14", "cvr15","cvr16", "cvr17", "cvr18", "cvr19", "cvr20", + "cvr21", "cvr22", "cvr23", "cvr24", "cvr25", "cvr26", + "cvr27", "cvr28", "cvr29", "cvr30", "cvr31", "cvscr", + "cvrsave" + }; - Thus, the target description is expected to supply the upper - halves separately. */ + for (i = 0; i < ARRAY_SIZE (cvmx); i++) + valid_p &= tdesc_numbered_register (feature, tdesc_data, + PPC_CVR0_REGNUM + i, + cvmx[i]); + + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + have_htm_altivec = 1; + } + else + have_htm_altivec = 0; feature = tdesc_find_feature (tdesc, - "org.gnu.gdb.power.spe"); + "org.gnu.gdb.power.htm.vsx"); if (feature != NULL) { - static const char *const upper_spe[] = { - "ev0h", "ev1h", "ev2h", "ev3h", - "ev4h", "ev5h", "ev6h", "ev7h", - "ev8h", "ev9h", "ev10h", "ev11h", - "ev12h", "ev13h", "ev14h", "ev15h", - "ev16h", "ev17h", "ev18h", "ev19h", - "ev20h", "ev21h", "ev22h", "ev23h", - "ev24h", "ev25h", "ev26h", "ev27h", - "ev28h", "ev29h", "ev30h", "ev31h" + valid_p = 1; + + static const char *const cvsx[] = { + "cvs0h", "cvs1h", "cvs2h", "cvs3h", "cvs4h", "cvs5h", + "cvs6h", "cvs7h", "cvs8h", "cvs9h", "cvs10h", "cvs11h", + "cvs12h", "cvs13h", "cvs14h", "cvs15h", "cvs16h", "cvs17h", + "cvs18h", "cvs19h", "cvs20h", "cvs21h", "cvs22h", "cvs23h", + "cvs24h", "cvs25h", "cvs26h", "cvs27h", "cvs28h", "cvs29h", + "cvs30h", "cvs31h" }; - valid_p = 1; - for (i = 0; i < ppc_num_gprs; i++) + for (i = 0; i < ARRAY_SIZE (cvsx); i++) valid_p &= tdesc_numbered_register (feature, tdesc_data, - PPC_SPE_UPPER_GP0_REGNUM + i, - upper_spe[i]); - valid_p &= tdesc_numbered_register (feature, tdesc_data, - PPC_SPE_ACC_REGNUM, "acc"); - valid_p &= tdesc_numbered_register (feature, tdesc_data, - PPC_SPE_FSCR_REGNUM, "spefscr"); + (PPC_CVSR0_UPPER_REGNUM + + i), + cvsx[i]); - if (have_mq || have_fpu || !valid_p) + if (!valid_p || !have_htm_fpu || !have_htm_altivec) { tdesc_data_cleanup (tdesc_data); return NULL; } - have_spe = 1; + have_htm_vsx = 1; } else - have_spe = 0; + have_htm_vsx = 0; + + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.power.htm.ppr"); + if (feature != NULL) + { + valid_p = tdesc_numbered_register (feature, tdesc_data, + PPC_CPPR_REGNUM, "cppr"); + + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + have_htm_ppr = 1; + } + else + have_htm_ppr = 0; + + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.power.htm.dscr"); + if (feature != NULL) + { + valid_p = tdesc_numbered_register (feature, tdesc_data, + PPC_CDSCR_REGNUM, "cdscr"); + + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + have_htm_dscr = 1; + } + else + have_htm_dscr = 0; + + feature = tdesc_find_feature (tdesc, + "org.gnu.gdb.power.htm.tar"); + if (feature != NULL) + { + valid_p = tdesc_numbered_register (feature, tdesc_data, + PPC_CTAR_REGNUM, "ctar"); + + if (!valid_p) + { + tdesc_data_cleanup (tdesc_data); + return NULL; + } + have_htm_tar = 1; + } + else + have_htm_tar = 0; } /* If we have a 64-bit binary on a 32-bit target, complain. Also @@ -3543,10 +6739,25 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) } #ifdef HAVE_ELF + if (from_elf_exec) + { + switch (elf_elfheader (info.abfd)->e_flags & EF_PPC64_ABI) + { + case 1: + elf_abi = POWERPC_ELF_V1; + break; + case 2: + elf_abi = POWERPC_ELF_V2; + break; + default: + break; + } + } + if (soft_float_flag == AUTO_BOOLEAN_AUTO && from_elf_exec) { switch (bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_GNU, - Tag_GNU_Power_ABI_FP)) + Tag_GNU_Power_ABI_FP) & 3) { case 1: soft_float_flag = AUTO_BOOLEAN_FALSE; @@ -3559,6 +6770,22 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) } } + if (long_double_abi == POWERPC_LONG_DOUBLE_AUTO && from_elf_exec) + { + switch (bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_GNU, + Tag_GNU_Power_ABI_FP) >> 2) + { + case 1: + long_double_abi = POWERPC_LONG_DOUBLE_IBM128; + break; + case 3: + long_double_abi = POWERPC_LONG_DOUBLE_IEEE128; + break; + default: + break; + } + } + if (vector_abi == POWERPC_VEC_AUTO && from_elf_exec) { switch (bfd_elf_get_obj_attr_int (info.abfd, OBJ_ATTR_GNU, @@ -3579,6 +6806,21 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) } #endif + /* At this point, the only supported ELF-based 64-bit little-endian + operating system is GNU/Linux, and this uses the ELFv2 ABI by + default. All other supported ELF-based operating systems use the + ELFv1 ABI by default. Therefore, if the ABI marker is missing, + e.g. because we run a legacy binary, or have attached to a process + and have not found any associated binary file, set the default + according to this heuristic. */ + if (elf_abi == POWERPC_ELF_AUTO) + { + if (wordsize == 8 && info.byte_order == BFD_ENDIAN_LITTLE) + elf_abi = POWERPC_ELF_V2; + else + elf_abi = POWERPC_ELF_V1; + } + if (soft_float_flag == AUTO_BOOLEAN_TRUE) soft_float = 1; else if (soft_float_flag == AUTO_BOOLEAN_FALSE) @@ -3621,8 +6863,12 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) meaningful, because 64-bit CPUs can run in 32-bit mode. So, perform separate word size check. */ tdep = gdbarch_tdep (arches->gdbarch); + if (tdep && tdep->elf_abi != elf_abi) + continue; if (tdep && tdep->soft_float != soft_float) continue; + if (tdep && tdep->long_double_abi != long_double_abi) + continue; if (tdep && tdep->vector_abi != vector_abi) continue; if (tdep && tdep->wordsize == wordsize) @@ -3641,9 +6887,11 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) - "set arch" trust blindly - GDB startup useless but harmless */ - tdep = XCALLOC (1, struct gdbarch_tdep); + tdep = XCNEW (struct gdbarch_tdep); tdep->wordsize = wordsize; + tdep->elf_abi = elf_abi; tdep->soft_float = soft_float; + tdep->long_double_abi = long_double_abi; tdep->vector_abi = vector_abi; gdbarch = gdbarch_alloc (&info, tdep); @@ -3659,15 +6907,41 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) tdep->ppc_fp0_regnum = have_fpu ? PPC_F0_REGNUM : -1; tdep->ppc_fpscr_regnum = have_fpu ? PPC_FPSCR_REGNUM : -1; + tdep->ppc_vsr0_upper_regnum = have_vsx ? PPC_VSR0_UPPER_REGNUM : -1; tdep->ppc_vr0_regnum = have_altivec ? PPC_VR0_REGNUM : -1; tdep->ppc_vrsave_regnum = have_altivec ? PPC_VRSAVE_REGNUM : -1; tdep->ppc_ev0_upper_regnum = have_spe ? PPC_SPE_UPPER_GP0_REGNUM : -1; tdep->ppc_acc_regnum = have_spe ? PPC_SPE_ACC_REGNUM : -1; tdep->ppc_spefscr_regnum = have_spe ? PPC_SPE_FSCR_REGNUM : -1; + tdep->ppc_ppr_regnum = have_ppr ? PPC_PPR_REGNUM : -1; + tdep->ppc_dscr_regnum = have_dscr ? PPC_DSCR_REGNUM : -1; + tdep->ppc_tar_regnum = have_tar ? PPC_TAR_REGNUM : -1; + tdep->have_ebb = have_ebb; + + /* If additional pmu registers are added, care must be taken when + setting new fields in the tdep below, to maintain compatibility + with features that only provide some of the registers. Currently + gdb access to the pmu registers is only supported in linux, and + linux only provides a subset of the pmu registers defined in the + architecture. */ + + tdep->ppc_mmcr0_regnum = have_pmu ? PPC_MMCR0_REGNUM : -1; + tdep->ppc_mmcr2_regnum = have_pmu ? PPC_MMCR2_REGNUM : -1; + tdep->ppc_siar_regnum = have_pmu ? PPC_SIAR_REGNUM : -1; + tdep->ppc_sdar_regnum = have_pmu ? PPC_SDAR_REGNUM : -1; + tdep->ppc_sier_regnum = have_pmu ? PPC_SIER_REGNUM : -1; + + tdep->have_htm_spr = have_htm_spr; + tdep->have_htm_core = have_htm_core; + tdep->have_htm_fpu = have_htm_fpu; + tdep->have_htm_altivec = have_htm_altivec; + tdep->have_htm_vsx = have_htm_vsx; + tdep->ppc_cppr_regnum = have_htm_ppr ? PPC_CPPR_REGNUM : -1; + tdep->ppc_cdscr_regnum = have_htm_dscr ? PPC_CDSCR_REGNUM : -1; + tdep->ppc_ctar_regnum = have_htm_tar ? PPC_CTAR_REGNUM : -1; set_gdbarch_pc_regnum (gdbarch, PPC_PC_REGNUM); set_gdbarch_sp_regnum (gdbarch, PPC_R0_REGNUM + 1); - set_gdbarch_deprecated_fp_regnum (gdbarch, PPC_R0_REGNUM + 1); set_gdbarch_fp0_regnum (gdbarch, tdep->ppc_fp0_regnum); set_gdbarch_register_sim_regno (gdbarch, rs6000_register_sim_regno); @@ -3676,34 +6950,30 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) alias. */ set_gdbarch_ps_regnum (gdbarch, tdep->ppc_ps_regnum); - if (sysv_abi && wordsize == 8) + if (wordsize == 8) set_gdbarch_return_value (gdbarch, ppc64_sysv_abi_return_value); - else if (sysv_abi && wordsize == 4) - set_gdbarch_return_value (gdbarch, ppc_sysv_abi_return_value); else - set_gdbarch_return_value (gdbarch, rs6000_return_value); + set_gdbarch_return_value (gdbarch, ppc_sysv_abi_return_value); /* Set lr_frame_offset. */ if (wordsize == 8) tdep->lr_frame_offset = 16; - else if (sysv_abi) - tdep->lr_frame_offset = 4; else - tdep->lr_frame_offset = 8; + tdep->lr_frame_offset = 4; - if (have_spe || have_dfp) + if (have_spe || have_dfp || have_altivec + || have_vsx || have_htm_fpu || have_htm_vsx) { set_gdbarch_pseudo_register_read (gdbarch, rs6000_pseudo_register_read); - set_gdbarch_pseudo_register_write (gdbarch, rs6000_pseudo_register_write); + set_gdbarch_pseudo_register_write (gdbarch, + rs6000_pseudo_register_write); + set_gdbarch_ax_pseudo_register_collect (gdbarch, + rs6000_ax_pseudo_register_collect); } - set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1); + set_gdbarch_gen_return_address (gdbarch, rs6000_gen_return_address); - /* Select instruction printer. */ - if (arch == bfd_arch_rs6000) - set_gdbarch_print_insn (gdbarch, print_insn_rs6000); - else - set_gdbarch_print_insn (gdbarch, gdb_print_insn_powerpc); + set_gdbarch_have_nonsteppable_watchpoint (gdbarch, 1); set_gdbarch_num_regs (gdbarch, PPC_NUM_REGS); @@ -3711,6 +6981,16 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) num_pseudoregs += 32; if (have_dfp) num_pseudoregs += 16; + if (have_altivec) + num_pseudoregs += 32; + if (have_vsx) + /* Include both VSX and Extended FP registers. */ + num_pseudoregs += 96; + if (have_htm_fpu) + num_pseudoregs += 16; + /* Include both checkpointed VSX and EFP registers. */ + if (have_htm_vsx) + num_pseudoregs += 64 + 32; set_gdbarch_num_pseudo_regs (gdbarch, num_pseudoregs); @@ -3721,22 +7001,13 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_long_long_bit (gdbarch, 8 * TARGET_CHAR_BIT); set_gdbarch_float_bit (gdbarch, 4 * TARGET_CHAR_BIT); set_gdbarch_double_bit (gdbarch, 8 * TARGET_CHAR_BIT); - if (sysv_abi) - set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT); - else - set_gdbarch_long_double_bit (gdbarch, 8 * TARGET_CHAR_BIT); + set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT); set_gdbarch_char_signed (gdbarch, 0); set_gdbarch_frame_align (gdbarch, rs6000_frame_align); - if (sysv_abi && wordsize == 8) + if (wordsize == 8) /* PPC64 SYSV. */ set_gdbarch_frame_red_zone_size (gdbarch, 288); - else if (!sysv_abi && wordsize == 4) - /* PowerOpen / AIX 32 bit. The saved area or red zone consists of - 19 4 byte GPRS + 18 8 byte FPRs giving a total of 220 bytes. - Problem is, 220 isn't frame (16 byte) aligned. Round it up to - 224. */ - set_gdbarch_frame_red_zone_size (gdbarch, 224); set_gdbarch_convert_register_p (gdbarch, rs6000_convert_register_p); set_gdbarch_register_to_value (gdbarch, rs6000_register_to_value); @@ -3745,46 +7016,32 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_stab_reg_to_regnum (gdbarch, rs6000_stab_reg_to_regnum); set_gdbarch_dwarf2_reg_to_regnum (gdbarch, rs6000_dwarf2_reg_to_regnum); - if (sysv_abi && wordsize == 4) + if (wordsize == 4) set_gdbarch_push_dummy_call (gdbarch, ppc_sysv_abi_push_dummy_call); - else if (sysv_abi && wordsize == 8) + else if (wordsize == 8) set_gdbarch_push_dummy_call (gdbarch, ppc64_sysv_abi_push_dummy_call); - else - set_gdbarch_push_dummy_call (gdbarch, rs6000_push_dummy_call); set_gdbarch_skip_prologue (gdbarch, rs6000_skip_prologue); - set_gdbarch_in_function_epilogue_p (gdbarch, rs6000_in_function_epilogue_p); + set_gdbarch_stack_frame_destroyed_p (gdbarch, rs6000_stack_frame_destroyed_p); + set_gdbarch_skip_main_prologue (gdbarch, rs6000_skip_main_prologue); set_gdbarch_inner_than (gdbarch, core_addr_lessthan); - set_gdbarch_breakpoint_from_pc (gdbarch, rs6000_breakpoint_from_pc); + + set_gdbarch_breakpoint_kind_from_pc (gdbarch, + rs6000_breakpoint::kind_from_pc); + set_gdbarch_sw_breakpoint_from_kind (gdbarch, + rs6000_breakpoint::bp_from_kind); /* The value of symbols of type N_SO and N_FUN maybe null when - it shouldn't be. */ + it shouldn't be. */ set_gdbarch_sofun_address_maybe_missing (gdbarch, 1); /* Handles single stepping of atomic sequences. */ - set_gdbarch_software_single_step (gdbarch, deal_with_atomic_sequence); + set_gdbarch_software_single_step (gdbarch, ppc_deal_with_atomic_sequence); - /* Handle the 64-bit SVR4 minimal-symbol convention of using "FN" - for the descriptor and ".FN" for the entry-point -- a user - specifying "break FN" will unexpectedly end up with a breakpoint - on the descriptor and not the function. This architecture method - transforms any breakpoints on descriptors into breakpoints on the - corresponding entry point. */ - if (sysv_abi && wordsize == 8) - set_gdbarch_adjust_breakpoint_address (gdbarch, ppc64_sysv_abi_adjust_breakpoint_address); - - /* Not sure on this. FIXMEmgo */ + /* Not sure on this. FIXMEmgo */ set_gdbarch_frame_args_skip (gdbarch, 8); - if (!sysv_abi) - { - /* Handle RS/6000 function pointers (which are really function - descriptors). */ - set_gdbarch_convert_from_func_ptr_addr (gdbarch, - rs6000_convert_from_func_ptr_addr); - } - /* Helpers for function argument information. */ set_gdbarch_fetch_pointer_argument (gdbarch, rs6000_fetch_pointer_argument); @@ -3794,32 +7051,42 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) set_gdbarch_skip_trampoline_code (gdbarch, rs6000_skip_trampoline_code); /* Hook in the DWARF CFI frame unwinder. */ - frame_unwind_append_sniffer (gdbarch, dwarf2_frame_sniffer); + dwarf2_append_unwinders (gdbarch); dwarf2_frame_set_adjust_regnum (gdbarch, rs6000_adjust_frame_regnum); /* Frame handling. */ dwarf2_frame_set_init_reg (gdbarch, ppc_dwarf2_frame_init_reg); + /* Setup displaced stepping. */ + set_gdbarch_displaced_step_copy_insn (gdbarch, + ppc_displaced_step_copy_insn); + set_gdbarch_displaced_step_hw_singlestep (gdbarch, + ppc_displaced_step_hw_singlestep); + set_gdbarch_displaced_step_fixup (gdbarch, ppc_displaced_step_fixup); + set_gdbarch_displaced_step_location (gdbarch, + displaced_step_at_entry_point); + + set_gdbarch_max_insn_length (gdbarch, PPC_INSN_SIZE); + /* Hook in ABI-specific overrides, if they have been registered. */ + info.target_desc = tdesc; + info.tdesc_data = tdesc_data; gdbarch_init_osabi (info, gdbarch); switch (info.osabi) { case GDB_OSABI_LINUX: - case GDB_OSABI_NETBSD_AOUT: - case GDB_OSABI_NETBSD_ELF: + case GDB_OSABI_NETBSD: case GDB_OSABI_UNKNOWN: - set_gdbarch_unwind_pc (gdbarch, rs6000_unwind_pc); - frame_unwind_append_sniffer (gdbarch, rs6000_frame_sniffer); - set_gdbarch_unwind_dummy_id (gdbarch, rs6000_unwind_dummy_id); + frame_unwind_append_unwinder (gdbarch, &rs6000_epilogue_frame_unwind); + frame_unwind_append_unwinder (gdbarch, &rs6000_frame_unwind); frame_base_append_sniffer (gdbarch, rs6000_frame_base_sniffer); break; default: set_gdbarch_believe_pcc_promotion (gdbarch, 1); - set_gdbarch_unwind_pc (gdbarch, rs6000_unwind_pc); - frame_unwind_append_sniffer (gdbarch, rs6000_frame_sniffer); - set_gdbarch_unwind_dummy_id (gdbarch, rs6000_unwind_dummy_id); + frame_unwind_append_unwinder (gdbarch, &rs6000_epilogue_frame_unwind); + frame_unwind_append_unwinder (gdbarch, &rs6000_frame_unwind); frame_base_append_sniffer (gdbarch, rs6000_frame_base_sniffer); } @@ -3832,15 +7099,64 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches) halves anonymous. */ set_gdbarch_register_name (gdbarch, rs6000_register_name); - /* Recording the numbering of pseudo registers. */ - tdep->ppc_ev0_regnum = have_spe ? gdbarch_num_regs (gdbarch) : -1; + /* Choose register numbers for all supported pseudo-registers. */ + tdep->ppc_ev0_regnum = -1; + tdep->ppc_dl0_regnum = -1; + tdep->ppc_v0_alias_regnum = -1; + tdep->ppc_vsr0_regnum = -1; + tdep->ppc_efpr0_regnum = -1; + tdep->ppc_cdl0_regnum = -1; + tdep->ppc_cvsr0_regnum = -1; + tdep->ppc_cefpr0_regnum = -1; - /* Set the register number for _Decimal128 pseudo-registers. */ - tdep->ppc_dl0_regnum = have_dfp? gdbarch_num_regs (gdbarch) : -1; + cur_reg = gdbarch_num_regs (gdbarch); - if (have_dfp && have_spe) - /* Put the _Decimal128 pseudo-registers after the SPE registers. */ - tdep->ppc_dl0_regnum += 32; + if (have_spe) + { + tdep->ppc_ev0_regnum = cur_reg; + cur_reg += 32; + } + if (have_dfp) + { + tdep->ppc_dl0_regnum = cur_reg; + cur_reg += 16; + } + if (have_altivec) + { + tdep->ppc_v0_alias_regnum = cur_reg; + cur_reg += 32; + } + if (have_vsx) + { + tdep->ppc_vsr0_regnum = cur_reg; + cur_reg += 64; + tdep->ppc_efpr0_regnum = cur_reg; + cur_reg += 32; + } + if (have_htm_fpu) + { + tdep->ppc_cdl0_regnum = cur_reg; + cur_reg += 16; + } + if (have_htm_vsx) + { + tdep->ppc_cvsr0_regnum = cur_reg; + cur_reg += 64; + tdep->ppc_cefpr0_regnum = cur_reg; + cur_reg += 32; + } + + gdb_assert (gdbarch_num_cooked_regs (gdbarch) == cur_reg); + + /* Register the ravenscar_arch_ops. */ + if (mach == bfd_mach_ppc_e500) + register_e500_ravenscar_ops (gdbarch); + else + register_ppc_ravenscar_ops (gdbarch); + + set_gdbarch_disassembler_options (gdbarch, &powerpc_disassembler_options); + set_gdbarch_valid_disassembler_options (gdbarch, + disassembler_options_powerpc ()); return gdbarch; } @@ -3856,24 +7172,8 @@ rs6000_dump_tdep (struct gdbarch *gdbarch, struct ui_file *file) /* FIXME: Dump gdbarch_tdep. */ } -/* PowerPC-specific commands. */ - -static void -set_powerpc_command (char *args, int from_tty) -{ - printf_unfiltered (_("\ -\"set powerpc\" must be followed by an appropriate subcommand.\n")); - help_list (setpowerpccmdlist, "set powerpc ", all_commands, gdb_stdout); -} - -static void -show_powerpc_command (char *args, int from_tty) -{ - cmd_show_list (showpowerpccmdlist, from_tty, ""); -} - static void -powerpc_set_soft_float (char *args, int from_tty, +powerpc_set_soft_float (const char *args, int from_tty, struct cmd_list_element *c) { struct gdbarch_info info; @@ -3881,15 +7181,15 @@ powerpc_set_soft_float (char *args, int from_tty, /* Update the architecture. */ gdbarch_info_init (&info); if (!gdbarch_update_p (info)) - internal_error (__FILE__, __LINE__, "could not update architecture"); + internal_error (__FILE__, __LINE__, _("could not update architecture")); } static void -powerpc_set_vector_abi (char *args, int from_tty, +powerpc_set_vector_abi (const char *args, int from_tty, struct cmd_list_element *c) { struct gdbarch_info info; - enum powerpc_vector_abi vector_abi; + int vector_abi; for (vector_abi = POWERPC_VEC_AUTO; vector_abi != POWERPC_VEC_LAST; @@ -3897,7 +7197,7 @@ powerpc_set_vector_abi (char *args, int from_tty, if (strcmp (powerpc_vector_abi_string, powerpc_vector_strings[vector_abi]) == 0) { - powerpc_vector_abi_global = vector_abi; + powerpc_vector_abi_global = (enum powerpc_vector_abi) vector_abi; break; } @@ -3908,29 +7208,112 @@ powerpc_set_vector_abi (char *args, int from_tty, /* Update the architecture. */ gdbarch_info_init (&info); if (!gdbarch_update_p (info)) - internal_error (__FILE__, __LINE__, "could not update architecture"); + internal_error (__FILE__, __LINE__, _("could not update architecture")); } -/* Initialization code. */ +/* Show the current setting of the exact watchpoints flag. */ + +static void +show_powerpc_exact_watchpoints (struct ui_file *file, int from_tty, + struct cmd_list_element *c, + const char *value) +{ + fprintf_filtered (file, _("Use of exact watchpoints is %s.\n"), value); +} -extern initialize_file_ftype _initialize_rs6000_tdep; /* -Wmissing-prototypes */ +/* Read a PPC instruction from memory. */ +static unsigned int +read_insn (struct frame_info *frame, CORE_ADDR pc) +{ + struct gdbarch *gdbarch = get_frame_arch (frame); + enum bfd_endian byte_order = gdbarch_byte_order (gdbarch); + + return read_memory_unsigned_integer (pc, 4, byte_order); +} + +/* Return non-zero if the instructions at PC match the series + described in PATTERN, or zero otherwise. PATTERN is an array of + 'struct ppc_insn_pattern' objects, terminated by an entry whose + mask is zero. + + When the match is successful, fill INSNS[i] with what PATTERN[i] + matched. If PATTERN[i] is optional, and the instruction wasn't + present, set INSNS[i] to 0 (which is not a valid PPC instruction). + INSNS should have as many elements as PATTERN, minus the terminator. + Note that, if PATTERN contains optional instructions which aren't + present in memory, then INSNS will have holes, so INSNS[i] isn't + necessarily the i'th instruction in memory. */ + +int +ppc_insns_match_pattern (struct frame_info *frame, CORE_ADDR pc, + const struct ppc_insn_pattern *pattern, + unsigned int *insns) +{ + int i; + unsigned int insn; + + for (i = 0, insn = 0; pattern[i].mask; i++) + { + if (insn == 0) + insn = read_insn (frame, pc); + insns[i] = 0; + if ((insn & pattern[i].mask) == pattern[i].data) + { + insns[i] = insn; + pc += 4; + insn = 0; + } + else if (!pattern[i].optional) + return 0; + } + + return 1; +} + +/* Return the 'd' field of the d-form instruction INSN, properly + sign-extended. */ + +CORE_ADDR +ppc_insn_d_field (unsigned int insn) +{ + return ((((CORE_ADDR) insn & 0xffff) ^ 0x8000) - 0x8000); +} + +/* Return the 'ds' field of the ds-form instruction INSN, with the two + zero bits concatenated at the right, and properly + sign-extended. */ + +CORE_ADDR +ppc_insn_ds_field (unsigned int insn) +{ + return ((((CORE_ADDR) insn & 0xfffc) ^ 0x8000) - 0x8000); +} + +/* Initialization code. */ + +void _initialize_rs6000_tdep (); void -_initialize_rs6000_tdep (void) +_initialize_rs6000_tdep () { gdbarch_register (bfd_arch_rs6000, rs6000_gdbarch_init, rs6000_dump_tdep); gdbarch_register (bfd_arch_powerpc, rs6000_gdbarch_init, rs6000_dump_tdep); /* Initialize the standard target descriptions. */ initialize_tdesc_powerpc_32 (); + initialize_tdesc_powerpc_altivec32 (); + initialize_tdesc_powerpc_vsx32 (); initialize_tdesc_powerpc_403 (); initialize_tdesc_powerpc_403gc (); + initialize_tdesc_powerpc_405 (); initialize_tdesc_powerpc_505 (); initialize_tdesc_powerpc_601 (); initialize_tdesc_powerpc_602 (); initialize_tdesc_powerpc_603 (); initialize_tdesc_powerpc_604 (); initialize_tdesc_powerpc_64 (); + initialize_tdesc_powerpc_altivec64 (); + initialize_tdesc_powerpc_vsx64 (); initialize_tdesc_powerpc_7400 (); initialize_tdesc_powerpc_750 (); initialize_tdesc_powerpc_860 (); @@ -3939,13 +7322,13 @@ _initialize_rs6000_tdep (void) /* Add root prefix command for all "set powerpc"/"show powerpc" commands. */ - add_prefix_cmd ("powerpc", no_class, set_powerpc_command, - _("Various PowerPC-specific commands."), - &setpowerpccmdlist, "set powerpc ", 0, &setlist); + add_basic_prefix_cmd ("powerpc", no_class, + _("Various PowerPC-specific commands."), + &setpowerpccmdlist, "set powerpc ", 0, &setlist); - add_prefix_cmd ("powerpc", no_class, show_powerpc_command, - _("Various PowerPC-specific commands."), - &showpowerpccmdlist, "show powerpc ", 0, &showlist); + add_show_prefix_cmd ("powerpc", no_class, + _("Various PowerPC-specific commands."), + &showpowerpccmdlist, "show powerpc ", 0, &showlist); /* Add a command to allow the user to force the ABI. */ add_setshow_auto_boolean_cmd ("soft-float", class_support, @@ -3962,4 +7345,17 @@ _initialize_rs6000_tdep (void) _("Show the vector ABI."), NULL, powerpc_set_vector_abi, NULL, &setpowerpccmdlist, &showpowerpccmdlist); + + add_setshow_boolean_cmd ("exact-watchpoints", class_support, + &target_exact_watchpoints, + _("\ +Set whether to use just one debug register for watchpoints on scalars."), + _("\ +Show whether to use just one debug register for watchpoints on scalars."), + _("\ +If true, GDB will use only one debug register when watching a variable of\n\ +scalar type, thus assuming that the variable is accessed through the address\n\ +of its first byte."), + NULL, show_powerpc_exact_watchpoints, + &setpowerpccmdlist, &showpowerpccmdlist); }