diff --git gdb/armfbsd-nat.c gdb/armfbsd-nat.c new file mode 100644 index 0000000..b883411 --- /dev/null +++ gdb/armfbsd-nat.c @@ -0,0 +1,215 @@ +/* Native-dependent code for BSD Unix running on ARM's, for GDB. + + Copyright (C) 1988-2015 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "gdbcore.h" +#include "inferior.h" +#include "regcache.h" +#include "target.h" +#include "gregset.h" +#include +#include +#include +#include + +#include "fbsd-nat.h" +#include "arm-tdep.h" +#include "inf-ptrace.h" + +extern int arm_apcs_32; + +static pid_t +ptrace_pid (ptid_t ptid) +{ + pid_t pid; + +#ifdef __FreeBSD__ + pid = ptid_get_lwp (ptid); + if (pid == 0) +#endif + pid = ptid_get_pid (ptid); + return pid; +} + +static void +arm_supply_gregset (struct regcache *regcache, const gregset_t *gregset, int regnum) +{ + int r; + CORE_ADDR r_pc; + + /* Integer registers. */ + for (r = ARM_A1_REGNUM; r < ARM_SP_REGNUM; r++) + if ((r == regnum) || (regnum == -1)) + regcache_raw_supply (regcache, r, (char *) &gregset->r[r]); + + if ((regnum == ARM_SP_REGNUM) || (regnum == -1)) + regcache_raw_supply (regcache, ARM_SP_REGNUM, + (char *) &gregset->r_sp); + if ((regnum == ARM_LR_REGNUM) || (regnum == -1)) + regcache_raw_supply (regcache, ARM_LR_REGNUM, + (char *) &gregset->r_lr); + /* This is ok: we're running native... */ + if ((regnum == ARM_PC_REGNUM) || (regnum == -1)) + { + r_pc = gdbarch_addr_bits_remove (get_regcache_arch (regcache), gregset->r_pc); + regcache_raw_supply (regcache, ARM_PC_REGNUM, (char *) &r_pc); + } + + if ((regnum == ARM_PS_REGNUM) || (regnum == -1)) + { + if (arm_apcs_32) + regcache_raw_supply (regcache, ARM_PS_REGNUM, + (char *) &gregset->r_cpsr); + else + regcache_raw_supply (regcache, ARM_PS_REGNUM, + (char *) &gregset->r_pc); + } +} + +static void +armbsd_collect_gregset (const struct regcache *regcache, gregset_t *gregset, int regnum) +{ + int ret; + int r; + + for (r = ARM_A1_REGNUM; r < ARM_SP_REGNUM; r++) + if ((regnum == r) || (regnum == -1)) + regcache_raw_collect (regcache, r, + (char *) &gregset->r[r]); + + if ((regnum == ARM_SP_REGNUM) || (regnum == -1)) + regcache_raw_collect (regcache, ARM_SP_REGNUM, + (char *) &gregset->r_sp); + if ((regnum == ARM_LR_REGNUM) || (regnum == -1)) + regcache_raw_collect (regcache, ARM_LR_REGNUM, + (char *) &gregset->r_lr); + + + if ((regnum == ARM_PC_REGNUM) || (regnum == -1)) + regcache_raw_collect (regcache, ARM_PC_REGNUM, + (char *) &gregset->r_pc); + if ((regnum == ARM_PS_REGNUM) || (regnum == -1)) + { + if (arm_apcs_32) + { + regcache_raw_collect (regcache, ARM_PS_REGNUM, + (char *) &gregset->r_cpsr); + } + else + { + unsigned psr_val; + + regcache_raw_collect (regcache, ARM_PS_REGNUM, + (char *) &psr_val); + + psr_val ^= gdbarch_addr_bits_remove (get_regcache_arch (regcache), psr_val); + gregset->r_pc = gdbarch_addr_bits_remove + (get_regcache_arch (regcache), gregset->r_pc); + gregset->r_pc |= psr_val; + } + } +} + +/* Fill GDB's register array with the general-purpose register values + in *GREGSETP. */ + +void +supply_gregset (struct regcache *regcache, const gregset_t *gregsetp) +{ + arm_supply_gregset (regcache, gregsetp, -1); +} + +/* Fill register REGNUM (if it is a general-purpose register) in + *GREGSETPS with the value in GDB's register array. If REGNUM is -1, + do this for all registers. */ + +void +fill_gregset (const struct regcache *regcache, gdb_gregset_t *gregsetp, int regnum) +{ + armbsd_collect_gregset (regcache, gregsetp, regnum); +} + +/* Fill GDB's register array with the floating-point register values + in *FPREGSETP. */ + +void +supply_fpregset (struct regcache *regcache, const fpregset_t *fpregsetp) +{ +} + +/* Fill register REGNUM (if it is a floating-point register) in + *FPREGSETP with the value in GDB's register array. If REGNUM is -1, + do this for all registers. */ + +void +fill_fpregset (const struct regcache *regcache, gdb_fpregset_t *fpregsetp, int regnum) +{ +} + +/* Fetch register REGNO from the child process. If REGNO is -1, do it + for all registers. */ + +static void +armfbsd_fetch_inferior_registers (struct target_ops *ops, + struct regcache *regcache, int regno) +{ + gdb_gregset_t regs; + + if (ptrace (PT_GETREGS, ptrace_pid (inferior_ptid), + (PTRACE_TYPE_ARG3) ®s, 0) == -1) + perror_with_name (_("Couldn't get registers")); + + arm_supply_gregset (regcache, ®s, regno); + /* TODO: fpregs */ +} + +/* Store register REGNO back into the child process. If REGNO is -1, + do this for all registers. */ + +static void +armfbsd_store_inferior_registers (struct target_ops *ops, + struct regcache *regcache, int regno) +{ + gdb_gregset_t regs; + + if (ptrace (PT_GETREGS, ptrace_pid (inferior_ptid), + (PTRACE_TYPE_ARG3) ®s, 0) == -1) + perror_with_name (_("Couldn't get registers")); + + fill_gregset (regcache, ®s, regno); + + if (ptrace (PT_SETREGS, ptrace_pid (inferior_ptid), + (PTRACE_TYPE_ARG3) ®s, 0) == -1) + perror_with_name (_("Couldn't write registers")); + /* TODO: FP regs */ +} + +void _initialize_armfbsd_nat (void); + +void +_initialize_armfbsd_nat (void) +{ + struct target_ops *t; + + /* Add in local overrides. */ + t = inf_ptrace_target (); + t->to_fetch_registers = armfbsd_fetch_inferior_registers; + t->to_store_registers = armfbsd_store_inferior_registers; + fbsd_nat_add_target (t); +} diff --git gdb/armfbsd-tdep.c gdb/armfbsd-tdep.c new file mode 100644 index 0000000..f58c323 --- /dev/null +++ gdb/armfbsd-tdep.c @@ -0,0 +1,109 @@ +/* Target-dependent code for PowerPC systems running FreeBSD. + + Copyright (C) 2013-2015 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see . */ + +#include "defs.h" +#include "arch-utils.h" +#include "frame.h" +#include "gdbcore.h" +#include "frame-unwind.h" +#include "gdbtypes.h" +#include "osabi.h" +#include "regcache.h" +#include "regset.h" +#include "symtab.h" +#include "target.h" +#include "trad-frame.h" + +#include "arm-tdep.h" +#include "solib-svr4.h" + +/* Description of the longjmp buffer. */ +#define ARM_FBSD_JB_PC 24 +#define ARM_FBSD_JB_ELEMENT_SIZE INT_REGISTER_SIZE + +/* For compatibility with previous implemenations of GDB on arm/FreeBSD, + override the default little-endian breakpoint. */ +static const gdb_byte arm_fbsd_arm_le_breakpoint[] = {0x11, 0x00, 0x00, 0xe6}; +static const gdb_byte arm_fbsd_arm_be_breakpoint[] = {0xe6, 0x00, 0x00, 0x11}; +static const gdb_byte arm_fbsd_thumb_le_breakpoint[] = {0xfe, 0xde}; +static const gdb_byte arm_fbsd_thumb_be_breakpoint[] = {0xde, 0xfe}; + +static void +arm_freebsd_init_abi_common (struct gdbarch_info info, + struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + tdep->lowest_pc = 0x8000; + switch (info.byte_order) + { + case BFD_ENDIAN_LITTLE: + tdep->arm_breakpoint = arm_fbsd_arm_le_breakpoint; + tdep->thumb_breakpoint = arm_fbsd_thumb_le_breakpoint; + tdep->arm_breakpoint_size = sizeof (arm_fbsd_arm_le_breakpoint); + tdep->thumb_breakpoint_size = sizeof (arm_fbsd_thumb_le_breakpoint); + break; + + case BFD_ENDIAN_BIG: + tdep->arm_breakpoint = arm_fbsd_arm_be_breakpoint; + tdep->thumb_breakpoint = arm_fbsd_thumb_be_breakpoint; + tdep->arm_breakpoint_size = sizeof (arm_fbsd_arm_be_breakpoint); + tdep->thumb_breakpoint_size = sizeof (arm_fbsd_thumb_be_breakpoint); + break; + + default: + internal_error (__FILE__, __LINE__, + _("arm_gdbarch_init: bad byte order for float format")); + } + + tdep->jb_pc = ARM_FBSD_JB_PC; + tdep->jb_elt_size = ARM_FBSD_JB_ELEMENT_SIZE; + + /* Single stepping. */ + set_gdbarch_software_single_step (gdbarch, arm_software_single_step); +} + +static void +arm_freebsd_elf_init_abi (struct gdbarch_info info, + struct gdbarch *gdbarch) +{ + struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch); + + arm_freebsd_init_abi_common (info, gdbarch); + if (tdep->fp_model == ARM_FLOAT_AUTO) + tdep->fp_model = ARM_FLOAT_SOFT_VFP; + + /* NetBSD ELF uses SVR4-style shared libraries. */ + set_solib_svr4_fetch_link_map_offsets + (gdbarch, svr4_ilp32_fetch_link_map_offsets); +} + + + +/* Provide a prototype to silence -Wmissing-prototypes. */ + +void _initialize_armfbsd_tdep (void); + +void +_initialize_armfbsd_tdep (void) +{ + + gdbarch_register_osabi (bfd_arch_arm, 0, GDB_OSABI_FREEBSD_ELF, + arm_freebsd_elf_init_abi); +} diff --git gdb/config/arm/fbsd.mh gdb/config/arm/fbsd.mh new file mode 100644 index 0000000..0a2d8b1 --- /dev/null +++ gdb/config/arm/fbsd.mh @@ -0,0 +1,3 @@ +# Host: FreeBSD/arm +NATDEPFILES= armfbsd-nat.o fbsd-nat.o fork-child.o inf-ptrace.o +HAVE_NATIVE_GCORE_HOST = 1 diff --git gdb/Makefile.in gdb/Makefile.in index dfaa8a3..ddad28d 100644 --- gdb/Makefile.in +++ gdb/Makefile.in @@ -659,7 +659,7 @@ ALL_TARGET_OBS = \ armbsd-tdep.o arm.o arm-linux.o arm-linux-tdep.o \ arm-get-next-pcs.o arm-symbian-tdep.o \ - armnbsd-tdep.o armobsd-tdep.o \ + armnbsd-tdep.o armobsd-tdep.o armfbsd-tdep.o \ arm-tdep.o arm-wince-tdep.o \ avr-tdep.o \ bfin-linux-tdep.o bfin-tdep.o \ @@ -1666,7 +1666,7 @@ arm.c arm-get-next-pcs.c \ arm-linux.c arm-linux-nat.c arm-linux-tdep.c \ arm-symbian-tdep.c arm-tdep.c \ - armnbsd-nat.c armbsd-tdep.c armnbsd-tdep.c armobsd-tdep.c \ + armnbsd-nat.c armbsd-tdep.c armnbsd-tdep.c armobsd-tdep.c armfbsd-tdep.c \ avr-tdep.c \ bfin-linux-tdep.c bfin-tdep.c \ bsd-uthread.c bsd-kvm.c \