gdb/ppc-linux-nat.c - gdb
Global variables defined
Data types defined
Functions defined
Macros defined
Source code
- #include "defs.h"
- #include "observer.h"
- #include "frame.h"
- #include "inferior.h"
- #include "gdbthread.h"
- #include "gdbcore.h"
- #include "regcache.h"
- #include "target.h"
- #include "linux-nat.h"
- #include <stdint.h>
- #include <sys/types.h>
- #include <signal.h>
- #include <sys/user.h>
- #include <sys/ioctl.h>
- #include "gdb_wait.h"
- #include <fcntl.h>
- #include <sys/procfs.h>
- #include <sys/ptrace.h>
- #include "gregset.h"
- #include "ppc-tdep.h"
- #include "ppc-linux-tdep.h"
- #include "elf/common.h"
- #include "auxv.h"
- #ifndef PT_ORIG_R3
- #define PT_ORIG_R3 34
- #endif
- #ifndef PT_TRAP
- #define PT_TRAP 40
- #endif
- #ifndef PPC_FEATURE_CELL
- #define PPC_FEATURE_CELL 0x00010000
- #endif
- #ifndef PPC_FEATURE_BOOKE
- #define PPC_FEATURE_BOOKE 0x00008000
- #endif
- #ifndef PPC_FEATURE_HAS_DFP
- #define PPC_FEATURE_HAS_DFP 0x00000400
- #endif
- #ifndef PTRACE_GETVRREGS
- #define PTRACE_GETVRREGS 18
- #define PTRACE_SETVRREGS 19
- #endif
- #ifndef PTRACE_GETVSXREGS
- #define PTRACE_GETVSXREGS 27
- #define PTRACE_SETVSXREGS 28
- #endif
- #ifndef PTRACE_GETEVRREGS
- #define PTRACE_GETEVRREGS 20
- #define PTRACE_SETEVRREGS 21
- #endif
- #ifndef PTRACE_GET_DEBUGREG
- #define PTRACE_GET_DEBUGREG 25
- #endif
- #ifndef PTRACE_SET_DEBUGREG
- #define PTRACE_SET_DEBUGREG 26
- #endif
- #ifndef PTRACE_GETSIGINFO
- #define PTRACE_GETSIGINFO 0x4202
- #endif
- #ifndef PPC_PTRACE_GETHWDBGINFO
- #define PPC_PTRACE_GETHWDBGINFO 0x89
- #define PPC_PTRACE_SETHWDEBUG 0x88
- #define PPC_PTRACE_DELHWDEBUG 0x87
- struct ppc_debug_info
- {
- uint32_t version;
- uint32_t num_instruction_bps;
- uint32_t num_data_bps;
- uint32_t num_condition_regs;
- uint32_t data_bp_alignment;
- uint32_t sizeof_condition;
- uint64_t features;
- };
- #define PPC_DEBUG_FEATURE_INSN_BP_RANGE 0x1
- #define PPC_DEBUG_FEATURE_INSN_BP_MASK 0x2
- #define PPC_DEBUG_FEATURE_DATA_BP_RANGE 0x4
- #define PPC_DEBUG_FEATURE_DATA_BP_MASK 0x8
- struct ppc_hw_breakpoint
- {
- uint32_t version;
- uint32_t trigger_type;
- uint32_t addr_mode;
- uint32_t condition_mode;
- uint64_t addr;
- uint64_t addr2;
- uint64_t condition_value;
- };
- #define PPC_BREAKPOINT_TRIGGER_EXECUTE 0x1
- #define PPC_BREAKPOINT_TRIGGER_READ 0x2
- #define PPC_BREAKPOINT_TRIGGER_WRITE 0x4
- #define PPC_BREAKPOINT_TRIGGER_RW 0x6
- #define PPC_BREAKPOINT_MODE_EXACT 0x0
- #define PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE 0x1
- #define PPC_BREAKPOINT_MODE_RANGE_EXCLUSIVE 0x2
- #define PPC_BREAKPOINT_MODE_MASK 0x3
- #define PPC_BREAKPOINT_CONDITION_NONE 0x0
- #define PPC_BREAKPOINT_CONDITION_AND 0x1
- #define PPC_BREAKPOINT_CONDITION_EXACT 0x1
- #define PPC_BREAKPOINT_CONDITION_OR 0x2
- #define PPC_BREAKPOINT_CONDITION_AND_OR 0x3
- #define PPC_BREAKPOINT_CONDITION_BE_ALL 0x00ff0000
- #define PPC_BREAKPOINT_CONDITION_BE_SHIFT 16
- #define PPC_BREAKPOINT_CONDITION_BE(n) \
- (1<<((n)+PPC_BREAKPOINT_CONDITION_BE_SHIFT))
- #endif
- #ifndef PPC_DEBUG_FEATURE_DATA_BP_DAWR
- #define PPC_DEBUG_FEATURE_DATA_BP_DAWR 0x10
- #endif
- #ifndef PTRACE_GETREGS
- #define PTRACE_GETREGS 12
- #endif
- #ifndef PTRACE_SETREGS
- #define PTRACE_SETREGS 13
- #endif
- #ifndef PTRACE_GETFPREGS
- #define PTRACE_GETFPREGS 14
- #endif
- #ifndef PTRACE_SETFPREGS
- #define PTRACE_SETFPREGS 15
- #endif
- #define SIZEOF_VRREGS 33*16+4
- typedef char gdb_vrregset_t[SIZEOF_VRREGS];
- #define SIZEOF_VSXREGS 32*8
- typedef char gdb_vsxregset_t[SIZEOF_VSXREGS];
- struct gdb_evrregset_t
- {
- unsigned long evr[32];
- unsigned long long acc;
- unsigned long spefscr;
- };
- int have_ptrace_getsetvsxregs = 1;
- int have_ptrace_getvrregs = 1;
- int have_ptrace_getsetevrregs = 1;
- int have_ptrace_getsetregs = 1;
- int have_ptrace_getsetfpregs = 1;
- static int
- ppc_register_u_addr (struct gdbarch *gdbarch, int regno)
- {
- int u_addr = -1;
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-
- int wordsize = sizeof (long);
-
- if (regno >= tdep->ppc_gp0_regnum
- && regno < tdep->ppc_gp0_regnum + ppc_num_gprs)
- u_addr = ((regno - tdep->ppc_gp0_regnum + PT_R0) * wordsize);
-
- if (tdep->ppc_fp0_regnum >= 0
- && regno >= tdep->ppc_fp0_regnum
- && regno < tdep->ppc_fp0_regnum + ppc_num_fprs)
- u_addr = (PT_FPR0 * wordsize) + ((regno - tdep->ppc_fp0_regnum) * 8);
-
- if (regno == gdbarch_pc_regnum (gdbarch))
- u_addr = PT_NIP * wordsize;
- if (regno == tdep->ppc_lr_regnum)
- u_addr = PT_LNK * wordsize;
- if (regno == tdep->ppc_cr_regnum)
- u_addr = PT_CCR * wordsize;
- if (regno == tdep->ppc_xer_regnum)
- u_addr = PT_XER * wordsize;
- if (regno == tdep->ppc_ctr_regnum)
- u_addr = PT_CTR * wordsize;
- #ifdef PT_MQ
- if (regno == tdep->ppc_mq_regnum)
- u_addr = PT_MQ * wordsize;
- #endif
- if (regno == tdep->ppc_ps_regnum)
- u_addr = PT_MSR * wordsize;
- if (regno == PPC_ORIG_R3_REGNUM)
- u_addr = PT_ORIG_R3 * wordsize;
- if (regno == PPC_TRAP_REGNUM)
- u_addr = PT_TRAP * wordsize;
- if (tdep->ppc_fpscr_regnum >= 0
- && regno == tdep->ppc_fpscr_regnum)
- {
-
- if (wordsize == 8 && PT_FPSCR == (48 + 32 + 1))
- u_addr = (48 + 32) * wordsize;
-
- else if (wordsize == 4 && register_size (gdbarch, regno) == 8
- && PT_FPSCR == (48 + 2*32 + 1))
- u_addr = (48 + 2*32) * wordsize;
- else
- u_addr = PT_FPSCR * wordsize;
- }
- return u_addr;
- }
- static void
- fetch_vsx_register (struct regcache *regcache, int tid, int regno)
- {
- int ret;
- gdb_vsxregset_t regs;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
- ret = ptrace (PTRACE_GETVSXREGS, tid, 0, ®s);
- if (ret < 0)
- {
- if (errno == EIO)
- {
- have_ptrace_getsetvsxregs = 0;
- return;
- }
- perror_with_name (_("Unable to fetch VSX register"));
- }
- regcache_raw_supply (regcache, regno,
- regs + (regno - tdep->ppc_vsr0_upper_regnum)
- * vsxregsize);
- }
- static void
- fetch_altivec_register (struct regcache *regcache, int tid, int regno)
- {
- int ret;
- int offset = 0;
- gdb_vrregset_t regs;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- int vrregsize = register_size (gdbarch, tdep->ppc_vr0_regnum);
- ret = ptrace (PTRACE_GETVRREGS, tid, 0, ®s);
- if (ret < 0)
- {
- if (errno == EIO)
- {
- have_ptrace_getvrregs = 0;
- return;
- }
- perror_with_name (_("Unable to fetch AltiVec register"));
- }
-
- if (regno == (tdep->ppc_vrsave_regnum - 1))
- offset = vrregsize - register_size (gdbarch, tdep->ppc_vrsave_regnum);
- regcache_raw_supply (regcache, regno,
- regs + (regno
- - tdep->ppc_vr0_regnum) * vrregsize + offset);
- }
- static void
- get_spe_registers (int tid, struct gdb_evrregset_t *evrregset)
- {
- if (have_ptrace_getsetevrregs)
- {
- if (ptrace (PTRACE_GETEVRREGS, tid, 0, evrregset) >= 0)
- return;
- else
- {
-
- if (errno == EIO)
- have_ptrace_getsetevrregs = 0;
- else
-
- perror_with_name (_("Unable to fetch SPE registers"));
- }
- }
- memset (evrregset, 0, sizeof (*evrregset));
- }
- static void
- fetch_spe_register (struct regcache *regcache, int tid, int regno)
- {
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- struct gdb_evrregset_t evrregs;
- gdb_assert (sizeof (evrregs.evr[0])
- == register_size (gdbarch, tdep->ppc_ev0_upper_regnum));
- gdb_assert (sizeof (evrregs.acc)
- == register_size (gdbarch, tdep->ppc_acc_regnum));
- gdb_assert (sizeof (evrregs.spefscr)
- == register_size (gdbarch, tdep->ppc_spefscr_regnum));
- get_spe_registers (tid, &evrregs);
- if (regno == -1)
- {
- int i;
- for (i = 0; i < ppc_num_gprs; i++)
- regcache_raw_supply (regcache, tdep->ppc_ev0_upper_regnum + i,
- &evrregs.evr[i]);
- }
- else if (tdep->ppc_ev0_upper_regnum <= regno
- && regno < tdep->ppc_ev0_upper_regnum + ppc_num_gprs)
- regcache_raw_supply (regcache, regno,
- &evrregs.evr[regno - tdep->ppc_ev0_upper_regnum]);
- if (regno == -1
- || regno == tdep->ppc_acc_regnum)
- regcache_raw_supply (regcache, tdep->ppc_acc_regnum, &evrregs.acc);
- if (regno == -1
- || regno == tdep->ppc_spefscr_regnum)
- regcache_raw_supply (regcache, tdep->ppc_spefscr_regnum,
- &evrregs.spefscr);
- }
- static void
- fetch_register (struct regcache *regcache, int tid, int regno)
- {
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-
- CORE_ADDR regaddr = ppc_register_u_addr (gdbarch, regno);
- int bytes_transferred;
- unsigned int offset;
- gdb_byte buf[MAX_REGISTER_SIZE];
- if (altivec_register_p (gdbarch, regno))
- {
-
- if (have_ptrace_getvrregs)
- {
- fetch_altivec_register (regcache, tid, regno);
- return;
- }
-
- }
- if (vsx_register_p (gdbarch, regno))
- {
- if (have_ptrace_getsetvsxregs)
- {
- fetch_vsx_register (regcache, tid, regno);
- return;
- }
- }
- else if (spe_register_p (gdbarch, regno))
- {
- fetch_spe_register (regcache, tid, regno);
- return;
- }
- if (regaddr == -1)
- {
- memset (buf, '\0', register_size (gdbarch, regno));
- regcache_raw_supply (regcache, regno, buf);
- return;
- }
-
- for (bytes_transferred = 0;
- bytes_transferred < register_size (gdbarch, regno);
- bytes_transferred += sizeof (long))
- {
- long l;
- errno = 0;
- l = ptrace (PTRACE_PEEKUSER, tid, (PTRACE_TYPE_ARG3) regaddr, 0);
- regaddr += sizeof (long);
- if (errno != 0)
- {
- char message[128];
- xsnprintf (message, sizeof (message), "reading register %s (#%d)",
- gdbarch_register_name (gdbarch, regno), regno);
- perror_with_name (message);
- }
- memcpy (&buf[bytes_transferred], &l, sizeof (l));
- }
-
- if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
- {
-
- regcache_raw_supply (regcache, regno, buf);
- }
- else if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
- {
-
- size_t padding = (bytes_transferred - register_size (gdbarch, regno));
- regcache_raw_supply (regcache, regno, buf + padding);
- }
- else
- internal_error (__FILE__, __LINE__,
- _("fetch_register: unexpected byte order: %d"),
- gdbarch_byte_order (gdbarch));
- }
- static void
- supply_vsxregset (struct regcache *regcache, gdb_vsxregset_t *vsxregsetp)
- {
- int i;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
- for (i = 0; i < ppc_num_vshrs; i++)
- {
- regcache_raw_supply (regcache, tdep->ppc_vsr0_upper_regnum + i,
- *vsxregsetp + i * vsxregsize);
- }
- }
- static void
- supply_vrregset (struct regcache *regcache, gdb_vrregset_t *vrregsetp)
- {
- int i;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
- int vrregsize = register_size (gdbarch, tdep->ppc_vr0_regnum);
- int offset = vrregsize - register_size (gdbarch, tdep->ppc_vrsave_regnum);
- for (i = 0; i < num_of_vrregs; i++)
- {
-
- if (i == (num_of_vrregs - 2))
- regcache_raw_supply (regcache, tdep->ppc_vr0_regnum + i,
- *vrregsetp + i * vrregsize + offset);
- else
- regcache_raw_supply (regcache, tdep->ppc_vr0_regnum + i,
- *vrregsetp + i * vrregsize);
- }
- }
- static void
- fetch_vsx_registers (struct regcache *regcache, int tid)
- {
- int ret;
- gdb_vsxregset_t regs;
- ret = ptrace (PTRACE_GETVSXREGS, tid, 0, ®s);
- if (ret < 0)
- {
- if (errno == EIO)
- {
- have_ptrace_getsetvsxregs = 0;
- return;
- }
- perror_with_name (_("Unable to fetch VSX registers"));
- }
- supply_vsxregset (regcache, ®s);
- }
- static void
- fetch_altivec_registers (struct regcache *regcache, int tid)
- {
- int ret;
- gdb_vrregset_t regs;
- ret = ptrace (PTRACE_GETVRREGS, tid, 0, ®s);
- if (ret < 0)
- {
- if (errno == EIO)
- {
- have_ptrace_getvrregs = 0;
- return;
- }
- perror_with_name (_("Unable to fetch AltiVec registers"));
- }
- supply_vrregset (regcache, ®s);
- }
- static int
- fetch_all_gp_regs (struct regcache *regcache, int tid)
- {
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- gdb_gregset_t gregset;
- if (ptrace (PTRACE_GETREGS, tid, 0, (void *) &gregset) < 0)
- {
- if (errno == EIO)
- {
- have_ptrace_getsetregs = 0;
- return 0;
- }
- perror_with_name (_("Couldn't get general-purpose registers."));
- }
- supply_gregset (regcache, (const gdb_gregset_t *) &gregset);
- return 1;
- }
- static void
- fetch_gp_regs (struct regcache *regcache, int tid)
- {
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- int i;
- if (have_ptrace_getsetregs)
- if (fetch_all_gp_regs (regcache, tid))
- return;
-
- for (i = 0; i < ppc_num_gprs; i++)
- fetch_register (regcache, tid, tdep->ppc_gp0_regnum + i);
- }
- static int
- fetch_all_fp_regs (struct regcache *regcache, int tid)
- {
- gdb_fpregset_t fpregs;
- if (ptrace (PTRACE_GETFPREGS, tid, 0, (void *) &fpregs) < 0)
- {
- if (errno == EIO)
- {
- have_ptrace_getsetfpregs = 0;
- return 0;
- }
- perror_with_name (_("Couldn't get floating-point registers."));
- }
- supply_fpregset (regcache, (const gdb_fpregset_t *) &fpregs);
- return 1;
- }
- static void
- fetch_fp_regs (struct regcache *regcache, int tid)
- {
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- int i;
- if (have_ptrace_getsetfpregs)
- if (fetch_all_fp_regs (regcache, tid))
- return;
-
- for (i = 0; i < ppc_num_fprs; i++)
- fetch_register (regcache, tid, tdep->ppc_fp0_regnum + i);
- }
- static void
- fetch_ppc_registers (struct regcache *regcache, int tid)
- {
- int i;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- fetch_gp_regs (regcache, tid);
- if (tdep->ppc_fp0_regnum >= 0)
- fetch_fp_regs (regcache, tid);
- fetch_register (regcache, tid, gdbarch_pc_regnum (gdbarch));
- if (tdep->ppc_ps_regnum != -1)
- fetch_register (regcache, tid, tdep->ppc_ps_regnum);
- if (tdep->ppc_cr_regnum != -1)
- fetch_register (regcache, tid, tdep->ppc_cr_regnum);
- if (tdep->ppc_lr_regnum != -1)
- fetch_register (regcache, tid, tdep->ppc_lr_regnum);
- if (tdep->ppc_ctr_regnum != -1)
- fetch_register (regcache, tid, tdep->ppc_ctr_regnum);
- if (tdep->ppc_xer_regnum != -1)
- fetch_register (regcache, tid, tdep->ppc_xer_regnum);
- if (tdep->ppc_mq_regnum != -1)
- fetch_register (regcache, tid, tdep->ppc_mq_regnum);
- if (ppc_linux_trap_reg_p (gdbarch))
- {
- fetch_register (regcache, tid, PPC_ORIG_R3_REGNUM);
- fetch_register (regcache, tid, PPC_TRAP_REGNUM);
- }
- if (tdep->ppc_fpscr_regnum != -1)
- fetch_register (regcache, tid, tdep->ppc_fpscr_regnum);
- if (have_ptrace_getvrregs)
- if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
- fetch_altivec_registers (regcache, tid);
- if (have_ptrace_getsetvsxregs)
- if (tdep->ppc_vsr0_upper_regnum != -1)
- fetch_vsx_registers (regcache, tid);
- if (tdep->ppc_ev0_upper_regnum >= 0)
- fetch_spe_register (regcache, tid, -1);
- }
- static void
- ppc_linux_fetch_inferior_registers (struct target_ops *ops,
- struct regcache *regcache, int regno)
- {
-
- int tid = ptid_get_lwp (inferior_ptid);
-
- if (tid == 0)
- tid = ptid_get_pid (inferior_ptid);
- if (regno == -1)
- fetch_ppc_registers (regcache, tid);
- else
- fetch_register (regcache, tid, regno);
- }
- static void
- store_vsx_register (const struct regcache *regcache, int tid, int regno)
- {
- int ret;
- gdb_vsxregset_t regs;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
- ret = ptrace (PTRACE_GETVSXREGS, tid, 0, ®s);
- if (ret < 0)
- {
- if (errno == EIO)
- {
- have_ptrace_getsetvsxregs = 0;
- return;
- }
- perror_with_name (_("Unable to fetch VSX register"));
- }
- regcache_raw_collect (regcache, regno, regs +
- (regno - tdep->ppc_vsr0_upper_regnum) * vsxregsize);
- ret = ptrace (PTRACE_SETVSXREGS, tid, 0, ®s);
- if (ret < 0)
- perror_with_name (_("Unable to store VSX register"));
- }
- static void
- store_altivec_register (const struct regcache *regcache, int tid, int regno)
- {
- int ret;
- int offset = 0;
- gdb_vrregset_t regs;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- int vrregsize = register_size (gdbarch, tdep->ppc_vr0_regnum);
- ret = ptrace (PTRACE_GETVRREGS, tid, 0, ®s);
- if (ret < 0)
- {
- if (errno == EIO)
- {
- have_ptrace_getvrregs = 0;
- return;
- }
- perror_with_name (_("Unable to fetch AltiVec register"));
- }
-
- if (regno == (tdep->ppc_vrsave_regnum - 1))
- offset = vrregsize - register_size (gdbarch, tdep->ppc_vrsave_regnum);
- regcache_raw_collect (regcache, regno,
- regs + (regno
- - tdep->ppc_vr0_regnum) * vrregsize + offset);
- ret = ptrace (PTRACE_SETVRREGS, tid, 0, ®s);
- if (ret < 0)
- perror_with_name (_("Unable to store AltiVec register"));
- }
- static void
- set_spe_registers (int tid, struct gdb_evrregset_t *evrregset)
- {
- if (have_ptrace_getsetevrregs)
- {
- if (ptrace (PTRACE_SETEVRREGS, tid, 0, evrregset) >= 0)
- return;
- else
- {
-
- if (errno == EIO)
- have_ptrace_getsetevrregs = 0;
- else
-
- perror_with_name (_("Unable to set SPE registers"));
- }
- }
- }
- static void
- store_spe_register (const struct regcache *regcache, int tid, int regno)
- {
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- struct gdb_evrregset_t evrregs;
- gdb_assert (sizeof (evrregs.evr[0])
- == register_size (gdbarch, tdep->ppc_ev0_upper_regnum));
- gdb_assert (sizeof (evrregs.acc)
- == register_size (gdbarch, tdep->ppc_acc_regnum));
- gdb_assert (sizeof (evrregs.spefscr)
- == register_size (gdbarch, tdep->ppc_spefscr_regnum));
- if (regno == -1)
-
- memset (&evrregs, 42, sizeof (evrregs));
- else
-
- get_spe_registers (tid, &evrregs);
- if (regno == -1)
- {
- int i;
- for (i = 0; i < ppc_num_gprs; i++)
- regcache_raw_collect (regcache,
- tdep->ppc_ev0_upper_regnum + i,
- &evrregs.evr[i]);
- }
- else if (tdep->ppc_ev0_upper_regnum <= regno
- && regno < tdep->ppc_ev0_upper_regnum + ppc_num_gprs)
- regcache_raw_collect (regcache, regno,
- &evrregs.evr[regno - tdep->ppc_ev0_upper_regnum]);
- if (regno == -1
- || regno == tdep->ppc_acc_regnum)
- regcache_raw_collect (regcache,
- tdep->ppc_acc_regnum,
- &evrregs.acc);
- if (regno == -1
- || regno == tdep->ppc_spefscr_regnum)
- regcache_raw_collect (regcache,
- tdep->ppc_spefscr_regnum,
- &evrregs.spefscr);
-
- set_spe_registers (tid, &evrregs);
- }
- static void
- store_register (const struct regcache *regcache, int tid, int regno)
- {
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
-
- CORE_ADDR regaddr = ppc_register_u_addr (gdbarch, regno);
- int i;
- size_t bytes_to_transfer;
- gdb_byte buf[MAX_REGISTER_SIZE];
- if (altivec_register_p (gdbarch, regno))
- {
- store_altivec_register (regcache, tid, regno);
- return;
- }
- if (vsx_register_p (gdbarch, regno))
- {
- store_vsx_register (regcache, tid, regno);
- return;
- }
- else if (spe_register_p (gdbarch, regno))
- {
- store_spe_register (regcache, tid, regno);
- return;
- }
- if (regaddr == -1)
- return;
-
- memset (buf, 0, sizeof buf);
- bytes_to_transfer = align_up (register_size (gdbarch, regno), sizeof (long));
- if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_LITTLE)
- {
-
- regcache_raw_collect (regcache, regno, buf);
- }
- else if (gdbarch_byte_order (gdbarch) == BFD_ENDIAN_BIG)
- {
-
- size_t padding = (bytes_to_transfer - register_size (gdbarch, regno));
- regcache_raw_collect (regcache, regno, buf + padding);
- }
- for (i = 0; i < bytes_to_transfer; i += sizeof (long))
- {
- long l;
- memcpy (&l, &buf[i], sizeof (l));
- errno = 0;
- ptrace (PTRACE_POKEUSER, tid, (PTRACE_TYPE_ARG3) regaddr, l);
- regaddr += sizeof (long);
- if (errno == EIO
- && (regno == tdep->ppc_fpscr_regnum
- || regno == PPC_ORIG_R3_REGNUM
- || regno == PPC_TRAP_REGNUM))
- {
-
- continue;
- }
- if (errno != 0)
- {
- char message[128];
- xsnprintf (message, sizeof (message), "writing register %s (#%d)",
- gdbarch_register_name (gdbarch, regno), regno);
- perror_with_name (message);
- }
- }
- }
- static void
- fill_vsxregset (const struct regcache *regcache, gdb_vsxregset_t *vsxregsetp)
- {
- int i;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- int vsxregsize = register_size (gdbarch, tdep->ppc_vsr0_upper_regnum);
- for (i = 0; i < ppc_num_vshrs; i++)
- regcache_raw_collect (regcache, tdep->ppc_vsr0_upper_regnum + i,
- *vsxregsetp + i * vsxregsize);
- }
- static void
- fill_vrregset (const struct regcache *regcache, gdb_vrregset_t *vrregsetp)
- {
- int i;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- int num_of_vrregs = tdep->ppc_vrsave_regnum - tdep->ppc_vr0_regnum + 1;
- int vrregsize = register_size (gdbarch, tdep->ppc_vr0_regnum);
- int offset = vrregsize - register_size (gdbarch, tdep->ppc_vrsave_regnum);
- for (i = 0; i < num_of_vrregs; i++)
- {
-
- if (i == (num_of_vrregs - 2))
- regcache_raw_collect (regcache, tdep->ppc_vr0_regnum + i,
- *vrregsetp + i * vrregsize + offset);
- else
- regcache_raw_collect (regcache, tdep->ppc_vr0_regnum + i,
- *vrregsetp + i * vrregsize);
- }
- }
- static void
- store_vsx_registers (const struct regcache *regcache, int tid)
- {
- int ret;
- gdb_vsxregset_t regs;
- ret = ptrace (PTRACE_GETVSXREGS, tid, 0, ®s);
- if (ret < 0)
- {
- if (errno == EIO)
- {
- have_ptrace_getsetvsxregs = 0;
- return;
- }
- perror_with_name (_("Couldn't get VSX registers"));
- }
- fill_vsxregset (regcache, ®s);
- if (ptrace (PTRACE_SETVSXREGS, tid, 0, ®s) < 0)
- perror_with_name (_("Couldn't write VSX registers"));
- }
- static void
- store_altivec_registers (const struct regcache *regcache, int tid)
- {
- int ret;
- gdb_vrregset_t regs;
- ret = ptrace (PTRACE_GETVRREGS, tid, 0, ®s);
- if (ret < 0)
- {
- if (errno == EIO)
- {
- have_ptrace_getvrregs = 0;
- return;
- }
- perror_with_name (_("Couldn't get AltiVec registers"));
- }
- fill_vrregset (regcache, ®s);
- if (ptrace (PTRACE_SETVRREGS, tid, 0, ®s) < 0)
- perror_with_name (_("Couldn't write AltiVec registers"));
- }
- static int
- store_all_gp_regs (const struct regcache *regcache, int tid, int regno)
- {
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- gdb_gregset_t gregset;
- if (ptrace (PTRACE_GETREGS, tid, 0, (void *) &gregset) < 0)
- {
- if (errno == EIO)
- {
- have_ptrace_getsetregs = 0;
- return 0;
- }
- perror_with_name (_("Couldn't get general-purpose registers."));
- }
- fill_gregset (regcache, &gregset, regno);
- if (ptrace (PTRACE_SETREGS, tid, 0, (void *) &gregset) < 0)
- {
- if (errno == EIO)
- {
- have_ptrace_getsetregs = 0;
- return 0;
- }
- perror_with_name (_("Couldn't set general-purpose registers."));
- }
- return 1;
- }
- static void
- store_gp_regs (const struct regcache *regcache, int tid, int regno)
- {
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- int i;
- if (have_ptrace_getsetregs)
- if (store_all_gp_regs (regcache, tid, regno))
- return;
-
- for (i = 0; i < ppc_num_gprs; i++)
- store_register (regcache, tid, tdep->ppc_gp0_regnum + i);
- }
- static int
- store_all_fp_regs (const struct regcache *regcache, int tid, int regno)
- {
- gdb_fpregset_t fpregs;
- if (ptrace (PTRACE_GETFPREGS, tid, 0, (void *) &fpregs) < 0)
- {
- if (errno == EIO)
- {
- have_ptrace_getsetfpregs = 0;
- return 0;
- }
- perror_with_name (_("Couldn't get floating-point registers."));
- }
- fill_fpregset (regcache, &fpregs, regno);
- if (ptrace (PTRACE_SETFPREGS, tid, 0, (void *) &fpregs) < 0)
- {
- if (errno == EIO)
- {
- have_ptrace_getsetfpregs = 0;
- return 0;
- }
- perror_with_name (_("Couldn't set floating-point registers."));
- }
- return 1;
- }
- static void
- store_fp_regs (const struct regcache *regcache, int tid, int regno)
- {
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- int i;
- if (have_ptrace_getsetfpregs)
- if (store_all_fp_regs (regcache, tid, regno))
- return;
-
- for (i = 0; i < ppc_num_fprs; i++)
- store_register (regcache, tid, tdep->ppc_fp0_regnum + i);
- }
- static void
- store_ppc_registers (const struct regcache *regcache, int tid)
- {
- int i;
- struct gdbarch *gdbarch = get_regcache_arch (regcache);
- struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- store_gp_regs (regcache, tid, -1);
- if (tdep->ppc_fp0_regnum >= 0)
- store_fp_regs (regcache, tid, -1);
- store_register (regcache, tid, gdbarch_pc_regnum (gdbarch));
- if (tdep->ppc_ps_regnum != -1)
- store_register (regcache, tid, tdep->ppc_ps_regnum);
- if (tdep->ppc_cr_regnum != -1)
- store_register (regcache, tid, tdep->ppc_cr_regnum);
- if (tdep->ppc_lr_regnum != -1)
- store_register (regcache, tid, tdep->ppc_lr_regnum);
- if (tdep->ppc_ctr_regnum != -1)
- store_register (regcache, tid, tdep->ppc_ctr_regnum);
- if (tdep->ppc_xer_regnum != -1)
- store_register (regcache, tid, tdep->ppc_xer_regnum);
- if (tdep->ppc_mq_regnum != -1)
- store_register (regcache, tid, tdep->ppc_mq_regnum);
- if (tdep->ppc_fpscr_regnum != -1)
- store_register (regcache, tid, tdep->ppc_fpscr_regnum);
- if (ppc_linux_trap_reg_p (gdbarch))
- {
- store_register (regcache, tid, PPC_ORIG_R3_REGNUM);
- store_register (regcache, tid, PPC_TRAP_REGNUM);
- }
- if (have_ptrace_getvrregs)
- if (tdep->ppc_vr0_regnum != -1 && tdep->ppc_vrsave_regnum != -1)
- store_altivec_registers (regcache, tid);
- if (have_ptrace_getsetvsxregs)
- if (tdep->ppc_vsr0_upper_regnum != -1)
- store_vsx_registers (regcache, tid);
- if (tdep->ppc_ev0_upper_regnum >= 0)
- store_spe_register (regcache, tid, -1);
- }
- static unsigned long
- ppc_linux_get_hwcap (void)
- {
- CORE_ADDR field;
- if (target_auxv_search (¤t_target, AT_HWCAP, &field))
- return (unsigned long) field;
- return 0;
- }
- static long saved_dabr_value;
- static struct ppc_debug_info hwdebug_info;
- static size_t max_slots_number = 0;
- struct hw_break_tuple
- {
- long slot;
- struct ppc_hw_breakpoint *hw_break;
- };
- typedef struct thread_points
- {
-
- int tid;
-
- struct hw_break_tuple *hw_breaks;
- } *thread_points_p;
- DEF_VEC_P (thread_points_p);
- VEC(thread_points_p) *ppc_threads = NULL;
- #define PPC_DEBUG_CURRENT_VERSION 1
- static int
- have_ptrace_hwdebug_interface (void)
- {
- static int have_ptrace_hwdebug_interface = -1;
- if (have_ptrace_hwdebug_interface == -1)
- {
- int tid;
- tid = ptid_get_lwp (inferior_ptid);
- if (tid == 0)
- tid = ptid_get_pid (inferior_ptid);
-
- if (ptrace (PPC_PTRACE_GETHWDBGINFO, tid, 0, &hwdebug_info) >= 0)
- {
-
- if (hwdebug_info.features != 0)
- {
- have_ptrace_hwdebug_interface = 1;
- max_slots_number = hwdebug_info.num_instruction_bps
- + hwdebug_info.num_data_bps
- + hwdebug_info.num_condition_regs;
- return have_ptrace_hwdebug_interface;
- }
- }
-
- have_ptrace_hwdebug_interface = 0;
- memset (&hwdebug_info, 0, sizeof (struct ppc_debug_info));
- }
- return have_ptrace_hwdebug_interface;
- }
- static int
- ppc_linux_can_use_hw_breakpoint (struct target_ops *self,
- int type, int cnt, int ot)
- {
- int total_hw_wp, total_hw_bp;
- if (have_ptrace_hwdebug_interface ())
- {
-
- total_hw_bp = hwdebug_info.num_instruction_bps;
- total_hw_wp = hwdebug_info.num_data_bps;
- }
- else
- {
-
- total_hw_bp = 0;
- total_hw_wp = 1;
- }
- if (type == bp_hardware_watchpoint || type == bp_read_watchpoint
- || type == bp_access_watchpoint || type == bp_watchpoint)
- {
- if (cnt + ot > total_hw_wp)
- return -1;
- }
- else if (type == bp_hardware_breakpoint)
- {
- if (total_hw_bp == 0)
- {
-
- return 0;
- }
- if (cnt > total_hw_bp)
- return -1;
- }
- if (!have_ptrace_hwdebug_interface ())
- {
- int tid;
- ptid_t ptid = inferior_ptid;
-
- tid = ptid_get_lwp (ptid);
- if (tid == 0)
- tid = ptid_get_pid (ptid);
- if (ptrace (PTRACE_SET_DEBUGREG, tid, 0, 0) == -1)
- return 0;
- }
- return 1;
- }
- static int
- ppc_linux_region_ok_for_hw_watchpoint (struct target_ops *self,
- CORE_ADDR addr, int len)
- {
-
- if (len <= 0)
- return 0;
-
- if (have_ptrace_hwdebug_interface ())
- {
- int region_size;
-
- if (len > 1
- && hwdebug_info.features & PPC_DEBUG_FEATURE_DATA_BP_RANGE
- && ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
- return 2;
-
- if (hwdebug_info.features & PPC_DEBUG_FEATURE_DATA_BP_DAWR)
-
- region_size = 512;
- else
- region_size = hwdebug_info.data_bp_alignment;
-
- if (region_size
- && (addr + len > (addr & ~(region_size - 1)) + region_size))
- return 0;
- }
-
- else if (((ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
- && (addr + len) > (addr & ~3) + 4)
- || (addr + len) > (addr & ~7) + 8)
- return 0;
- return 1;
- }
- static int
- hwdebug_point_cmp (struct ppc_hw_breakpoint *a, struct ppc_hw_breakpoint *b)
- {
- return (a->trigger_type == b->trigger_type
- && a->addr_mode == b->addr_mode
- && a->condition_mode == b->condition_mode
- && a->addr == b->addr
- && a->addr2 == b->addr2
- && a->condition_value == b->condition_value);
- }
- static struct thread_points *
- hwdebug_find_thread_points_by_tid (int tid, int alloc_new)
- {
- int i;
- struct thread_points *t;
- for (i = 0; VEC_iterate (thread_points_p, ppc_threads, i, t); i++)
- if (t->tid == tid)
- return t;
- t = NULL;
-
- if (alloc_new)
- {
- t = xmalloc (sizeof (struct thread_points));
- t->hw_breaks
- = xzalloc (max_slots_number * sizeof (struct hw_break_tuple));
- t->tid = tid;
- VEC_safe_push (thread_points_p, ppc_threads, t);
- }
- return t;
- }
- static void
- hwdebug_insert_point (struct ppc_hw_breakpoint *b, int tid)
- {
- int i;
- long slot;
- struct ppc_hw_breakpoint *p = xmalloc (sizeof (struct ppc_hw_breakpoint));
- struct hw_break_tuple *hw_breaks;
- struct cleanup *c = make_cleanup (xfree, p);
- struct thread_points *t;
- struct hw_break_tuple *tuple;
- memcpy (p, b, sizeof (struct ppc_hw_breakpoint));
- errno = 0;
- slot = ptrace (PPC_PTRACE_SETHWDEBUG, tid, 0, p);
- if (slot < 0)
- perror_with_name (_("Unexpected error setting breakpoint or watchpoint"));
-
- t = hwdebug_find_thread_points_by_tid (tid, 1);
- gdb_assert (t != NULL);
- hw_breaks = t->hw_breaks;
-
- for (i = 0; i < max_slots_number; i++)
- if (hw_breaks[i].hw_break == NULL)
- {
- hw_breaks[i].slot = slot;
- hw_breaks[i].hw_break = p;
- break;
- }
- gdb_assert (i != max_slots_number);
- discard_cleanups (c);
- }
- static void
- hwdebug_remove_point (struct ppc_hw_breakpoint *b, int tid)
- {
- int i;
- struct hw_break_tuple *hw_breaks;
- struct thread_points *t;
- t = hwdebug_find_thread_points_by_tid (tid, 0);
- gdb_assert (t != NULL);
- hw_breaks = t->hw_breaks;
- for (i = 0; i < max_slots_number; i++)
- if (hw_breaks[i].hw_break && hwdebug_point_cmp (hw_breaks[i].hw_break, b))
- break;
- gdb_assert (i != max_slots_number);
-
- errno = 0;
- if (ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot) < 0)
- if (errno != ENOENT)
- perror_with_name (_("Unexpected error deleting "
- "breakpoint or watchpoint"));
- xfree (hw_breaks[i].hw_break);
- hw_breaks[i].hw_break = NULL;
- }
- static int
- ppc_linux_ranged_break_num_registers (struct target_ops *target)
- {
- return ((have_ptrace_hwdebug_interface ()
- && hwdebug_info.features & PPC_DEBUG_FEATURE_INSN_BP_RANGE)?
- 2 : -1);
- }
- static int
- ppc_linux_insert_hw_breakpoint (struct target_ops *self,
- struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
- {
- struct lwp_info *lp;
- struct ppc_hw_breakpoint p;
- if (!have_ptrace_hwdebug_interface ())
- return -1;
- p.version = PPC_DEBUG_CURRENT_VERSION;
- p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
- p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
- p.addr = (uint64_t) (bp_tgt->placed_address = bp_tgt->reqstd_address);
- p.condition_value = 0;
- if (bp_tgt->length)
- {
- p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
-
- p.addr2 = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
- }
- else
- {
- p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
- p.addr2 = 0;
- }
- ALL_LWPS (lp)
- hwdebug_insert_point (&p, ptid_get_lwp (lp->ptid));
- return 0;
- }
- static int
- ppc_linux_remove_hw_breakpoint (struct target_ops *self,
- struct gdbarch *gdbarch,
- struct bp_target_info *bp_tgt)
- {
- struct lwp_info *lp;
- struct ppc_hw_breakpoint p;
- if (!have_ptrace_hwdebug_interface ())
- return -1;
- p.version = PPC_DEBUG_CURRENT_VERSION;
- p.trigger_type = PPC_BREAKPOINT_TRIGGER_EXECUTE;
- p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
- p.addr = (uint64_t) bp_tgt->placed_address;
- p.condition_value = 0;
- if (bp_tgt->length)
- {
- p.addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
-
- p.addr2 = (uint64_t) bp_tgt->placed_address + bp_tgt->length;
- }
- else
- {
- p.addr_mode = PPC_BREAKPOINT_MODE_EXACT;
- p.addr2 = 0;
- }
- ALL_LWPS (lp)
- hwdebug_remove_point (&p, ptid_get_lwp (lp->ptid));
- return 0;
- }
- static int
- get_trigger_type (int rw)
- {
- int t;
- if (rw == hw_read)
- t = PPC_BREAKPOINT_TRIGGER_READ;
- else if (rw == hw_write)
- t = PPC_BREAKPOINT_TRIGGER_WRITE;
- else
- t = PPC_BREAKPOINT_TRIGGER_READ | PPC_BREAKPOINT_TRIGGER_WRITE;
- return t;
- }
- static int
- ppc_linux_insert_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
- CORE_ADDR mask, int rw)
- {
- struct lwp_info *lp;
- struct ppc_hw_breakpoint p;
- gdb_assert (have_ptrace_hwdebug_interface ());
- p.version = PPC_DEBUG_CURRENT_VERSION;
- p.trigger_type = get_trigger_type (rw);
- p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
- p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
- p.addr = addr;
- p.addr2 = mask;
- p.condition_value = 0;
- ALL_LWPS (lp)
- hwdebug_insert_point (&p, ptid_get_lwp (lp->ptid));
- return 0;
- }
- static int
- ppc_linux_remove_mask_watchpoint (struct target_ops *ops, CORE_ADDR addr,
- CORE_ADDR mask, int rw)
- {
- struct lwp_info *lp;
- struct ppc_hw_breakpoint p;
- gdb_assert (have_ptrace_hwdebug_interface ());
- p.version = PPC_DEBUG_CURRENT_VERSION;
- p.trigger_type = get_trigger_type (rw);
- p.addr_mode = PPC_BREAKPOINT_MODE_MASK;
- p.condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
- p.addr = addr;
- p.addr2 = mask;
- p.condition_value = 0;
- ALL_LWPS (lp)
- hwdebug_remove_point (&p, ptid_get_lwp (lp->ptid));
- return 0;
- }
- static int
- can_use_watchpoint_cond_accel (void)
- {
- struct thread_points *p;
- int tid = ptid_get_lwp (inferior_ptid);
- int cnt = hwdebug_info.num_condition_regs, i;
- CORE_ADDR tmp_value;
- if (!have_ptrace_hwdebug_interface () || cnt == 0)
- return 0;
- p = hwdebug_find_thread_points_by_tid (tid, 0);
- if (p)
- {
- for (i = 0; i < max_slots_number; i++)
- if (p->hw_breaks[i].hw_break != NULL
- && (p->hw_breaks[i].hw_break->condition_mode
- != PPC_BREAKPOINT_CONDITION_NONE))
- cnt--;
-
- if (cnt <= 0)
- return 0;
- }
- return 1;
- }
- static void
- calculate_dvc (CORE_ADDR addr, int len, CORE_ADDR data_value,
- uint32_t *condition_mode, uint64_t *condition_value)
- {
- int i, num_byte_enable, align_offset, num_bytes_off_dvc,
- rightmost_enabled_byte;
- CORE_ADDR addr_end_data, addr_end_dvc;
-
- align_offset = addr % hwdebug_info.sizeof_condition;
- addr_end_data = addr + len;
- addr_end_dvc = (addr - align_offset
- + hwdebug_info.sizeof_condition);
- num_bytes_off_dvc = (addr_end_data > addr_end_dvc)?
- addr_end_data - addr_end_dvc : 0;
- num_byte_enable = len - num_bytes_off_dvc;
-
- rightmost_enabled_byte = (addr_end_data < addr_end_dvc)?
- addr_end_dvc - addr_end_data : 0;
- *condition_mode = PPC_BREAKPOINT_CONDITION_AND;
- for (i = 0; i < num_byte_enable; i++)
- *condition_mode
- |= PPC_BREAKPOINT_CONDITION_BE (i + rightmost_enabled_byte);
-
- *condition_value = ((uint64_t) data_value >> num_bytes_off_dvc * 8
- << rightmost_enabled_byte * 8);
- }
- static int
- num_memory_accesses (struct value *v)
- {
- int found_memory_cnt = 0;
- struct value *head = v;
-
- FIXME
- for (; v; v = value_next (v))
- {
-
- if (VALUE_LVAL (v) == not_lval || deprecated_value_modifiable (v) == 0)
- continue;
- else if (VALUE_LVAL (v) == lval_memory)
- {
-
- if (!value_lazy (v))
- found_memory_cnt++;
- }
-
- else
- return -1;
- }
- return found_memory_cnt;
- }
- static int
- check_condition (CORE_ADDR watch_addr, struct expression *cond,
- CORE_ADDR *data_value, int *len)
- {
- int pc = 1, num_accesses_left, num_accesses_right;
- struct value *left_val, *right_val, *left_chain, *right_chain;
- if (cond->elts[0].opcode != BINOP_EQUAL)
- return 0;
- fetch_subexp_value (cond, &pc, &left_val, NULL, &left_chain, 0);
- num_accesses_left = num_memory_accesses (left_chain);
- if (left_val == NULL || num_accesses_left < 0)
- {
- free_value_chain (left_chain);
- return 0;
- }
- fetch_subexp_value (cond, &pc, &right_val, NULL, &right_chain, 0);
- num_accesses_right = num_memory_accesses (right_chain);
- if (right_val == NULL || num_accesses_right < 0)
- {
- free_value_chain (left_chain);
- free_value_chain (right_chain);
- return 0;
- }
- if (num_accesses_left == 1 && num_accesses_right == 0
- && VALUE_LVAL (left_val) == lval_memory
- && value_address (left_val) == watch_addr)
- {
- *data_value = value_as_long (right_val);
-
- *len = TYPE_LENGTH (check_typedef (value_type (left_val)));
- }
- else if (num_accesses_left == 0 && num_accesses_right == 1
- && VALUE_LVAL (right_val) == lval_memory
- && value_address (right_val) == watch_addr)
- {
- *data_value = value_as_long (left_val);
-
- *len = TYPE_LENGTH (check_typedef (value_type (right_val)));
- }
- else
- {
- free_value_chain (left_chain);
- free_value_chain (right_chain);
- return 0;
- }
- free_value_chain (left_chain);
- free_value_chain (right_chain);
- return 1;
- }
- static int
- ppc_linux_can_accel_watchpoint_condition (struct target_ops *self,
- CORE_ADDR addr, int len, int rw,
- struct expression *cond)
- {
- CORE_ADDR data_value;
- return (have_ptrace_hwdebug_interface ()
- && hwdebug_info.num_condition_regs > 0
- && check_condition (addr, cond, &data_value, &len));
- }
- static void
- create_watchpoint_request (struct ppc_hw_breakpoint *p, CORE_ADDR addr,
- int len, int rw, struct expression *cond,
- int insert)
- {
- if (len == 1
- || !(hwdebug_info.features & PPC_DEBUG_FEATURE_DATA_BP_RANGE))
- {
- int use_condition;
- CORE_ADDR data_value;
- use_condition = (insert? can_use_watchpoint_cond_accel ()
- : hwdebug_info.num_condition_regs > 0);
- if (cond && use_condition && check_condition (addr, cond,
- &data_value, &len))
- calculate_dvc (addr, len, data_value, &p->condition_mode,
- &p->condition_value);
- else
- {
- p->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
- p->condition_value = 0;
- }
- p->addr_mode = PPC_BREAKPOINT_MODE_EXACT;
- p->addr2 = 0;
- }
- else
- {
- p->addr_mode = PPC_BREAKPOINT_MODE_RANGE_INCLUSIVE;
- p->condition_mode = PPC_BREAKPOINT_CONDITION_NONE;
- p->condition_value = 0;
-
- p->addr2 = (uint64_t) addr + len;
- }
- p->version = PPC_DEBUG_CURRENT_VERSION;
- p->trigger_type = get_trigger_type (rw);
- p->addr = (uint64_t) addr;
- }
- static int
- ppc_linux_insert_watchpoint (struct target_ops *self,
- CORE_ADDR addr, int len, int rw,
- struct expression *cond)
- {
- struct lwp_info *lp;
- int ret = -1;
- if (have_ptrace_hwdebug_interface ())
- {
- struct ppc_hw_breakpoint p;
- create_watchpoint_request (&p, addr, len, rw, cond, 1);
- ALL_LWPS (lp)
- hwdebug_insert_point (&p, ptid_get_lwp (lp->ptid));
- ret = 0;
- }
- else
- {
- long dabr_value;
- long read_mode, write_mode;
- if (ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
- {
-
- read_mode = 1;
- write_mode = 2;
- }
- else
- {
-
- read_mode = 5;
- write_mode = 6;
- }
- dabr_value = addr & ~(read_mode | write_mode);
- switch (rw)
- {
- case hw_read:
-
- dabr_value |= read_mode;
- break;
- case hw_write:
-
- dabr_value |= write_mode;
- break;
- case hw_access:
-
- dabr_value |= read_mode | write_mode;
- break;
- }
- saved_dabr_value = dabr_value;
- ALL_LWPS (lp)
- if (ptrace (PTRACE_SET_DEBUGREG, ptid_get_lwp (lp->ptid), 0,
- saved_dabr_value) < 0)
- return -1;
- ret = 0;
- }
- return ret;
- }
- static int
- ppc_linux_remove_watchpoint (struct target_ops *self,
- CORE_ADDR addr, int len, int rw,
- struct expression *cond)
- {
- struct lwp_info *lp;
- int ret = -1;
- if (have_ptrace_hwdebug_interface ())
- {
- struct ppc_hw_breakpoint p;
- create_watchpoint_request (&p, addr, len, rw, cond, 0);
- ALL_LWPS (lp)
- hwdebug_remove_point (&p, ptid_get_lwp (lp->ptid));
- ret = 0;
- }
- else
- {
- saved_dabr_value = 0;
- ALL_LWPS (lp)
- if (ptrace (PTRACE_SET_DEBUGREG, ptid_get_lwp (lp->ptid), 0,
- saved_dabr_value) < 0)
- return -1;
- ret = 0;
- }
- return ret;
- }
- static void
- ppc_linux_new_thread (struct lwp_info *lp)
- {
- int tid = ptid_get_lwp (lp->ptid);
- if (have_ptrace_hwdebug_interface ())
- {
- int i;
- struct thread_points *p;
- struct hw_break_tuple *hw_breaks;
- if (VEC_empty (thread_points_p, ppc_threads))
- return;
-
- p = VEC_last (thread_points_p, ppc_threads);
- hw_breaks = p->hw_breaks;
-
- for (i = 0; i < max_slots_number; i++)
- if (hw_breaks[i].hw_break)
- {
-
-
- ptrace (PPC_PTRACE_DELHWDEBUG, tid, 0, hw_breaks[i].slot);
- hwdebug_insert_point (hw_breaks[i].hw_break, tid);
- }
- }
- else
- ptrace (PTRACE_SET_DEBUGREG, tid, 0, saved_dabr_value);
- }
- static void
- ppc_linux_thread_exit (struct thread_info *tp, int silent)
- {
- int i;
- int tid = ptid_get_lwp (tp->ptid);
- struct hw_break_tuple *hw_breaks;
- struct thread_points *t = NULL, *p;
- if (!have_ptrace_hwdebug_interface ())
- return;
- for (i = 0; VEC_iterate (thread_points_p, ppc_threads, i, p); i++)
- if (p->tid == tid)
- {
- t = p;
- break;
- }
- if (t == NULL)
- return;
- VEC_unordered_remove (thread_points_p, ppc_threads, i);
- hw_breaks = t->hw_breaks;
- for (i = 0; i < max_slots_number; i++)
- if (hw_breaks[i].hw_break)
- xfree (hw_breaks[i].hw_break);
- xfree (t->hw_breaks);
- xfree (t);
- }
- static int
- ppc_linux_stopped_data_address (struct target_ops *target, CORE_ADDR *addr_p)
- {
- siginfo_t siginfo;
- if (!linux_nat_get_siginfo (inferior_ptid, &siginfo))
- return 0;
- if (siginfo.si_signo != SIGTRAP
- || (siginfo.si_code & 0xffff) != 0x0004 )
- return 0;
- if (have_ptrace_hwdebug_interface ())
- {
- int i;
- struct thread_points *t;
- struct hw_break_tuple *hw_breaks;
-
- int slot = siginfo.si_errno;
- t = hwdebug_find_thread_points_by_tid (ptid_get_lwp (inferior_ptid), 0);
-
- if (t)
- {
- hw_breaks = t->hw_breaks;
- for (i = 0; i < max_slots_number; i++)
- if (hw_breaks[i].hw_break && hw_breaks[i].slot == slot
- && hw_breaks[i].hw_break->trigger_type
- == PPC_BREAKPOINT_TRIGGER_EXECUTE)
- return 0;
- }
- }
- *addr_p = (CORE_ADDR) (uintptr_t) siginfo.si_addr;
- return 1;
- }
- static int
- ppc_linux_stopped_by_watchpoint (struct target_ops *ops)
- {
- CORE_ADDR addr;
- return ppc_linux_stopped_data_address (ops, &addr);
- }
- static int
- ppc_linux_watchpoint_addr_within_range (struct target_ops *target,
- CORE_ADDR addr,
- CORE_ADDR start, int length)
- {
- int mask;
- if (have_ptrace_hwdebug_interface ()
- && ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
- return start <= addr && start + length >= addr;
- else if (ppc_linux_get_hwcap () & PPC_FEATURE_BOOKE)
- mask = 3;
- else
- mask = 7;
- addr &= ~mask;
-
- return start <= addr + mask && start + length - 1 >= addr;
- }
- static int
- ppc_linux_masked_watch_num_registers (struct target_ops *target,
- CORE_ADDR addr, CORE_ADDR mask)
- {
- if (!have_ptrace_hwdebug_interface ()
- || (hwdebug_info.features & PPC_DEBUG_FEATURE_DATA_BP_MASK) == 0)
- return -1;
- else if ((mask & 0xC0000000) != 0xC0000000)
- {
- warning (_("The given mask covers kernel address space "
- "and cannot be used.\n"));
- return -2;
- }
- else
- return 2;
- }
- static void
- ppc_linux_store_inferior_registers (struct target_ops *ops,
- struct regcache *regcache, int regno)
- {
-
- int tid = ptid_get_lwp (inferior_ptid);
-
- if (tid == 0)
- tid = ptid_get_pid (inferior_ptid);
- if (regno >= 0)
- store_register (regcache, tid, regno);
- else
- store_ppc_registers (regcache, tid);
- }
- void
- supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
- {
- const struct regset *regset = ppc_linux_gregset (sizeof (long));
- ppc_supply_gregset (regset, regcache, -1, gregsetp, sizeof (*gregsetp));
- }
- void
- fill_gregset (const struct regcache *regcache,
- gdb_gregset_t *gregsetp, int regno)
- {
- const struct regset *regset = ppc_linux_gregset (sizeof (long));
- if (regno == -1)
- memset (gregsetp, 0, sizeof (*gregsetp));
- ppc_collect_gregset (regset, regcache, regno, gregsetp, sizeof (*gregsetp));
- }
- void
- supply_fpregset (struct regcache *regcache, const gdb_fpregset_t * fpregsetp)
- {
- const struct regset *regset = ppc_linux_fpregset ();
- ppc_supply_fpregset (regset, regcache, -1,
- fpregsetp, sizeof (*fpregsetp));
- }
- void
- fill_fpregset (const struct regcache *regcache,
- gdb_fpregset_t *fpregsetp, int regno)
- {
- const struct regset *regset = ppc_linux_fpregset ();
- ppc_collect_fpregset (regset, regcache, regno,
- fpregsetp, sizeof (*fpregsetp));
- }
- static int
- ppc_linux_target_wordsize (void)
- {
- int wordsize = 4;
-
- #ifdef __powerpc64__
- long msr;
- int tid = ptid_get_lwp (inferior_ptid);
- if (tid == 0)
- tid = ptid_get_pid (inferior_ptid);
- errno = 0;
- msr = (long) ptrace (PTRACE_PEEKUSER, tid, PT_MSR * 8, 0);
- if (errno == 0 && msr < 0)
- wordsize = 8;
- #endif
- return wordsize;
- }
- static int
- ppc_linux_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
- gdb_byte *endptr, CORE_ADDR *typep, CORE_ADDR *valp)
- {
- int sizeof_auxv_field = ppc_linux_target_wordsize ();
- enum bfd_endian byte_order = gdbarch_byte_order (target_gdbarch ());
- gdb_byte *ptr = *readptr;
- if (endptr == ptr)
- return 0;
- if (endptr - ptr < sizeof_auxv_field * 2)
- return -1;
- *typep = extract_unsigned_integer (ptr, sizeof_auxv_field, byte_order);
- ptr += sizeof_auxv_field;
- *valp = extract_unsigned_integer (ptr, sizeof_auxv_field, byte_order);
- ptr += sizeof_auxv_field;
- *readptr = ptr;
- return 1;
- }
- static const struct target_desc *
- ppc_linux_read_description (struct target_ops *ops)
- {
- int altivec = 0;
- int vsx = 0;
- int isa205 = 0;
- int cell = 0;
- int tid = ptid_get_lwp (inferior_ptid);
- if (tid == 0)
- tid = ptid_get_pid (inferior_ptid);
- if (have_ptrace_getsetevrregs)
- {
- struct gdb_evrregset_t evrregset;
- if (ptrace (PTRACE_GETEVRREGS, tid, 0, &evrregset) >= 0)
- return tdesc_powerpc_e500l;
-
- else if (errno != EIO)
- perror_with_name (_("Unable to fetch SPE registers"));
- }
- if (have_ptrace_getsetvsxregs)
- {
- gdb_vsxregset_t vsxregset;
- if (ptrace (PTRACE_GETVSXREGS, tid, 0, &vsxregset) >= 0)
- vsx = 1;
-
- else if (errno != EIO)
- perror_with_name (_("Unable to fetch VSX registers"));
- }
- if (have_ptrace_getvrregs)
- {
- gdb_vrregset_t vrregset;
- if (ptrace (PTRACE_GETVRREGS, tid, 0, &vrregset) >= 0)
- altivec = 1;
-
- else if (errno != EIO)
- perror_with_name (_("Unable to fetch AltiVec registers"));
- }
-
- if (ppc_linux_get_hwcap () & PPC_FEATURE_HAS_DFP)
- isa205 = 1;
- if (ppc_linux_get_hwcap () & PPC_FEATURE_CELL)
- cell = 1;
- if (ppc_linux_target_wordsize () == 8)
- {
- if (cell)
- return tdesc_powerpc_cell64l;
- else if (vsx)
- return isa205? tdesc_powerpc_isa205_vsx64l : tdesc_powerpc_vsx64l;
- else if (altivec)
- return isa205
- ? tdesc_powerpc_isa205_altivec64l : tdesc_powerpc_altivec64l;
- return isa205? tdesc_powerpc_isa205_64l : tdesc_powerpc_64l;
- }
- if (cell)
- return tdesc_powerpc_cell32l;
- else if (vsx)
- return isa205? tdesc_powerpc_isa205_vsx32l : tdesc_powerpc_vsx32l;
- else if (altivec)
- return isa205? tdesc_powerpc_isa205_altivec32l : tdesc_powerpc_altivec32l;
- return isa205? tdesc_powerpc_isa205_32l : tdesc_powerpc_32l;
- }
- void _initialize_ppc_linux_nat (void);
- void
- _initialize_ppc_linux_nat (void)
- {
- struct target_ops *t;
-
- t = linux_target ();
-
- t->to_fetch_registers = ppc_linux_fetch_inferior_registers;
- t->to_store_registers = ppc_linux_store_inferior_registers;
-
- t->to_can_use_hw_breakpoint = ppc_linux_can_use_hw_breakpoint;
- t->to_insert_hw_breakpoint = ppc_linux_insert_hw_breakpoint;
- t->to_remove_hw_breakpoint = ppc_linux_remove_hw_breakpoint;
- t->to_region_ok_for_hw_watchpoint = ppc_linux_region_ok_for_hw_watchpoint;
- t->to_insert_watchpoint = ppc_linux_insert_watchpoint;
- t->to_remove_watchpoint = ppc_linux_remove_watchpoint;
- t->to_insert_mask_watchpoint = ppc_linux_insert_mask_watchpoint;
- t->to_remove_mask_watchpoint = ppc_linux_remove_mask_watchpoint;
- t->to_stopped_by_watchpoint = ppc_linux_stopped_by_watchpoint;
- t->to_stopped_data_address = ppc_linux_stopped_data_address;
- t->to_watchpoint_addr_within_range = ppc_linux_watchpoint_addr_within_range;
- t->to_can_accel_watchpoint_condition
- = ppc_linux_can_accel_watchpoint_condition;
- t->to_masked_watch_num_registers = ppc_linux_masked_watch_num_registers;
- t->to_ranged_break_num_registers = ppc_linux_ranged_break_num_registers;
- t->to_read_description = ppc_linux_read_description;
- t->to_auxv_parse = ppc_linux_auxv_parse;
- observer_attach_thread_exit (ppc_linux_thread_exit);
-
- linux_nat_add_target (t);
- linux_nat_set_new_thread (t, ppc_linux_new_thread);
- }