/* Target-dependent code for GDB, the GNU debugger.
- Copyright (C) 1986-2014 Free Software Foundation, Inc.
+ Copyright (C) 1986-2017 Free Software Foundation, Inc.
This file is part of GDB.
#include "auxv.h"
#include "elf/common.h"
#include "elf/ppc64.h"
-#include "exceptions.h"
#include "arch-utils.h"
#include "spu-tdep.h"
#include "xml-syscall.h"
#include "linux-tdep.h"
+#include "linux-record.h"
+#include "record-full.h"
+#include "infrun.h"
#include "stap-probe.h"
#include "ax.h"
ppc_linux_memory_remove_breakpoint (struct gdbarch *gdbarch,
struct bp_target_info *bp_tgt)
{
- CORE_ADDR addr = bp_tgt->placed_address;
+ CORE_ADDR addr = bp_tgt->reqstd_address;
const unsigned char *bp;
int val;
int bplen;
/* Determine appropriate breakpoint contents and size for this address. */
bp = gdbarch_breakpoint_from_pc (gdbarch, &addr, &bplen);
- if (bp == NULL)
- error (_("Software breakpoints not implemented for this target."));
/* Make sure we see the memory breakpoints. */
cleanup = make_show_memory_breakpoints_cleanup (1);
readbuf, writebuf);
}
-static struct core_regset_section ppc_linux_vsx_regset_sections[] =
-{
- { ".reg", 48 * 4, "general-purpose" },
- { ".reg2", 264, "floating-point" },
- { ".reg-ppc-vmx", 544, "ppc Altivec" },
- { ".reg-ppc-vsx", 256, "POWER7 VSX" },
- { NULL, 0}
-};
-
-static struct core_regset_section ppc_linux_vmx_regset_sections[] =
-{
- { ".reg", 48 * 4, "general-purpose" },
- { ".reg2", 264, "floating-point" },
- { ".reg-ppc-vmx", 544, "ppc Altivec" },
- { NULL, 0}
-};
-
-static struct core_regset_section ppc_linux_fp_regset_sections[] =
-{
- { ".reg", 48 * 4, "general-purpose" },
- { ".reg2", 264, "floating-point" },
- { NULL, 0}
-};
-
-static struct core_regset_section ppc64_linux_vsx_regset_sections[] =
-{
- { ".reg", 48 * 8, "general-purpose" },
- { ".reg2", 264, "floating-point" },
- { ".reg-ppc-vmx", 544, "ppc Altivec" },
- { ".reg-ppc-vsx", 256, "POWER7 VSX" },
- { NULL, 0}
-};
-
-static struct core_regset_section ppc64_linux_vmx_regset_sections[] =
-{
- { ".reg", 48 * 8, "general-purpose" },
- { ".reg2", 264, "floating-point" },
- { ".reg-ppc-vmx", 544, "ppc Altivec" },
- { NULL, 0}
-};
-
-static struct core_regset_section ppc64_linux_fp_regset_sections[] =
-{
- { ".reg", 48 * 8, "general-purpose" },
- { ".reg2", 264, "floating-point" },
- { NULL, 0}
-};
-
/* PLT stub in executable. */
static struct ppc_insn_pattern powerpc32_plt_stub[] =
{
return 0;
}
-/* Follow PLT stub to actual routine. */
+/* Follow PLT stub to actual routine.
+
+ When the execution direction is EXEC_REVERSE, scan backward to
+ check whether we are in the middle of a PLT stub. Currently,
+ we only look-behind at most 4 instructions (the max length of PLT
+ stub sequence. */
static CORE_ADDR
ppc_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
CORE_ADDR target = 0;
+ int scan_limit, i;
- if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub, insnbuf))
- {
- /* Insn pattern is
- lis r11, xxxx
- lwz r11, xxxx(r11)
- Branch target is in r11. */
-
- target = (ppc_insn_d_field (insnbuf[0]) << 16)
- | ppc_insn_d_field (insnbuf[1]);
- target = read_memory_unsigned_integer (target, 4, byte_order);
- }
+ scan_limit = 1;
+ /* When reverse-debugging, scan backward to check whether we are
+ in the middle of trampoline code. */
+ if (execution_direction == EXEC_REVERSE)
+ scan_limit = 4; /* At more 4 instructions. */
- if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub_so, insnbuf))
+ for (i = 0; i < scan_limit; i++)
{
- /* Insn pattern is
- lwz r11, xxxx(r30)
- Branch target is in r11. */
+ if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub, insnbuf))
+ {
+ /* Insn pattern is
+ lis r11, xxxx
+ lwz r11, xxxx(r11)
+ Branch target is in r11. */
+
+ target = (ppc_insn_d_field (insnbuf[0]) << 16)
+ | ppc_insn_d_field (insnbuf[1]);
+ target = read_memory_unsigned_integer (target, 4, byte_order);
+ }
+ else if (ppc_insns_match_pattern (frame, pc, powerpc32_plt_stub_so,
+ insnbuf))
+ {
+ /* Insn pattern is
+ lwz r11, xxxx(r30)
+ Branch target is in r11. */
+
+ target = get_frame_register_unsigned (frame,
+ tdep->ppc_gp0_regnum + 30)
+ + ppc_insn_d_field (insnbuf[0]);
+ target = read_memory_unsigned_integer (target, 4, byte_order);
+ }
+ else
+ {
+ /* Scan backward one more instructions if doesn't match. */
+ pc -= 4;
+ continue;
+ }
- target = get_frame_register_unsigned (frame, tdep->ppc_gp0_regnum + 30)
- + ppc_insn_d_field (insnbuf[0]);
- target = read_memory_unsigned_integer (target, 4, byte_order);
+ return target;
}
- return target;
+ return 0;
}
/* Wrappers to handle Linux-only registers. */
struct regcache *regcache,
int regnum, const void *gregs, size_t len)
{
- const struct ppc_reg_offsets *offsets = regset->regmap;
+ const struct ppc_reg_offsets *offsets
+ = (const struct ppc_reg_offsets *) regset->regmap;
ppc_supply_gregset (regset, regcache, regnum, gregs, len);
{
/* "orig_r3" is stored 2 slots after "pc". */
if (regnum == -1 || regnum == PPC_ORIG_R3_REGNUM)
- ppc_supply_reg (regcache, PPC_ORIG_R3_REGNUM, gregs,
+ ppc_supply_reg (regcache, PPC_ORIG_R3_REGNUM, (const gdb_byte *) gregs,
offsets->pc_offset + 2 * offsets->gpr_size,
offsets->gpr_size);
/* "trap" is stored 8 slots after "pc". */
if (regnum == -1 || regnum == PPC_TRAP_REGNUM)
- ppc_supply_reg (regcache, PPC_TRAP_REGNUM, gregs,
+ ppc_supply_reg (regcache, PPC_TRAP_REGNUM, (const gdb_byte *) gregs,
offsets->pc_offset + 8 * offsets->gpr_size,
offsets->gpr_size);
}
const struct regcache *regcache,
int regnum, void *gregs, size_t len)
{
- const struct ppc_reg_offsets *offsets = regset->regmap;
+ const struct ppc_reg_offsets *offsets
+ = (const struct ppc_reg_offsets *) regset->regmap;
/* Clear areas in the linux gregset not written elsewhere. */
if (regnum == -1)
{
/* "orig_r3" is stored 2 slots after "pc". */
if (regnum == -1 || regnum == PPC_ORIG_R3_REGNUM)
- ppc_collect_reg (regcache, PPC_ORIG_R3_REGNUM, gregs,
+ ppc_collect_reg (regcache, PPC_ORIG_R3_REGNUM, (gdb_byte *) gregs,
offsets->pc_offset + 2 * offsets->gpr_size,
offsets->gpr_size);
/* "trap" is stored 8 slots after "pc". */
if (regnum == -1 || regnum == PPC_TRAP_REGNUM)
- ppc_collect_reg (regcache, PPC_TRAP_REGNUM, gregs,
+ ppc_collect_reg (regcache, PPC_TRAP_REGNUM, (gdb_byte *) gregs,
offsets->pc_offset + 8 * offsets->gpr_size,
offsets->gpr_size);
}
return &ppc32_linux_fpregset;
}
-static const struct regset *
-ppc_linux_regset_from_core_section (struct gdbarch *core_arch,
- const char *sect_name, size_t sect_size)
+/* Iterate over supported core file register note sections. */
+
+static void
+ppc_linux_iterate_over_regset_sections (struct gdbarch *gdbarch,
+ iterate_over_regset_sections_cb *cb,
+ void *cb_data,
+ const struct regcache *regcache)
{
- struct gdbarch_tdep *tdep = gdbarch_tdep (core_arch);
- if (strcmp (sect_name, ".reg") == 0)
- {
- if (tdep->wordsize == 4)
- return &ppc32_linux_gregset;
- else
- return &ppc64_linux_gregset;
- }
- if (strcmp (sect_name, ".reg2") == 0)
- return &ppc32_linux_fpregset;
- if (strcmp (sect_name, ".reg-ppc-vmx") == 0)
- return &ppc32_linux_vrregset;
- if (strcmp (sect_name, ".reg-ppc-vsx") == 0)
- return &ppc32_linux_vsxregset;
- return NULL;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int have_altivec = tdep->ppc_vr0_regnum != -1;
+ int have_vsx = tdep->ppc_vsr0_upper_regnum != -1;
+
+ if (tdep->wordsize == 4)
+ cb (".reg", 48 * 4, &ppc32_linux_gregset, NULL, cb_data);
+ else
+ cb (".reg", 48 * 8, &ppc64_linux_gregset, NULL, cb_data);
+
+ cb (".reg2", 264, &ppc32_linux_fpregset, NULL, cb_data);
+
+ if (have_altivec)
+ cb (".reg-ppc-vmx", 544, &ppc32_linux_vrregset, "ppc Altivec", cb_data);
+
+ if (have_vsx)
+ cb (".reg-ppc-vsx", 256, &ppc32_linux_vsxregset, "POWER7 VSX", cb_data);
}
static void
ppc64_linux_sighandler_cache_init
};
-
-/* Address to use for displaced stepping. When debugging a stand-alone
- SPU executable, entry_point_address () will point to an SPU local-store
- address and is thus not usable as displaced stepping location. We use
- the auxiliary vector to determine the PowerPC-side entry point address
- instead. */
-
-static CORE_ADDR ppc_linux_entry_point_addr = 0;
-
-static void
-ppc_linux_inferior_created (struct target_ops *target, int from_tty)
-{
- ppc_linux_entry_point_addr = 0;
-}
-
-static CORE_ADDR
-ppc_linux_displaced_step_location (struct gdbarch *gdbarch)
-{
- if (ppc_linux_entry_point_addr == 0)
- {
- CORE_ADDR addr;
-
- /* Determine entry point from target auxiliary vector. */
- if (target_auxv_search (¤t_target, AT_ENTRY, &addr) <= 0)
- error (_("Cannot find AT_ENTRY auxiliary vector entry."));
-
- /* Make certain that the address points at real code, and not a
- function descriptor. */
- addr = gdbarch_convert_from_func_ptr_addr (gdbarch, addr,
- ¤t_target);
-
- /* Inferior calls also use the entry point as a breakpoint location.
- We don't want displaced stepping to interfere with those
- breakpoints, so leave space. */
- ppc_linux_entry_point_addr = addr + 2 * PPC_INSN_SIZE;
- }
-
- return ppc_linux_entry_point_addr;
-}
-
-
/* Return 1 if PPC_ORIG_R3_REGNUM and PPC_TRAP_REGNUM are usable. */
int
ppc_linux_trap_reg_p (struct gdbarch *gdbarch)
return ret;
}
+/* PPC process record-replay */
+
+static struct linux_record_tdep ppc_linux_record_tdep;
+static struct linux_record_tdep ppc64_linux_record_tdep;
+
+/* ppc_canonicalize_syscall maps from the native PowerPC Linux set of
+ syscall ids into a canonical set of syscall ids used by process
+ record. (See arch/powerpc/include/uapi/asm/unistd.h in kernel tree.)
+ Return -1 if this system call is not supported by process record.
+ Otherwise, return the syscall number for preocess reocrd of given
+ SYSCALL. */
+
+static enum gdb_syscall
+ppc_canonicalize_syscall (int syscall)
+{
+ int result = -1;
+
+ if (syscall <= 165)
+ result = syscall;
+ else if (syscall >= 167 && syscall <= 190) /* Skip query_module 166 */
+ result = syscall + 1;
+ else if (syscall >= 192 && syscall <= 197) /* mmap2 */
+ result = syscall;
+ else if (syscall == 208) /* tkill */
+ result = gdb_sys_tkill;
+ else if (syscall >= 207 && syscall <= 220) /* gettid */
+ result = syscall + 224 - 207;
+ else if (syscall >= 234 && syscall <= 239) /* exit_group */
+ result = syscall + 252 - 234;
+ else if (syscall >= 240 && syscall <= 248) /* timer_create */
+ result = syscall += 259 - 240;
+ else if (syscall >= 250 && syscall <= 251) /* tgkill */
+ result = syscall + 270 - 250;
+ else if (syscall == 336)
+ result = gdb_sys_recv;
+ else if (syscall == 337)
+ result = gdb_sys_recvfrom;
+ else if (syscall == 342)
+ result = gdb_sys_recvmsg;
+
+ return (enum gdb_syscall) result;
+}
+
+/* Record registers which might be clobbered during system call.
+ Return 0 if successful. */
+
+static int
+ppc_linux_syscall_record (struct regcache *regcache)
+{
+ struct gdbarch *gdbarch = get_regcache_arch (regcache);
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ ULONGEST scnum;
+ enum gdb_syscall syscall_gdb;
+ int ret;
+ int i;
+
+ regcache_raw_read_unsigned (regcache, tdep->ppc_gp0_regnum, &scnum);
+ syscall_gdb = ppc_canonicalize_syscall (scnum);
+
+ if (syscall_gdb < 0)
+ {
+ printf_unfiltered (_("Process record and replay target doesn't "
+ "support syscall number %d\n"), (int) scnum);
+ return 0;
+ }
+
+ if (syscall_gdb == gdb_sys_sigreturn
+ || syscall_gdb == gdb_sys_rt_sigreturn)
+ {
+ int i, j;
+ int regsets[] = { tdep->ppc_gp0_regnum,
+ tdep->ppc_fp0_regnum,
+ tdep->ppc_vr0_regnum,
+ tdep->ppc_vsr0_upper_regnum };
+
+ for (j = 0; j < 4; j++)
+ {
+ if (regsets[j] == -1)
+ continue;
+ for (i = 0; i < 32; i++)
+ {
+ if (record_full_arch_list_add_reg (regcache, regsets[j] + i))
+ return -1;
+ }
+ }
+
+ if (record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum))
+ return -1;
+ if (record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum))
+ return -1;
+ if (record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum))
+ return -1;
+ if (record_full_arch_list_add_reg (regcache, tdep->ppc_xer_regnum))
+ return -1;
+
+ return 0;
+ }
+
+ if (tdep->wordsize == 8)
+ ret = record_linux_system_call (syscall_gdb, regcache,
+ &ppc64_linux_record_tdep);
+ else
+ ret = record_linux_system_call (syscall_gdb, regcache,
+ &ppc_linux_record_tdep);
+
+ if (ret != 0)
+ return ret;
+
+ /* Record registers clobbered during syscall. */
+ for (i = 3; i <= 12; i++)
+ {
+ if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + i))
+ return -1;
+ }
+ if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + 0))
+ return -1;
+ if (record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum))
+ return -1;
+ if (record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum))
+ return -1;
+ if (record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum))
+ return -1;
+
+ return 0;
+}
+
+/* Record registers which might be clobbered during signal handling.
+ Return 0 if successful. */
+
+static int
+ppc_linux_record_signal (struct gdbarch *gdbarch, struct regcache *regcache,
+ enum gdb_signal signal)
+{
+ /* See handle_rt_signal64 in arch/powerpc/kernel/signal_64.c
+ handle_rt_signal32 in arch/powerpc/kernel/signal_32.c
+ arch/powerpc/include/asm/ptrace.h
+ for details. */
+ const int SIGNAL_FRAMESIZE = 128;
+ const int sizeof_rt_sigframe = 1440 * 2 + 8 * 2 + 4 * 6 + 8 + 8 + 128 + 512;
+ ULONGEST sp;
+ struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+ int i;
+
+ for (i = 3; i <= 12; i++)
+ {
+ if (record_full_arch_list_add_reg (regcache, tdep->ppc_gp0_regnum + i))
+ return -1;
+ }
+
+ if (record_full_arch_list_add_reg (regcache, tdep->ppc_lr_regnum))
+ return -1;
+ if (record_full_arch_list_add_reg (regcache, tdep->ppc_cr_regnum))
+ return -1;
+ if (record_full_arch_list_add_reg (regcache, tdep->ppc_ctr_regnum))
+ return -1;
+ if (record_full_arch_list_add_reg (regcache, gdbarch_pc_regnum (gdbarch)))
+ return -1;
+ if (record_full_arch_list_add_reg (regcache, gdbarch_sp_regnum (gdbarch)))
+ return -1;
+
+ /* Record the change in the stack.
+ frame-size = sizeof (struct rt_sigframe) + SIGNAL_FRAMESIZE */
+ regcache_raw_read_unsigned (regcache, gdbarch_sp_regnum (gdbarch), &sp);
+ sp -= SIGNAL_FRAMESIZE;
+ sp -= sizeof_rt_sigframe;
+
+ if (record_full_arch_list_add_mem (sp, SIGNAL_FRAMESIZE + sizeof_rt_sigframe))
+ return -1;
+
+ if (record_full_arch_list_add_end ())
+ return -1;
+
+ return 0;
+}
+
static void
ppc_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
{
static int
ppc_linux_spu_section (bfd *abfd, asection *asect, void *user_data)
{
- return strncmp (bfd_section_name (abfd, asect), "SPU/", 4) == 0;
+ return startswith (bfd_section_name (abfd, asect), "SPU/");
}
static const struct target_desc *
}
len = s - p->arg;
- regname = alloca (len + 2);
+ regname = (char *) alloca (len + 2);
regname[0] = 'r';
strncpy (regname + 1, p->arg, len);
{
spe_context_objfile = objfile;
spe_context_lm_addr = svr4_fetch_objfile_link_map (objfile);
- spe_context_offset = BMSYMBOL_VALUE_ADDRESS (sym);
+ spe_context_offset = MSYMBOL_VALUE_RAW_ADDRESS (sym.minsym);
spe_context_cache_ptid = minus_one_ptid;
spe_context_cache_address = 0;
return;
if (!ptid_equal (spe_context_cache_ptid, inferior_ptid))
{
struct target_ops *target = ¤t_target;
- volatile struct gdb_exception ex;
- TRY_CATCH (ex, RETURN_MASK_ERROR)
+ TRY
{
/* We do not call target_translate_tls_address here, because
svr4_fetch_objfile_link_map may invalidate the frame chain,
spe_context_cache_ptid = inferior_ptid;
}
- if (ex.reason < 0)
- return 0;
+ CATCH (ex, RETURN_MASK_ERROR)
+ {
+ return 0;
+ }
+ END_CATCH
}
/* Read variable value. */
static struct gdbarch *
ppu2spu_prev_arch (struct frame_info *this_frame, void **this_cache)
{
- struct ppu2spu_cache *cache = *this_cache;
+ struct ppu2spu_cache *cache = (struct ppu2spu_cache *) *this_cache;
return get_regcache_arch (cache->regcache);
}
ppu2spu_this_id (struct frame_info *this_frame,
void **this_cache, struct frame_id *this_id)
{
- struct ppu2spu_cache *cache = *this_cache;
+ struct ppu2spu_cache *cache = (struct ppu2spu_cache *) *this_cache;
*this_id = cache->frame_id;
}
ppu2spu_prev_register (struct frame_info *this_frame,
void **this_cache, int regnum)
{
- struct ppu2spu_cache *cache = *this_cache;
+ struct ppu2spu_cache *cache = (struct ppu2spu_cache *) *this_cache;
struct gdbarch *gdbarch = get_regcache_arch (cache->regcache);
gdb_byte *buf;
- buf = alloca (register_size (gdbarch, regnum));
+ buf = (gdb_byte *) alloca (register_size (gdbarch, regnum));
if (regnum < gdbarch_num_regs (gdbarch))
regcache_raw_read (cache->regcache, regnum, buf);
gdb_byte gprs[128*16];
};
-static int
+static enum register_status
ppu2spu_unwind_register (void *src, int regnum, gdb_byte *buf)
{
- struct ppu2spu_data *data = src;
+ struct ppu2spu_data *data = (struct ppu2spu_data *) src;
enum bfd_endian byte_order = gdbarch_byte_order (data->gdbarch);
if (regnum >= 0 && regnum < SPU_NUM_GPRS)
info.bfd_arch_info = bfd_lookup_arch (bfd_arch_spu, bfd_mach_spu);
info.byte_order = BFD_ENDIAN_BIG;
info.osabi = GDB_OSABI_LINUX;
- info.tdep_info = (void *) &data.id;
+ info.id = &data.id;
data.gdbarch = gdbarch_find_by_info (info);
if (!data.gdbarch)
return 0;
static void
ppu2spu_dealloc_cache (struct frame_info *self, void *this_cache)
{
- struct ppu2spu_cache *cache = this_cache;
+ struct ppu2spu_cache *cache = (struct ppu2spu_cache *) this_cache;
regcache_xfree (cache->regcache);
}
ppu2spu_prev_arch,
};
+/* Initialize linux_record_tdep if not initialized yet.
+ WORDSIZE is 4 or 8 for 32- or 64-bit PowerPC Linux respectively.
+ Sizes of data structures are initialized accordingly. */
+
+static void
+ppc_init_linux_record_tdep (struct linux_record_tdep *record_tdep,
+ int wordsize)
+{
+ /* Simply return if it had been initialized. */
+ if (record_tdep->size_pointer != 0)
+ return;
+
+ /* These values are the size of the type that will be used in a system
+ call. They are obtained from Linux Kernel source. */
+
+ if (wordsize == 8)
+ {
+ record_tdep->size_pointer = 8;
+ record_tdep->size__old_kernel_stat = 32;
+ record_tdep->size_tms = 32;
+ record_tdep->size_loff_t = 8;
+ record_tdep->size_flock = 32;
+ record_tdep->size_oldold_utsname = 45;
+ record_tdep->size_ustat = 32;
+ record_tdep->size_old_sigaction = 32;
+ record_tdep->size_old_sigset_t = 8;
+ record_tdep->size_rlimit = 16;
+ record_tdep->size_rusage = 144;
+ record_tdep->size_timeval = 16;
+ record_tdep->size_timezone = 8;
+ record_tdep->size_old_gid_t = 4;
+ record_tdep->size_old_uid_t = 4;
+ record_tdep->size_fd_set = 128;
+ record_tdep->size_old_dirent = 280;
+ record_tdep->size_statfs = 120;
+ record_tdep->size_statfs64 = 120;
+ record_tdep->size_sockaddr = 16;
+ record_tdep->size_int = 4;
+ record_tdep->size_long = 8;
+ record_tdep->size_ulong = 8;
+ record_tdep->size_msghdr = 56;
+ record_tdep->size_itimerval = 32;
+ record_tdep->size_stat = 144;
+ record_tdep->size_old_utsname = 325;
+ record_tdep->size_sysinfo = 112;
+ record_tdep->size_msqid_ds = 120;
+ record_tdep->size_shmid_ds = 112;
+ record_tdep->size_new_utsname = 390;
+ record_tdep->size_timex = 208;
+ record_tdep->size_mem_dqinfo = 24;
+ record_tdep->size_if_dqblk = 72;
+ record_tdep->size_fs_quota_stat = 80;
+ record_tdep->size_timespec = 16;
+ record_tdep->size_pollfd = 8;
+ record_tdep->size_NFS_FHSIZE = 32;
+ record_tdep->size_knfsd_fh = 132;
+ record_tdep->size_TASK_COMM_LEN = 16;
+ record_tdep->size_sigaction = 32;
+ record_tdep->size_sigset_t = 8;
+ record_tdep->size_siginfo_t = 128;
+ record_tdep->size_cap_user_data_t = 8;
+ record_tdep->size_stack_t = 24;
+ record_tdep->size_off_t = 8;
+ record_tdep->size_stat64 = 104;
+ record_tdep->size_gid_t = 4;
+ record_tdep->size_uid_t = 4;
+ record_tdep->size_PAGE_SIZE = 0x10000; /* 64KB */
+ record_tdep->size_flock64 = 32;
+ record_tdep->size_io_event = 32;
+ record_tdep->size_iocb = 64;
+ record_tdep->size_epoll_event = 16;
+ record_tdep->size_itimerspec = 32;
+ record_tdep->size_mq_attr = 64;
+ record_tdep->size_termios = 44;
+ record_tdep->size_pid_t = 4;
+ record_tdep->size_winsize = 8;
+ record_tdep->size_serial_struct = 72;
+ record_tdep->size_serial_icounter_struct = 80;
+ record_tdep->size_size_t = 8;
+ record_tdep->size_iovec = 16;
+ record_tdep->size_time_t = 8;
+ }
+ else if (wordsize == 4)
+ {
+ record_tdep->size_pointer = 4;
+ record_tdep->size__old_kernel_stat = 32;
+ record_tdep->size_tms = 16;
+ record_tdep->size_loff_t = 8;
+ record_tdep->size_flock = 16;
+ record_tdep->size_oldold_utsname = 45;
+ record_tdep->size_ustat = 20;
+ record_tdep->size_old_sigaction = 16;
+ record_tdep->size_old_sigset_t = 4;
+ record_tdep->size_rlimit = 8;
+ record_tdep->size_rusage = 72;
+ record_tdep->size_timeval = 8;
+ record_tdep->size_timezone = 8;
+ record_tdep->size_old_gid_t = 4;
+ record_tdep->size_old_uid_t = 4;
+ record_tdep->size_fd_set = 128;
+ record_tdep->size_old_dirent = 268;
+ record_tdep->size_statfs = 64;
+ record_tdep->size_statfs64 = 88;
+ record_tdep->size_sockaddr = 16;
+ record_tdep->size_int = 4;
+ record_tdep->size_long = 4;
+ record_tdep->size_ulong = 4;
+ record_tdep->size_msghdr = 28;
+ record_tdep->size_itimerval = 16;
+ record_tdep->size_stat = 88;
+ record_tdep->size_old_utsname = 325;
+ record_tdep->size_sysinfo = 64;
+ record_tdep->size_msqid_ds = 68;
+ record_tdep->size_shmid_ds = 60;
+ record_tdep->size_new_utsname = 390;
+ record_tdep->size_timex = 128;
+ record_tdep->size_mem_dqinfo = 24;
+ record_tdep->size_if_dqblk = 72;
+ record_tdep->size_fs_quota_stat = 80;
+ record_tdep->size_timespec = 8;
+ record_tdep->size_pollfd = 8;
+ record_tdep->size_NFS_FHSIZE = 32;
+ record_tdep->size_knfsd_fh = 132;
+ record_tdep->size_TASK_COMM_LEN = 16;
+ record_tdep->size_sigaction = 20;
+ record_tdep->size_sigset_t = 8;
+ record_tdep->size_siginfo_t = 128;
+ record_tdep->size_cap_user_data_t = 4;
+ record_tdep->size_stack_t = 12;
+ record_tdep->size_off_t = 4;
+ record_tdep->size_stat64 = 104;
+ record_tdep->size_gid_t = 4;
+ record_tdep->size_uid_t = 4;
+ record_tdep->size_PAGE_SIZE = 0x10000; /* 64KB */
+ record_tdep->size_flock64 = 32;
+ record_tdep->size_io_event = 32;
+ record_tdep->size_iocb = 64;
+ record_tdep->size_epoll_event = 16;
+ record_tdep->size_itimerspec = 16;
+ record_tdep->size_mq_attr = 32;
+ record_tdep->size_termios = 44;
+ record_tdep->size_pid_t = 4;
+ record_tdep->size_winsize = 8;
+ record_tdep->size_serial_struct = 60;
+ record_tdep->size_serial_icounter_struct = 80;
+ record_tdep->size_size_t = 4;
+ record_tdep->size_iovec = 8;
+ record_tdep->size_time_t = 4;
+ }
+ else
+ internal_error (__FILE__, __LINE__, _("unexpected wordsize"));
+
+ /* These values are the second argument of system call "sys_fcntl"
+ and "sys_fcntl64". They are obtained from Linux Kernel source. */
+ record_tdep->fcntl_F_GETLK = 5;
+ record_tdep->fcntl_F_GETLK64 = 12;
+ record_tdep->fcntl_F_SETLK64 = 13;
+ record_tdep->fcntl_F_SETLKW64 = 14;
+
+ record_tdep->arg1 = PPC_R0_REGNUM + 3;
+ record_tdep->arg2 = PPC_R0_REGNUM + 4;
+ record_tdep->arg3 = PPC_R0_REGNUM + 5;
+ record_tdep->arg4 = PPC_R0_REGNUM + 6;
+ record_tdep->arg5 = PPC_R0_REGNUM + 7;
+ record_tdep->arg6 = PPC_R0_REGNUM + 8;
+
+ /* These values are the second argument of system call "sys_ioctl".
+ They are obtained from Linux Kernel source.
+ See arch/powerpc/include/uapi/asm/ioctls.h. */
+ record_tdep->ioctl_TCGETS = 0x403c7413;
+ record_tdep->ioctl_TCSETS = 0x803c7414;
+ record_tdep->ioctl_TCSETSW = 0x803c7415;
+ record_tdep->ioctl_TCSETSF = 0x803c7416;
+ record_tdep->ioctl_TCGETA = 0x40147417;
+ record_tdep->ioctl_TCSETA = 0x80147418;
+ record_tdep->ioctl_TCSETAW = 0x80147419;
+ record_tdep->ioctl_TCSETAF = 0x8014741c;
+ record_tdep->ioctl_TCSBRK = 0x2000741d;
+ record_tdep->ioctl_TCXONC = 0x2000741e;
+ record_tdep->ioctl_TCFLSH = 0x2000741f;
+ record_tdep->ioctl_TIOCEXCL = 0x540c;
+ record_tdep->ioctl_TIOCNXCL = 0x540d;
+ record_tdep->ioctl_TIOCSCTTY = 0x540e;
+ record_tdep->ioctl_TIOCGPGRP = 0x40047477;
+ record_tdep->ioctl_TIOCSPGRP = 0x80047476;
+ record_tdep->ioctl_TIOCOUTQ = 0x40047473;
+ record_tdep->ioctl_TIOCSTI = 0x5412;
+ record_tdep->ioctl_TIOCGWINSZ = 0x40087468;
+ record_tdep->ioctl_TIOCSWINSZ = 0x80087467;
+ record_tdep->ioctl_TIOCMGET = 0x5415;
+ record_tdep->ioctl_TIOCMBIS = 0x5416;
+ record_tdep->ioctl_TIOCMBIC = 0x5417;
+ record_tdep->ioctl_TIOCMSET = 0x5418;
+ record_tdep->ioctl_TIOCGSOFTCAR = 0x5419;
+ record_tdep->ioctl_TIOCSSOFTCAR = 0x541a;
+ record_tdep->ioctl_FIONREAD = 0x4004667f;
+ record_tdep->ioctl_TIOCINQ = 0x4004667f;
+ record_tdep->ioctl_TIOCLINUX = 0x541c;
+ record_tdep->ioctl_TIOCCONS = 0x541d;
+ record_tdep->ioctl_TIOCGSERIAL = 0x541e;
+ record_tdep->ioctl_TIOCSSERIAL = 0x541f;
+ record_tdep->ioctl_TIOCPKT = 0x5420;
+ record_tdep->ioctl_FIONBIO = 0x8004667e;
+ record_tdep->ioctl_TIOCNOTTY = 0x5422;
+ record_tdep->ioctl_TIOCSETD = 0x5423;
+ record_tdep->ioctl_TIOCGETD = 0x5424;
+ record_tdep->ioctl_TCSBRKP = 0x5425;
+ record_tdep->ioctl_TIOCSBRK = 0x5427;
+ record_tdep->ioctl_TIOCCBRK = 0x5428;
+ record_tdep->ioctl_TIOCGSID = 0x5429;
+ record_tdep->ioctl_TIOCGPTN = 0x40045430;
+ record_tdep->ioctl_TIOCSPTLCK = 0x80045431;
+ record_tdep->ioctl_FIONCLEX = 0x20006602;
+ record_tdep->ioctl_FIOCLEX = 0x20006601;
+ record_tdep->ioctl_FIOASYNC = 0x8004667d;
+ record_tdep->ioctl_TIOCSERCONFIG = 0x5453;
+ record_tdep->ioctl_TIOCSERGWILD = 0x5454;
+ record_tdep->ioctl_TIOCSERSWILD = 0x5455;
+ record_tdep->ioctl_TIOCGLCKTRMIOS = 0x5456;
+ record_tdep->ioctl_TIOCSLCKTRMIOS = 0x5457;
+ record_tdep->ioctl_TIOCSERGSTRUCT = 0x5458;
+ record_tdep->ioctl_TIOCSERGETLSR = 0x5459;
+ record_tdep->ioctl_TIOCSERGETMULTI = 0x545a;
+ record_tdep->ioctl_TIOCSERSETMULTI = 0x545b;
+ record_tdep->ioctl_TIOCMIWAIT = 0x545c;
+ record_tdep->ioctl_TIOCGICOUNT = 0x545d;
+ record_tdep->ioctl_FIOQSIZE = 0x40086680;
+}
+
+/* Return a floating-point format for a floating-point variable of
+ length LEN in bits. If non-NULL, NAME is the name of its type.
+ If no suitable type is found, return NULL. */
+
+const struct floatformat **
+ppc_floatformat_for_type (struct gdbarch *gdbarch,
+ const char *name, int len)
+{
+ if (len == 128 && name)
+ if (strcmp (name, "__float128") == 0
+ || strcmp (name, "_Float128") == 0
+ || strcmp (name, "_Float64x") == 0
+ || strcmp (name, "complex _Float128") == 0
+ || strcmp (name, "complex _Float64x") == 0)
+ return floatformats_ia64_quad;
+
+ return default_floatformat_for_type (gdbarch, name, len);
+}
static void
ppc_linux_init_abi (struct gdbarch_info info,
struct gdbarch *gdbarch)
{
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
- struct tdesc_arch_data *tdesc_data = (void *) info.tdep_info;
+ struct tdesc_arch_data *tdesc_data = info.tdesc_data;
static const char *const stap_integer_prefixes[] = { "i", NULL };
static const char *const stap_register_indirection_prefixes[] = { "(",
NULL };
set_gdbarch_long_double_bit (gdbarch, 16 * TARGET_CHAR_BIT);
set_gdbarch_long_double_format (gdbarch, floatformats_ibm_long_double);
+ /* Support for floating-point data type variants. */
+ set_gdbarch_floatformat_for_type (gdbarch, ppc_floatformat_for_type);
+
/* Handle inferior calls during interrupted system calls. */
set_gdbarch_write_pc (gdbarch, ppc_linux_write_pc);
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
/* Setting the correct XML syscall filename. */
- set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC);
+ set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_PPC);
/* Trampolines. */
tramp_frame_prepend_unwinder (gdbarch,
else
set_gdbarch_gcore_bfd_target (gdbarch, "elf32-powerpc");
- /* Supported register sections. */
- if (tdesc_find_feature (info.target_desc,
- "org.gnu.gdb.power.vsx"))
- set_gdbarch_core_regset_sections (gdbarch,
- ppc_linux_vsx_regset_sections);
- else if (tdesc_find_feature (info.target_desc,
- "org.gnu.gdb.power.altivec"))
- set_gdbarch_core_regset_sections (gdbarch,
- ppc_linux_vmx_regset_sections);
- else
- set_gdbarch_core_regset_sections (gdbarch,
- ppc_linux_fp_regset_sections);
-
if (powerpc_so_ops.in_dynsym_resolve_code == NULL)
{
powerpc_so_ops = svr4_so_ops;
(gdbarch, svr4_lp64_fetch_link_map_offsets);
/* Setting the correct XML syscall filename. */
- set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC64);
+ set_xml_syscall_file_name (gdbarch, XML_SYSCALL_FILENAME_PPC64);
/* Trampolines. */
tramp_frame_prepend_unwinder (gdbarch,
set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpcle");
else
set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpc");
-
- /* Supported register sections. */
- if (tdesc_find_feature (info.target_desc,
- "org.gnu.gdb.power.vsx"))
- set_gdbarch_core_regset_sections (gdbarch,
- ppc64_linux_vsx_regset_sections);
- else if (tdesc_find_feature (info.target_desc,
- "org.gnu.gdb.power.altivec"))
- set_gdbarch_core_regset_sections (gdbarch,
- ppc64_linux_vmx_regset_sections);
- else
- set_gdbarch_core_regset_sections (gdbarch,
- ppc64_linux_fp_regset_sections);
}
/* PPC32 uses a different prpsinfo32 compared to most other Linux
set_gdbarch_elfcore_write_linux_prpsinfo (gdbarch,
elfcore_write_ppc_linux_prpsinfo32);
- set_gdbarch_regset_from_core_section (gdbarch,
- ppc_linux_regset_from_core_section);
set_gdbarch_core_read_description (gdbarch, ppc_linux_core_read_description);
+ set_gdbarch_iterate_over_regset_sections (gdbarch,
+ ppc_linux_iterate_over_regset_sections);
/* Enable TLS support. */
set_gdbarch_fetch_tls_load_module_address (gdbarch,
/* Cell/B.E. cross-architecture unwinder support. */
frame_unwind_prepend_unwinder (gdbarch, &ppu2spu_unwind);
-
- /* The default displaced_step_at_entry_point doesn't work for
- SPU stand-alone executables. */
- set_gdbarch_displaced_step_location (gdbarch,
- ppc_linux_displaced_step_location);
}
- set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
+ set_gdbarch_displaced_step_location (gdbarch,
+ linux_displaced_step_location);
+
+ /* Support reverse debugging. */
+ set_gdbarch_process_record (gdbarch, ppc_process_record);
+ set_gdbarch_process_record_signal (gdbarch, ppc_linux_record_signal);
+ tdep->ppc_syscall_record = ppc_linux_syscall_record;
+
+ ppc_init_linux_record_tdep (&ppc_linux_record_tdep, 4);
+ ppc_init_linux_record_tdep (&ppc64_linux_record_tdep, 8);
}
/* Provide a prototype to silence -Wmissing-prototypes. */
gdbarch_register_osabi (bfd_arch_rs6000, bfd_mach_rs6k, GDB_OSABI_LINUX,
ppc_linux_init_abi);
- /* Attach to inferior_created observer. */
- observer_attach_inferior_created (ppc_linux_inferior_created);
-
/* Attach to observers to track __spe_current_active_context. */
observer_attach_inferior_created (ppc_linux_spe_context_inferior_created);
observer_attach_solib_loaded (ppc_linux_spe_context_solib_loaded);