Mirror of the gdb-patches mailing list
 help / color / mirror / Atom feed
* [PATCH] FreeBSD powerpc support
@ 2012-11-19 21:44 Andreas Tobler
  2012-11-23 19:34 ` Pedro Alves
  0 siblings, 1 reply; 12+ messages in thread
From: Andreas Tobler @ 2012-11-19 21:44 UTC (permalink / raw)
  To: gdb-patches

[-- Attachment #1: Type: text/plain, Size: 1867 bytes --]

Hi all,

After a longer timeout here again :)

The attached patch adds support for FreeBSD PowerPC, 32-bit and 64-bit.
It is derived from ppcobsd* and ppc-linux with FreeBSD additions.

There is room for improvement :) And I will continue, but I'd like to
see this patch in the gdb cvs because it will be much easier for me fix
outstanding issues when I can work with cvs iso. of local revisions.
Also, other people might have a use of this work, even if not complete.

Currently missing/incomplete:
- Altivec support, kernel bits are missing.
- HW watchpoints, also kernel bits are missing.
- thread support.
- tls support.
- some sig tests.

Here the summary from 32-bit:

                === gdb Summary ===

# of expected passes            16337
# of unexpected failures        1107
# of expected failures          68
# of known failures             49
# of untested testcases         63
# of unresolved testcases       97
# of unsupported tests          141


Here the summary from 64-bit:
                === gdb Summary ===

# of expected passes            16203
# of unexpected failures        1192
# of unexpected successes       1
# of expected failures          69
# of known failures             48
# of untested testcases         61
# of unresolved testcases       2
# of unsupported tests          141

Note on the results, around 800 failures (c++) are due to compiling with
g++-4.2.1. Using a newer g++ will make them pass. This is on all
supported FreeBSD platforms the same.

I appreciate comments and corrections.

TIA,
Andreas


2012-11-19  Andreas Tobler  <andreast@fgznet.ch>

	* Makefile.in (ALL_TARGET_OBS): Add powerpc FreeBSD files.
	* configure.host: Add powerpc*-*-freebsd* target.
	* configure.tgt: Add target info for powerpc*-*-freebsd*.
	* ppcfbsd-nat.c, ppcfbsd-tdep.h, ppcfbsd-tdep.c: New files.
	* config/powerpc/fbsd.mh: New file.

[-- Attachment #2: gdb_ppc_20121119-1.diff --]
[-- Type: text/plain, Size: 56199 bytes --]

Index: ./ppcfbsd-nat.c
--- /dev/null
+++ ./ppcfbsd-nat.c
@@ -0,0 +1,200 @@
+/* Native-dependent code for PowerPC's running FreeBSD, for GDB.
+
+   Copyright (C) 2002, 2004, 2012
+   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 <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "regcache.h"
+
+#include "gdb_assert.h"
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/procfs.h>
+#include <sys/ptrace.h>
+#include <sys/signal.h>
+#include <machine/frame.h>
+#include <machine/pcb.h>
+#include <machine/reg.h>
+
+#include "fbsd-nat.h"
+#include "gregset.h"
+#include "ppc-tdep.h"
+#include "ppcfbsd-tdep.h"
+#include "inf-ptrace.h"
+#include "bsd-kvm.h"
+
+
+void
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
+{
+  const struct regset *regset = ppc_fbsd_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_fbsd_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_fbsd_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_fbsd_fpregset ();
+
+  ppc_collect_fpregset (regset, regcache, regno,
+			fpregsetp, sizeof (*fpregsetp));
+}
+
+static int
+getfpregs_supplies (struct gdbarch *gdbarch, int regno)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
+     point registers.  Traditionally, GDB's register set has still
+     listed the floating point registers for such machines, so this
+     code is harmless.  However, the new E500 port actually omits the
+     floating point registers entirely from the register set --- they
+     don't even have register numbers assigned to them.
+
+     It's not clear to me how best to update this code, so this assert
+     will alert the first person to encounter the NetBSD/E500
+     combination to the problem.  */
+  gdb_assert (ppc_floating_point_unit_p (gdbarch));
+
+  return ((regno >= tdep->ppc_fp0_regnum
+	   && regno < tdep->ppc_fp0_regnum + ppc_num_fprs)
+	  || regno == tdep->ppc_fpscr_regnum);
+}
+
+static void
+ppcfbsd_fetch_inferior_registers (struct target_ops *ops,
+				  struct regcache *regcache, int regno)
+{
+  gdb_gregset_t regs;
+
+  if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+  	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
+    perror_with_name (_("Couldn't get registers"));
+
+  supply_gregset (regcache, &regs);
+
+  if (regno == -1 || getfpregs_supplies (get_regcache_arch (regcache), regno))
+    {
+      const struct regset *fpregset = ppc_fbsd_fpregset ();
+      gdb_fpregset_t fpregs;
+
+      if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+  		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+  	perror_with_name (_("Couldn't get FP registers"));
+
+      ppc_supply_fpregset (fpregset, regcache, regno, &fpregs, sizeof fpregs);
+    }
+}
+
+static void
+ppcfbsd_store_inferior_registers (struct target_ops *ops,
+				  struct regcache *regcache, int regno)
+{
+  gdb_gregset_t regs;
+
+  if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
+    perror_with_name (_("Couldn't get registers"));
+
+  fill_gregset (regcache, &regs, regno);
+
+  if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
+	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
+    perror_with_name (_("Couldn't write registers"));
+
+  if (regno == -1 || getfpregs_supplies (get_regcache_arch (regcache), regno))
+    {
+      gdb_fpregset_t fpregs;
+
+      if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+	perror_with_name (_("Couldn't get FP registers"));
+
+      fill_fpregset (regcache, &fpregs, regno);
+
+      if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
+		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+	perror_with_name (_("Couldn't set FP registers"));
+    }
+}
+
+static int
+ppcfbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int i, regnum;
+
+  /* The stack pointer shouldn't be zero.  */
+  if (pcb->pcb_sp == 0)
+    return 0;
+
+  regcache_raw_supply (regcache, gdbarch_sp_regnum (gdbarch), &pcb->pcb_sp);
+  regcache_raw_supply (regcache, tdep->ppc_cr_regnum, &pcb->pcb_cr);
+  regcache_raw_supply (regcache, tdep->ppc_lr_regnum, &pcb->pcb_lr);
+  for (i = 0, regnum = tdep->ppc_gp0_regnum + 14; i < 20; i++, regnum++)
+    regcache_raw_supply (regcache, regnum, &pcb->pcb_context[i]);
+
+  return 1;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+void _initialize_ppcfbsd_nat (void);
+
+void
+_initialize_ppcfbsd_nat (void)
+{
+  struct target_ops *t;
+
+  /* Add in local overrides.  */
+  t = inf_ptrace_target ();
+  t->to_fetch_registers = ppcfbsd_fetch_inferior_registers;
+  t->to_store_registers = ppcfbsd_store_inferior_registers;
+  t->to_pid_to_exec_file = fbsd_pid_to_exec_file;
+  t->to_find_memory_regions = fbsd_find_memory_regions;
+  t->to_make_corefile_notes = fbsd_make_corefile_notes;
+  add_target (t);
+
+  /* Support debugging kernel virtual memory images.  */
+  bsd_kvm_add_target (ppcfbsd_supply_pcb);
+}
Index: ./ppcfbsd-tdep.c
--- /dev/null
+++ ./ppcfbsd-tdep.c
@@ -0,0 +1,727 @@
+/* Target-dependent code for PowerPC systems running FreeBSD.
+
+   Copyright (C) 2002, 2003, 2004, 2012
+   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 <http://www.gnu.org/licenses/>.  */
+
+#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 "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "ppc-tdep.h"
+#include "ppcfbsd-tdep.h"
+#include "solib-svr4.h"
+
+#include "features/rs6000/powerpc-32l.c"
+#include "features/rs6000/powerpc-64l.c"
+
+/* Macros for matching instructions.  Note that, since all the
+   operands are masked off before they're or-ed into the instruction,
+   you can use -1 to make masks.  */
+
+#define insn_d(opcd, rts, ra, d)                \
+  ((((opcd) & 0x3f) << 26)                      \
+   | (((rts) & 0x1f) << 21)                     \
+   | (((ra) & 0x1f) << 16)                      \
+   | ((d) & 0xffff))
+
+#define insn_ds(opcd, rts, ra, d, xo)           \
+  ((((opcd) & 0x3f) << 26)                      \
+   | (((rts) & 0x1f) << 21)                     \
+   | (((ra) & 0x1f) << 16)                      \
+   | ((d) & 0xfffc)                             \
+   | ((xo) & 0x3))
+
+#define insn_xfx(opcd, rts, spr, xo)            \
+  ((((opcd) & 0x3f) << 26)                      \
+   | (((rts) & 0x1f) << 21)                     \
+   | (((spr) & 0x1f) << 16)                     \
+   | (((spr) & 0x3e0) << 6)                     \
+   | (((xo) & 0x3ff) << 1))
+
+/* Read a PPC instruction from memory.  PPC instructions are always
+ *  big-endian, no matter what endianness the program is running in, so
+ *  we can't use read_memory_integer or one of its friends here.
+ */
+static unsigned int
+read_insn (CORE_ADDR pc)
+{
+  unsigned char buf[4];
+
+  read_memory (pc, buf, 4);
+  return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+}
+
+
+/* An instruction to match.  */
+struct insn_pattern
+{
+  unsigned int mask;            /* mask the insn with this...  */
+  unsigned int data;            /* ...and see if it matches this.  */
+  int optional;                 /* If non-zero, this insn may be absent.  */
+};
+
+/* Return non-zero if the instructions at PC match the series
+   described in PATTERN, or zero otherwise.  PATTERN is an array of
+   'struct insn_pattern' objects, terminated by an entry whose mask is
+   zero.
+
+   When the match is successful, fill INSN[i] with what PATTERN[i]
+   matched.  If PATTERN[i] is optional, and the instruction wasn't
+   present, set INSN[i] to 0 (which is not a valid PPC instruction).
+   INSN should have as many elements as PATTERN.  Note that, if
+   PATTERN contains optional instructions which aren't present in
+   memory, then INSN will have holes, so INSN[i] isn't necessarily the
+   i'th instruction in memory.  */
+static int
+insns_match_pattern (CORE_ADDR pc, struct insn_pattern *pattern,
+		     unsigned int *insn)
+{
+  int i;
+
+  for (i = 0; pattern[i].mask; i++)
+    {
+      insn[i] = read_insn (pc);
+      if ((insn[i] & pattern[i].mask) == pattern[i].data)
+	pc += 4;
+      else if (pattern[i].optional)
+	insn[i] = 0;
+      else
+	return 0;
+    }
+
+  return 1;
+}
+
+/* Return the 'd' field of the d-form instruction INSN, properly
+   sign-extended.  */
+static CORE_ADDR
+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.  */
+static CORE_ADDR
+insn_ds_field (unsigned int insn)
+{
+  return ((((CORE_ADDR) insn & 0xfffc) ^ 0x8000) - 0x8000);
+}
+
+/* If DESC is the address of a 64-bit PowerPC FreeBSD function
+   descriptor, return the descriptor's entry point.  */
+static CORE_ADDR
+ppc64_desc_entry_point (struct gdbarch *gdbarch, CORE_ADDR desc)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  /* The first word of the descriptor is the entry point.  */
+  return (CORE_ADDR) read_memory_unsigned_integer (desc, 8, byte_order);
+}
+
+/* Pattern for the standard linkage function.  These are built by
+   build_plt_stub in elf64-ppc.c, whose GLINK argument is always
+   zero.  */
+static struct insn_pattern ppc64_standard_linkage1[] =
+  {
+    /* addis r12, r2, <any> */
+    { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 },
+
+    /* std r2, 40(r1) */
+    { -1, insn_ds (62, 2, 1, 40, 0), 0 },
+
+    /* ld r11, <any>(r12) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 },
+
+    /* addis r12, r12, 1 <optional> */
+    { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 },
+
+    /* ld r2, <any>(r12) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 },
+
+    /* addis r12, r12, 1 <optional> */
+    { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 },
+
+    /* mtctr r11 */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
+
+    /* ld r11, <any>(r12) <optional> */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 },
+
+    /* bctr */
+    { -1, 0x4e800420, 0 },
+
+    { 0, 0, 0 }
+  };
+
+#define PPC64_STANDARD_LINKAGE1_LEN \
+  (sizeof (ppc64_standard_linkage1) / sizeof (ppc64_standard_linkage1[0]))
+
+static struct insn_pattern ppc64_standard_linkage2[] =
+  {
+    /* addis r12, r2, <any> */
+    { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 },
+
+    /* std r2, 40(r1) */
+    { -1, insn_ds (62, 2, 1, 40, 0), 0 },
+
+    /* ld r11, <any>(r12) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 },
+
+    /* addi r12, r12, <any> <optional> */
+    { insn_d (-1, -1, -1, 0), insn_d (14, 12, 12, 0), 1 },
+
+    /* mtctr r11 */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
+
+    /* ld r2, <any>(r12) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 },
+
+    /* ld r11, <any>(r12) <optional> */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 },
+
+    /* bctr */
+    { -1, 0x4e800420, 0 },
+
+    { 0, 0, 0 }
+  };
+
+#define PPC64_STANDARD_LINKAGE2_LEN \
+  (sizeof (ppc64_standard_linkage2) / sizeof (ppc64_standard_linkage2[0]))
+
+static struct insn_pattern ppc64_standard_linkage3[] =
+  {
+    /* std r2, 40(r1) */
+    { -1, insn_ds (62, 2, 1, 40, 0), 0 },
+
+    /* ld r11, <any>(r2) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 0 },
+
+    /* addi r2, r2, <any> <optional> */
+    { insn_d (-1, -1, -1, 0), insn_d (14, 2, 2, 0), 1 },
+
+    /* mtctr r11 */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
+
+    /* ld r11, <any>(r2) <optional> */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 1 },
+
+    /* ld r2, <any>(r2) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 2, 0, 0), 0 },
+
+    /* bctr */
+    { -1, 0x4e800420, 0 },
+
+    { 0, 0, 0 }
+  };
+
+#define PPC64_STANDARD_LINKAGE3_LEN \
+  (sizeof (ppc64_standard_linkage3) / sizeof (ppc64_standard_linkage3[0]))
+
+
+/* When the dynamic linker is doing lazy symbol resolution, the first
+   call to a function in another object will go like this:
+
+   - The user's function calls the linkage function:
+
+     100007c4:	4b ff fc d5 	bl	10000498
+     100007c8:	e8 41 00 28 	ld	r2,40(r1)
+
+   - The linkage function loads the entry point (and other stuff) from
+     the function descriptor in the PLT, and jumps to it:
+
+     10000498:	3d 82 00 00 	addis	r12,r2,0
+     1000049c:	f8 41 00 28 	std	r2,40(r1)
+     100004a0:	e9 6c 80 98 	ld	r11,-32616(r12)
+     100004a4:	e8 4c 80 a0 	ld	r2,-32608(r12)
+     100004a8:	7d 69 03 a6 	mtctr	r11
+     100004ac:	e9 6c 80 a8 	ld	r11,-32600(r12)
+     100004b0:	4e 80 04 20 	bctr
+
+   - But since this is the first time that PLT entry has been used, it
+     sends control to its glink entry.  That loads the number of the
+     PLT entry and jumps to the common glink0 code:
+
+     10000c98:	38 00 00 00 	li	r0,0
+     10000c9c:	4b ff ff dc 	b	10000c78
+
+   - The common glink0 code then transfers control to the dynamic
+     linker's fixup code:
+
+     10000c78:	e8 41 00 28 	ld	r2,40(r1)
+     10000c7c:	3d 82 00 00 	addis	r12,r2,0
+     10000c80:	e9 6c 80 80 	ld	r11,-32640(r12)
+     10000c84:	e8 4c 80 88 	ld	r2,-32632(r12)
+     10000c88:	7d 69 03 a6 	mtctr	r11
+     10000c8c:	e9 6c 80 90 	ld	r11,-32624(r12)
+     10000c90:	4e 80 04 20 	bctr
+
+   Eventually, this code will figure out how to skip all of this,
+   including the dynamic linker.  At the moment, we just get through
+   the linkage function.  */
+
+/* If the current thread is about to execute a series of instructions
+   at PC matching the ppc64_standard_linkage pattern, and INSN is the result
+   from that pattern match, return the code address to which the
+   standard linkage function will send them.  (This doesn't deal with
+   dynamic linker lazy symbol resolution stubs.)  */
+static CORE_ADDR
+ppc64_standard_linkage1_target (struct frame_info *frame,
+				CORE_ADDR pc, unsigned int *insn)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* The address of the function descriptor this linkage function
+     references.  */
+  CORE_ADDR desc
+    = ((CORE_ADDR) get_frame_register_unsigned (frame,
+						tdep->ppc_gp0_regnum + 2)
+       + (insn_d_field (insn[0]) << 16)
+       + insn_ds_field (insn[2]));
+
+  /* The first word of the descriptor is the entry point.  Return that.  */
+  return ppc64_desc_entry_point (gdbarch, desc);
+}
+
+static CORE_ADDR
+ppc64_standard_linkage2_target (struct frame_info *frame,
+				CORE_ADDR pc, unsigned int *insn)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* The address of the function descriptor this linkage function
+     references.  */
+  CORE_ADDR desc
+    = ((CORE_ADDR) get_frame_register_unsigned (frame,
+						tdep->ppc_gp0_regnum + 2)
+       + (insn_d_field (insn[0]) << 16)
+       + insn_ds_field (insn[2]));
+
+  /* The first word of the descriptor is the entry point.  Return that.  */
+  return ppc64_desc_entry_point (gdbarch, desc);
+}
+
+static CORE_ADDR
+ppc64_standard_linkage3_target (struct frame_info *frame,
+				CORE_ADDR pc, unsigned int *insn)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* The address of the function descriptor this linkage function
+     references.  */
+  CORE_ADDR desc
+    = ((CORE_ADDR) get_frame_register_unsigned (frame,
+						tdep->ppc_gp0_regnum + 2)
+       + insn_ds_field (insn[1]));
+
+  /* The first word of the descriptor is the entry point.  Return that.  */
+  return ppc64_desc_entry_point (gdbarch, desc);
+}
+
+
+/* Given that we've begun executing a call trampoline at PC, return
+   the entry point of the function the trampoline will go to.  */
+static CORE_ADDR
+ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+{
+  unsigned int ppc64_standard_linkage1_insn[PPC64_STANDARD_LINKAGE1_LEN];
+  unsigned int ppc64_standard_linkage2_insn[PPC64_STANDARD_LINKAGE2_LEN];
+  unsigned int ppc64_standard_linkage3_insn[PPC64_STANDARD_LINKAGE3_LEN];
+  CORE_ADDR target;
+
+  if (insns_match_pattern (pc, ppc64_standard_linkage1,
+			   ppc64_standard_linkage1_insn))
+    pc = ppc64_standard_linkage1_target (frame, pc,
+					 ppc64_standard_linkage1_insn);
+  else if (insns_match_pattern (pc, ppc64_standard_linkage2,
+				ppc64_standard_linkage2_insn))
+    pc = ppc64_standard_linkage2_target (frame, pc,
+					 ppc64_standard_linkage2_insn);
+  else if (insns_match_pattern (pc, ppc64_standard_linkage3,
+				ppc64_standard_linkage3_insn))
+    pc = ppc64_standard_linkage3_target (frame, pc,
+					 ppc64_standard_linkage3_insn);
+  else
+    return 0;
+
+  /* The PLT descriptor will either point to the already resolved target
+     address, or else to a glink stub.  As the latter carry synthetic @plt
+     symbols, find_solib_trampoline_target should be able to resolve them.  */
+  target = find_solib_trampoline_target (frame, pc);
+  return target ? target : pc;
+}
+
+/* Regset descriptions.  */
+static const struct ppc_reg_offsets ppc32_fbsd_reg_offsets =
+  {
+    /* General-purpose registers.  */
+    /* .r0_offset = */ 0,
+    /* .gpr_size = */ 4,
+    /* .xr_size = */ 4,
+    /* .pc_offset = */ 144,
+    /* .ps_offset = */ -1,
+    /* .cr_offset = */ 132,
+    /* .lr_offset = */ 128,
+    /* .ctr_offset = */ 140,
+    /* .xer_offset = */ 136,
+    /* .mq_offset = */ -1,
+
+    /* Floating-point registers.  */
+    /* .f0_offset = */ 0,
+    /* .fpscr_offset = */ 256,
+    /* .fpscr_size = */ 8,
+#ifdef NOTYET
+    /* AltiVec registers.  */
+    /* .vr0_offset = */ 0,
+    /* .vscr_offset = */ 512 + 12,
+    /* .vrsave_offset = */ 512
+#endif
+  };
+
+static const struct ppc_reg_offsets ppc64_fbsd_reg_offsets =
+  {
+    /* General-purpose registers.  */
+    /* .r0_offset = */ 0,
+    /* .gpr_size = */ 8,
+    /* .xr_size = */ 8,
+    /* .pc_offset = */ 288,
+    /* .ps_offset = */ -1,
+    /* .cr_offset = */ 264,
+    /* .lr_offset = */ 256,
+    /* .ctr_offset = */ 280,
+    /* .xer_offset = */ 272,
+    /* .mq_offset = */ -1,
+
+    /* Floating-point registers.  */
+    /* .f0_offset = */ 0,
+    /* .fpscr_offset = */ 256,
+    /* .fpscr_size = */ 8,
+#ifdef NOYET
+    /* AltiVec registers.  */
+    /* .vr0_offset = */ 0,
+    /* .vscr_offset = */ 512 + 12,
+    /* .vrsave_offset = */ 528
+#endif
+  };
+
+/* FreeBSD/powerpc register set.  */
+static const struct regset ppc32_fbsd_gregset = {
+  &ppc32_fbsd_reg_offsets,
+  ppc_supply_gregset,
+  ppc_collect_gregset,
+  NULL
+};
+
+static const struct regset ppc64_fbsd_gregset = {
+  &ppc64_fbsd_reg_offsets,
+  ppc_supply_gregset,
+  ppc_collect_gregset,
+  NULL
+};
+
+static struct regset ppc32_fbsd_fpregset = {
+  &ppc32_fbsd_reg_offsets,
+  ppc_supply_fpregset,
+  ppc_collect_fpregset
+};
+
+const struct regset *
+ppc_fbsd_gregset (int wordsize)
+{
+  return wordsize == 8 ? &ppc64_fbsd_gregset : &ppc32_fbsd_gregset;
+}
+
+const struct regset *
+ppc_fbsd_fpregset (void)
+{
+  return &ppc32_fbsd_fpregset;
+}
+
+/* Return the appropriate register set for the core section identified
+   by SECT_NAME and SECT_SIZE.  */
+
+static const struct regset *
+ppcfbsd_regset_from_core_section (struct gdbarch *gdbarch,
+				  const char *sect_name, size_t sect_size)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  if (strcmp (sect_name, ".reg") == 0 && sect_size >= 148)
+    {
+      if (tdep->wordsize == 4)
+	return &ppc32_fbsd_gregset;
+      else
+	return &ppc64_fbsd_gregset;
+    }
+  if (strcmp (sect_name, ".reg2") == 0 && sect_size >= 264)
+    return &ppc32_fbsd_fpregset;
+  return NULL;
+}
+
+/* Default page size.  */
+static const int ppcfbsd_page_size = 4096;
+
+/* Offset for sigreturn(2).  */
+static const int ppcfbsd_sigreturn_offset[] = {
+  0xc,				/* FreeBSD */
+  -1
+};
+
+/* Signal trampolines.  */
+
+static int
+ppcfbsd_sigtramp_frame_sniffer (const struct frame_unwind *self,
+				struct frame_info *this_frame,
+				void **this_cache)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  CORE_ADDR pc = get_frame_pc (this_frame);
+  CORE_ADDR start_pc = (pc & ~(ppcfbsd_page_size - 1));
+  const int *offset;
+  const char *name;
+
+  find_pc_partial_function (pc, &name, NULL, NULL);
+  if (name)
+    return 0;
+
+  for (offset = ppcfbsd_sigreturn_offset; *offset != -1; offset++)
+    {
+      gdb_byte buf[2 * PPC_INSN_SIZE];
+      unsigned long insn;
+
+      if (!safe_frame_unwind_memory (this_frame, start_pc + *offset,
+				     buf, sizeof buf))
+	continue;
+
+      /* Check for "li r0,SYS_sigreturn".  */
+      insn = extract_unsigned_integer (buf, PPC_INSN_SIZE, byte_order);
+      if (insn != 0x380001a1)
+	continue;
+
+      /* Check for "sc".  */
+      insn = extract_unsigned_integer (buf + PPC_INSN_SIZE,
+				       PPC_INSN_SIZE, byte_order);
+      if (insn != 0x44000002)
+	continue;
+
+      return 1;
+    }
+
+  return 0;
+}
+
+static struct trad_frame_cache *
+ppcfbsd_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+  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 trad_frame_cache *cache;
+  CORE_ADDR addr, base, func;
+  gdb_byte buf[PPC_INSN_SIZE];
+  int i;
+
+  if (*this_cache)
+    return *this_cache;
+
+  cache = trad_frame_cache_zalloc (this_frame);
+  *this_cache = cache;
+
+  func = get_frame_pc (this_frame);
+  func &= ~(ppcfbsd_page_size - 1);
+  if (!safe_frame_unwind_memory (this_frame, func, buf, sizeof buf))
+    return cache;
+
+  base = get_frame_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch));
+  addr = base + 0x10 + 2 * tdep->wordsize;
+  for (i = 0; i < ppc_num_gprs; i++, addr += tdep->wordsize)
+    {
+      int regnum = i + tdep->ppc_gp0_regnum;
+      trad_frame_set_reg_addr (cache, regnum, addr);
+    }
+  trad_frame_set_reg_addr (cache, tdep->ppc_lr_regnum, addr);
+  addr += tdep->wordsize;
+  trad_frame_set_reg_addr (cache, tdep->ppc_cr_regnum, addr);
+  addr += tdep->wordsize;
+  trad_frame_set_reg_addr (cache, tdep->ppc_xer_regnum, addr);
+  addr += tdep->wordsize;
+  trad_frame_set_reg_addr (cache, tdep->ppc_ctr_regnum, addr);
+  addr += tdep->wordsize;
+  trad_frame_set_reg_addr (cache, gdbarch_pc_regnum (gdbarch), addr);
+  /* SRR0? */
+  addr += tdep->wordsize;
+
+  /* Construct the frame ID using the function start.  */
+  trad_frame_set_id (cache, frame_id_build (base, func));
+
+  return cache;
+}
+
+static void
+ppcfbsd_sigtramp_frame_this_id (struct frame_info *this_frame,
+				void **this_cache, struct frame_id *this_id)
+{
+  struct trad_frame_cache *cache =
+    ppcfbsd_sigtramp_frame_cache (this_frame, this_cache);
+
+  trad_frame_get_id (cache, this_id);
+}
+
+static struct value *
+ppcfbsd_sigtramp_frame_prev_register (struct frame_info *this_frame,
+				      void **this_cache, int regnum)
+{
+  struct trad_frame_cache *cache =
+    ppcfbsd_sigtramp_frame_cache (this_frame, this_cache);
+
+  return trad_frame_get_register (cache, this_frame, regnum);
+}
+
+static const struct frame_unwind ppcfbsd_sigtramp_frame_unwind = {
+  SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
+  ppcfbsd_sigtramp_frame_this_id,
+  ppcfbsd_sigtramp_frame_prev_register,
+  NULL,
+  ppcfbsd_sigtramp_frame_sniffer
+};
+
+static enum return_value_convention
+ppcfbsd_return_value (struct gdbarch *gdbarch, struct value *function,
+		      struct type *valtype, struct regcache *regcache,
+		      gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+  return ppc_sysv_abi_broken_return_value (gdbarch, function, valtype,
+					   regcache, readbuf, writebuf);
+}
+static CORE_ADDR
+ppc64_fbsd_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
+				       CORE_ADDR addr,
+				       struct target_ops *targ)
+{
+  struct gdbarch_tdep *tdep;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct target_section *s = target_section_by_addr (targ, addr);
+  tdep = gdbarch_tdep (gdbarch);
+
+  /* Check if ADDR points to a function descriptor.  */
+  if (s && strcmp (s->the_bfd_section->name, ".opd") == 0)
+    {
+      /* There may be relocations that need to be applied to the .opd
+	 section.  Unfortunately, this function may be called at a time
+	 where these relocations have not yet been performed -- this can
+	 happen for example shortly after a library has been loaded with
+	 dlopen, but ld.so has not yet applied the relocations.
+
+	 To cope with both the case where the relocation has been applied,
+	 and the case where it has not yet been applied, we do *not* read
+	 the (maybe) relocated value from target memory, but we instead
+	 read the non-relocated value from the BFD, and apply the relocation
+	 offset manually.
+
+	 This makes the assumption that all .opd entries are always relocated
+	 by the same offset the section itself was relocated.  This should
+	 always be the case for GNU/Linux executables and shared libraries.
+	 Note that other kind of object files (e.g. those added via
+	 add-symbol-files) will currently never end up here anyway, as this
+	 function accesses *target* sections only; only the main exec and
+	 shared libraries are ever added to the target.  */
+
+      gdb_byte buf[8];
+      int res;
+
+      res = bfd_get_section_contents (s->bfd, s->the_bfd_section,
+				      &buf, addr - s->addr, 8);
+      if (res != 0)
+	return extract_unsigned_integer (buf, 8, byte_order)
+	  - bfd_section_vma (s->bfd, s->the_bfd_section) + s->addr;
+   }
+
+  return addr;
+}
+
+static void
+ppcfbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* FreeBSD doesn't support the 128-bit `long double' from the psABI. */
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  if (tdep->wordsize == 4)
+    {
+      set_gdbarch_return_value (gdbarch, ppcfbsd_return_value);
+
+      set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+      set_solib_svr4_fetch_link_map_offsets (gdbarch,
+					     svr4_ilp32_fetch_link_map_offsets);
+
+      frame_unwind_append_unwinder (gdbarch, &ppcfbsd_sigtramp_frame_unwind);
+      set_gdbarch_gcore_bfd_target (gdbarch, "elf32-powerpc");
+    }
+
+  if (tdep->wordsize == 8)
+    {
+      set_gdbarch_convert_from_func_ptr_addr
+	(gdbarch, ppc64_fbsd_convert_from_func_ptr_addr);
+      set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code);
+      set_solib_svr4_fetch_link_map_offsets (gdbarch,
+					     svr4_lp64_fetch_link_map_offsets);
+      set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpc");
+    }
+
+  set_gdbarch_regset_from_core_section
+    (gdbarch, ppcfbsd_regset_from_core_section);
+
+  set_gdbarch_fetch_tls_load_module_address (gdbarch,
+					     svr4_fetch_objfile_link_map);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+void _initialize_ppcfbsd_tdep (void);
+
+void
+_initialize_ppcfbsd_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc, GDB_OSABI_FREEBSD_ELF,
+			  ppcfbsd_init_abi);
+  gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc64,
+			  GDB_OSABI_FREEBSD_ELF,
+			  ppcfbsd_init_abi);
+  gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_FREEBSD_ELF,
+			  ppcfbsd_init_abi);
+  /* Initialize the FreeBSD target descriptions.  */
+  initialize_tdesc_powerpc_32l ();
+  initialize_tdesc_powerpc_64l ();
+}
Index: ./ppcfbsd-tdep.c
--- /dev/null
+++ ./ppcfbsd-tdep.c
@@ -0,0 +1,727 @@
+/* Target-dependent code for PowerPC systems running FreeBSD.
+
+   Copyright (C) 2002, 2003, 2004, 2012
+   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 <http://www.gnu.org/licenses/>.  */
+
+#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 "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "ppc-tdep.h"
+#include "ppcfbsd-tdep.h"
+#include "solib-svr4.h"
+
+#include "features/rs6000/powerpc-32l.c"
+#include "features/rs6000/powerpc-64l.c"
+
+/* Macros for matching instructions.  Note that, since all the
+   operands are masked off before they're or-ed into the instruction,
+   you can use -1 to make masks.  */
+
+#define insn_d(opcd, rts, ra, d)                \
+  ((((opcd) & 0x3f) << 26)                      \
+   | (((rts) & 0x1f) << 21)                     \
+   | (((ra) & 0x1f) << 16)                      \
+   | ((d) & 0xffff))
+
+#define insn_ds(opcd, rts, ra, d, xo)           \
+  ((((opcd) & 0x3f) << 26)                      \
+   | (((rts) & 0x1f) << 21)                     \
+   | (((ra) & 0x1f) << 16)                      \
+   | ((d) & 0xfffc)                             \
+   | ((xo) & 0x3))
+
+#define insn_xfx(opcd, rts, spr, xo)            \
+  ((((opcd) & 0x3f) << 26)                      \
+   | (((rts) & 0x1f) << 21)                     \
+   | (((spr) & 0x1f) << 16)                     \
+   | (((spr) & 0x3e0) << 6)                     \
+   | (((xo) & 0x3ff) << 1))
+
+/* Read a PPC instruction from memory.  PPC instructions are always
+ *  big-endian, no matter what endianness the program is running in, so
+ *  we can't use read_memory_integer or one of its friends here.
+ */
+static unsigned int
+read_insn (CORE_ADDR pc)
+{
+  unsigned char buf[4];
+
+  read_memory (pc, buf, 4);
+  return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
+}
+
+
+/* An instruction to match.  */
+struct insn_pattern
+{
+  unsigned int mask;            /* mask the insn with this...  */
+  unsigned int data;            /* ...and see if it matches this.  */
+  int optional;                 /* If non-zero, this insn may be absent.  */
+};
+
+/* Return non-zero if the instructions at PC match the series
+   described in PATTERN, or zero otherwise.  PATTERN is an array of
+   'struct insn_pattern' objects, terminated by an entry whose mask is
+   zero.
+
+   When the match is successful, fill INSN[i] with what PATTERN[i]
+   matched.  If PATTERN[i] is optional, and the instruction wasn't
+   present, set INSN[i] to 0 (which is not a valid PPC instruction).
+   INSN should have as many elements as PATTERN.  Note that, if
+   PATTERN contains optional instructions which aren't present in
+   memory, then INSN will have holes, so INSN[i] isn't necessarily the
+   i'th instruction in memory.  */
+static int
+insns_match_pattern (CORE_ADDR pc, struct insn_pattern *pattern,
+		     unsigned int *insn)
+{
+  int i;
+
+  for (i = 0; pattern[i].mask; i++)
+    {
+      insn[i] = read_insn (pc);
+      if ((insn[i] & pattern[i].mask) == pattern[i].data)
+	pc += 4;
+      else if (pattern[i].optional)
+	insn[i] = 0;
+      else
+	return 0;
+    }
+
+  return 1;
+}
+
+/* Return the 'd' field of the d-form instruction INSN, properly
+   sign-extended.  */
+static CORE_ADDR
+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.  */
+static CORE_ADDR
+insn_ds_field (unsigned int insn)
+{
+  return ((((CORE_ADDR) insn & 0xfffc) ^ 0x8000) - 0x8000);
+}
+
+/* If DESC is the address of a 64-bit PowerPC FreeBSD function
+   descriptor, return the descriptor's entry point.  */
+static CORE_ADDR
+ppc64_desc_entry_point (struct gdbarch *gdbarch, CORE_ADDR desc)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  /* The first word of the descriptor is the entry point.  */
+  return (CORE_ADDR) read_memory_unsigned_integer (desc, 8, byte_order);
+}
+
+/* Pattern for the standard linkage function.  These are built by
+   build_plt_stub in elf64-ppc.c, whose GLINK argument is always
+   zero.  */
+static struct insn_pattern ppc64_standard_linkage1[] =
+  {
+    /* addis r12, r2, <any> */
+    { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 },
+
+    /* std r2, 40(r1) */
+    { -1, insn_ds (62, 2, 1, 40, 0), 0 },
+
+    /* ld r11, <any>(r12) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 },
+
+    /* addis r12, r12, 1 <optional> */
+    { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 },
+
+    /* ld r2, <any>(r12) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 },
+
+    /* addis r12, r12, 1 <optional> */
+    { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 },
+
+    /* mtctr r11 */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
+
+    /* ld r11, <any>(r12) <optional> */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 },
+
+    /* bctr */
+    { -1, 0x4e800420, 0 },
+
+    { 0, 0, 0 }
+  };
+
+#define PPC64_STANDARD_LINKAGE1_LEN \
+  (sizeof (ppc64_standard_linkage1) / sizeof (ppc64_standard_linkage1[0]))
+
+static struct insn_pattern ppc64_standard_linkage2[] =
+  {
+    /* addis r12, r2, <any> */
+    { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 },
+
+    /* std r2, 40(r1) */
+    { -1, insn_ds (62, 2, 1, 40, 0), 0 },
+
+    /* ld r11, <any>(r12) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 },
+
+    /* addi r12, r12, <any> <optional> */
+    { insn_d (-1, -1, -1, 0), insn_d (14, 12, 12, 0), 1 },
+
+    /* mtctr r11 */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
+
+    /* ld r2, <any>(r12) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 },
+
+    /* ld r11, <any>(r12) <optional> */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 },
+
+    /* bctr */
+    { -1, 0x4e800420, 0 },
+
+    { 0, 0, 0 }
+  };
+
+#define PPC64_STANDARD_LINKAGE2_LEN \
+  (sizeof (ppc64_standard_linkage2) / sizeof (ppc64_standard_linkage2[0]))
+
+static struct insn_pattern ppc64_standard_linkage3[] =
+  {
+    /* std r2, 40(r1) */
+    { -1, insn_ds (62, 2, 1, 40, 0), 0 },
+
+    /* ld r11, <any>(r2) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 0 },
+
+    /* addi r2, r2, <any> <optional> */
+    { insn_d (-1, -1, -1, 0), insn_d (14, 2, 2, 0), 1 },
+
+    /* mtctr r11 */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
+
+    /* ld r11, <any>(r2) <optional> */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 1 },
+
+    /* ld r2, <any>(r2) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 2, 0, 0), 0 },
+
+    /* bctr */
+    { -1, 0x4e800420, 0 },
+
+    { 0, 0, 0 }
+  };
+
+#define PPC64_STANDARD_LINKAGE3_LEN \
+  (sizeof (ppc64_standard_linkage3) / sizeof (ppc64_standard_linkage3[0]))
+
+
+/* When the dynamic linker is doing lazy symbol resolution, the first
+   call to a function in another object will go like this:
+
+   - The user's function calls the linkage function:
+
+     100007c4:	4b ff fc d5 	bl	10000498
+     100007c8:	e8 41 00 28 	ld	r2,40(r1)
+
+   - The linkage function loads the entry point (and other stuff) from
+     the function descriptor in the PLT, and jumps to it:
+
+     10000498:	3d 82 00 00 	addis	r12,r2,0
+     1000049c:	f8 41 00 28 	std	r2,40(r1)
+     100004a0:	e9 6c 80 98 	ld	r11,-32616(r12)
+     100004a4:	e8 4c 80 a0 	ld	r2,-32608(r12)
+     100004a8:	7d 69 03 a6 	mtctr	r11
+     100004ac:	e9 6c 80 a8 	ld	r11,-32600(r12)
+     100004b0:	4e 80 04 20 	bctr
+
+   - But since this is the first time that PLT entry has been used, it
+     sends control to its glink entry.  That loads the number of the
+     PLT entry and jumps to the common glink0 code:
+
+     10000c98:	38 00 00 00 	li	r0,0
+     10000c9c:	4b ff ff dc 	b	10000c78
+
+   - The common glink0 code then transfers control to the dynamic
+     linker's fixup code:
+
+     10000c78:	e8 41 00 28 	ld	r2,40(r1)
+     10000c7c:	3d 82 00 00 	addis	r12,r2,0
+     10000c80:	e9 6c 80 80 	ld	r11,-32640(r12)
+     10000c84:	e8 4c 80 88 	ld	r2,-32632(r12)
+     10000c88:	7d 69 03 a6 	mtctr	r11
+     10000c8c:	e9 6c 80 90 	ld	r11,-32624(r12)
+     10000c90:	4e 80 04 20 	bctr
+
+   Eventually, this code will figure out how to skip all of this,
+   including the dynamic linker.  At the moment, we just get through
+   the linkage function.  */
+
+/* If the current thread is about to execute a series of instructions
+   at PC matching the ppc64_standard_linkage pattern, and INSN is the result
+   from that pattern match, return the code address to which the
+   standard linkage function will send them.  (This doesn't deal with
+   dynamic linker lazy symbol resolution stubs.)  */
+static CORE_ADDR
+ppc64_standard_linkage1_target (struct frame_info *frame,
+				CORE_ADDR pc, unsigned int *insn)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* The address of the function descriptor this linkage function
+     references.  */
+  CORE_ADDR desc
+    = ((CORE_ADDR) get_frame_register_unsigned (frame,
+						tdep->ppc_gp0_regnum + 2)
+       + (insn_d_field (insn[0]) << 16)
+       + insn_ds_field (insn[2]));
+
+  /* The first word of the descriptor is the entry point.  Return that.  */
+  return ppc64_desc_entry_point (gdbarch, desc);
+}
+
+static CORE_ADDR
+ppc64_standard_linkage2_target (struct frame_info *frame,
+				CORE_ADDR pc, unsigned int *insn)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* The address of the function descriptor this linkage function
+     references.  */
+  CORE_ADDR desc
+    = ((CORE_ADDR) get_frame_register_unsigned (frame,
+						tdep->ppc_gp0_regnum + 2)
+       + (insn_d_field (insn[0]) << 16)
+       + insn_ds_field (insn[2]));
+
+  /* The first word of the descriptor is the entry point.  Return that.  */
+  return ppc64_desc_entry_point (gdbarch, desc);
+}
+
+static CORE_ADDR
+ppc64_standard_linkage3_target (struct frame_info *frame,
+				CORE_ADDR pc, unsigned int *insn)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* The address of the function descriptor this linkage function
+     references.  */
+  CORE_ADDR desc
+    = ((CORE_ADDR) get_frame_register_unsigned (frame,
+						tdep->ppc_gp0_regnum + 2)
+       + insn_ds_field (insn[1]));
+
+  /* The first word of the descriptor is the entry point.  Return that.  */
+  return ppc64_desc_entry_point (gdbarch, desc);
+}
+
+
+/* Given that we've begun executing a call trampoline at PC, return
+   the entry point of the function the trampoline will go to.  */
+static CORE_ADDR
+ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+{
+  unsigned int ppc64_standard_linkage1_insn[PPC64_STANDARD_LINKAGE1_LEN];
+  unsigned int ppc64_standard_linkage2_insn[PPC64_STANDARD_LINKAGE2_LEN];
+  unsigned int ppc64_standard_linkage3_insn[PPC64_STANDARD_LINKAGE3_LEN];
+  CORE_ADDR target;
+
+  if (insns_match_pattern (pc, ppc64_standard_linkage1,
+			   ppc64_standard_linkage1_insn))
+    pc = ppc64_standard_linkage1_target (frame, pc,
+					 ppc64_standard_linkage1_insn);
+  else if (insns_match_pattern (pc, ppc64_standard_linkage2,
+				ppc64_standard_linkage2_insn))
+    pc = ppc64_standard_linkage2_target (frame, pc,
+					 ppc64_standard_linkage2_insn);
+  else if (insns_match_pattern (pc, ppc64_standard_linkage3,
+				ppc64_standard_linkage3_insn))
+    pc = ppc64_standard_linkage3_target (frame, pc,
+					 ppc64_standard_linkage3_insn);
+  else
+    return 0;
+
+  /* The PLT descriptor will either point to the already resolved target
+     address, or else to a glink stub.  As the latter carry synthetic @plt
+     symbols, find_solib_trampoline_target should be able to resolve them.  */
+  target = find_solib_trampoline_target (frame, pc);
+  return target ? target : pc;
+}
+
+/* Regset descriptions.  */
+static const struct ppc_reg_offsets ppc32_fbsd_reg_offsets =
+  {
+    /* General-purpose registers.  */
+    /* .r0_offset = */ 0,
+    /* .gpr_size = */ 4,
+    /* .xr_size = */ 4,
+    /* .pc_offset = */ 144,
+    /* .ps_offset = */ -1,
+    /* .cr_offset = */ 132,
+    /* .lr_offset = */ 128,
+    /* .ctr_offset = */ 140,
+    /* .xer_offset = */ 136,
+    /* .mq_offset = */ -1,
+
+    /* Floating-point registers.  */
+    /* .f0_offset = */ 0,
+    /* .fpscr_offset = */ 256,
+    /* .fpscr_size = */ 8,
+#ifdef NOTYET
+    /* AltiVec registers.  */
+    /* .vr0_offset = */ 0,
+    /* .vscr_offset = */ 512 + 12,
+    /* .vrsave_offset = */ 512
+#endif
+  };
+
+static const struct ppc_reg_offsets ppc64_fbsd_reg_offsets =
+  {
+    /* General-purpose registers.  */
+    /* .r0_offset = */ 0,
+    /* .gpr_size = */ 8,
+    /* .xr_size = */ 8,
+    /* .pc_offset = */ 288,
+    /* .ps_offset = */ -1,
+    /* .cr_offset = */ 264,
+    /* .lr_offset = */ 256,
+    /* .ctr_offset = */ 280,
+    /* .xer_offset = */ 272,
+    /* .mq_offset = */ -1,
+
+    /* Floating-point registers.  */
+    /* .f0_offset = */ 0,
+    /* .fpscr_offset = */ 256,
+    /* .fpscr_size = */ 8,
+#ifdef NOYET
+    /* AltiVec registers.  */
+    /* .vr0_offset = */ 0,
+    /* .vscr_offset = */ 512 + 12,
+    /* .vrsave_offset = */ 528
+#endif
+  };
+
+/* FreeBSD/powerpc register set.  */
+static const struct regset ppc32_fbsd_gregset = {
+  &ppc32_fbsd_reg_offsets,
+  ppc_supply_gregset,
+  ppc_collect_gregset,
+  NULL
+};
+
+static const struct regset ppc64_fbsd_gregset = {
+  &ppc64_fbsd_reg_offsets,
+  ppc_supply_gregset,
+  ppc_collect_gregset,
+  NULL
+};
+
+static struct regset ppc32_fbsd_fpregset = {
+  &ppc32_fbsd_reg_offsets,
+  ppc_supply_fpregset,
+  ppc_collect_fpregset
+};
+
+const struct regset *
+ppc_fbsd_gregset (int wordsize)
+{
+  return wordsize == 8 ? &ppc64_fbsd_gregset : &ppc32_fbsd_gregset;
+}
+
+const struct regset *
+ppc_fbsd_fpregset (void)
+{
+  return &ppc32_fbsd_fpregset;
+}
+
+/* Return the appropriate register set for the core section identified
+   by SECT_NAME and SECT_SIZE.  */
+
+static const struct regset *
+ppcfbsd_regset_from_core_section (struct gdbarch *gdbarch,
+				  const char *sect_name, size_t sect_size)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  if (strcmp (sect_name, ".reg") == 0 && sect_size >= 148)
+    {
+      if (tdep->wordsize == 4)
+	return &ppc32_fbsd_gregset;
+      else
+	return &ppc64_fbsd_gregset;
+    }
+  if (strcmp (sect_name, ".reg2") == 0 && sect_size >= 264)
+    return &ppc32_fbsd_fpregset;
+  return NULL;
+}
+
+/* Default page size.  */
+static const int ppcfbsd_page_size = 4096;
+
+/* Offset for sigreturn(2).  */
+static const int ppcfbsd_sigreturn_offset[] = {
+  0xc,				/* FreeBSD */
+  -1
+};
+
+/* Signal trampolines.  */
+
+static int
+ppcfbsd_sigtramp_frame_sniffer (const struct frame_unwind *self,
+				struct frame_info *this_frame,
+				void **this_cache)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  CORE_ADDR pc = get_frame_pc (this_frame);
+  CORE_ADDR start_pc = (pc & ~(ppcfbsd_page_size - 1));
+  const int *offset;
+  const char *name;
+
+  find_pc_partial_function (pc, &name, NULL, NULL);
+  if (name)
+    return 0;
+
+  for (offset = ppcfbsd_sigreturn_offset; *offset != -1; offset++)
+    {
+      gdb_byte buf[2 * PPC_INSN_SIZE];
+      unsigned long insn;
+
+      if (!safe_frame_unwind_memory (this_frame, start_pc + *offset,
+				     buf, sizeof buf))
+	continue;
+
+      /* Check for "li r0,SYS_sigreturn".  */
+      insn = extract_unsigned_integer (buf, PPC_INSN_SIZE, byte_order);
+      if (insn != 0x380001a1)
+	continue;
+
+      /* Check for "sc".  */
+      insn = extract_unsigned_integer (buf + PPC_INSN_SIZE,
+				       PPC_INSN_SIZE, byte_order);
+      if (insn != 0x44000002)
+	continue;
+
+      return 1;
+    }
+
+  return 0;
+}
+
+static struct trad_frame_cache *
+ppcfbsd_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+  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 trad_frame_cache *cache;
+  CORE_ADDR addr, base, func;
+  gdb_byte buf[PPC_INSN_SIZE];
+  int i;
+
+  if (*this_cache)
+    return *this_cache;
+
+  cache = trad_frame_cache_zalloc (this_frame);
+  *this_cache = cache;
+
+  func = get_frame_pc (this_frame);
+  func &= ~(ppcfbsd_page_size - 1);
+  if (!safe_frame_unwind_memory (this_frame, func, buf, sizeof buf))
+    return cache;
+
+  base = get_frame_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch));
+  addr = base + 0x10 + 2 * tdep->wordsize;
+  for (i = 0; i < ppc_num_gprs; i++, addr += tdep->wordsize)
+    {
+      int regnum = i + tdep->ppc_gp0_regnum;
+      trad_frame_set_reg_addr (cache, regnum, addr);
+    }
+  trad_frame_set_reg_addr (cache, tdep->ppc_lr_regnum, addr);
+  addr += tdep->wordsize;
+  trad_frame_set_reg_addr (cache, tdep->ppc_cr_regnum, addr);
+  addr += tdep->wordsize;
+  trad_frame_set_reg_addr (cache, tdep->ppc_xer_regnum, addr);
+  addr += tdep->wordsize;
+  trad_frame_set_reg_addr (cache, tdep->ppc_ctr_regnum, addr);
+  addr += tdep->wordsize;
+  trad_frame_set_reg_addr (cache, gdbarch_pc_regnum (gdbarch), addr);
+  /* SRR0? */
+  addr += tdep->wordsize;
+
+  /* Construct the frame ID using the function start.  */
+  trad_frame_set_id (cache, frame_id_build (base, func));
+
+  return cache;
+}
+
+static void
+ppcfbsd_sigtramp_frame_this_id (struct frame_info *this_frame,
+				void **this_cache, struct frame_id *this_id)
+{
+  struct trad_frame_cache *cache =
+    ppcfbsd_sigtramp_frame_cache (this_frame, this_cache);
+
+  trad_frame_get_id (cache, this_id);
+}
+
+static struct value *
+ppcfbsd_sigtramp_frame_prev_register (struct frame_info *this_frame,
+				      void **this_cache, int regnum)
+{
+  struct trad_frame_cache *cache =
+    ppcfbsd_sigtramp_frame_cache (this_frame, this_cache);
+
+  return trad_frame_get_register (cache, this_frame, regnum);
+}
+
+static const struct frame_unwind ppcfbsd_sigtramp_frame_unwind = {
+  SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
+  ppcfbsd_sigtramp_frame_this_id,
+  ppcfbsd_sigtramp_frame_prev_register,
+  NULL,
+  ppcfbsd_sigtramp_frame_sniffer
+};
+
+static enum return_value_convention
+ppcfbsd_return_value (struct gdbarch *gdbarch, struct value *function,
+		      struct type *valtype, struct regcache *regcache,
+		      gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+  return ppc_sysv_abi_broken_return_value (gdbarch, function, valtype,
+					   regcache, readbuf, writebuf);
+}
+static CORE_ADDR
+ppc64_fbsd_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
+				       CORE_ADDR addr,
+				       struct target_ops *targ)
+{
+  struct gdbarch_tdep *tdep;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct target_section *s = target_section_by_addr (targ, addr);
+  tdep = gdbarch_tdep (gdbarch);
+
+  /* Check if ADDR points to a function descriptor.  */
+  if (s && strcmp (s->the_bfd_section->name, ".opd") == 0)
+    {
+      /* There may be relocations that need to be applied to the .opd
+	 section.  Unfortunately, this function may be called at a time
+	 where these relocations have not yet been performed -- this can
+	 happen for example shortly after a library has been loaded with
+	 dlopen, but ld.so has not yet applied the relocations.
+
+	 To cope with both the case where the relocation has been applied,
+	 and the case where it has not yet been applied, we do *not* read
+	 the (maybe) relocated value from target memory, but we instead
+	 read the non-relocated value from the BFD, and apply the relocation
+	 offset manually.
+
+	 This makes the assumption that all .opd entries are always relocated
+	 by the same offset the section itself was relocated.  This should
+	 always be the case for GNU/Linux executables and shared libraries.
+	 Note that other kind of object files (e.g. those added via
+	 add-symbol-files) will currently never end up here anyway, as this
+	 function accesses *target* sections only; only the main exec and
+	 shared libraries are ever added to the target.  */
+
+      gdb_byte buf[8];
+      int res;
+
+      res = bfd_get_section_contents (s->bfd, s->the_bfd_section,
+				      &buf, addr - s->addr, 8);
+      if (res != 0)
+	return extract_unsigned_integer (buf, 8, byte_order)
+	  - bfd_section_vma (s->bfd, s->the_bfd_section) + s->addr;
+   }
+
+  return addr;
+}
+
+static void
+ppcfbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* FreeBSD doesn't support the 128-bit `long double' from the psABI. */
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  if (tdep->wordsize == 4)
+    {
+      set_gdbarch_return_value (gdbarch, ppcfbsd_return_value);
+
+      set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+      set_solib_svr4_fetch_link_map_offsets (gdbarch,
+					     svr4_ilp32_fetch_link_map_offsets);
+
+      frame_unwind_append_unwinder (gdbarch, &ppcfbsd_sigtramp_frame_unwind);
+      set_gdbarch_gcore_bfd_target (gdbarch, "elf32-powerpc");
+    }
+
+  if (tdep->wordsize == 8)
+    {
+      set_gdbarch_convert_from_func_ptr_addr
+	(gdbarch, ppc64_fbsd_convert_from_func_ptr_addr);
+      set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code);
+      set_solib_svr4_fetch_link_map_offsets (gdbarch,
+					     svr4_lp64_fetch_link_map_offsets);
+      set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpc");
+    }
+
+  set_gdbarch_regset_from_core_section
+    (gdbarch, ppcfbsd_regset_from_core_section);
+
+  set_gdbarch_fetch_tls_load_module_address (gdbarch,
+					     svr4_fetch_objfile_link_map);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+void _initialize_ppcfbsd_tdep (void);
+
+void
+_initialize_ppcfbsd_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc, GDB_OSABI_FREEBSD_ELF,
+			  ppcfbsd_init_abi);
+  gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc64,
+			  GDB_OSABI_FREEBSD_ELF,
+			  ppcfbsd_init_abi);
+  gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_FREEBSD_ELF,
+			  ppcfbsd_init_abi);
+  /* Initialize the FreeBSD target descriptions.  */
+  initialize_tdesc_powerpc_32l ();
+  initialize_tdesc_powerpc_64l ();
+}
Index: config/powerpc/fbsd.mh
--- /dev/null
+++ config/powerpc/fbsd.mh
@@ -0,0 +1,5 @@
+# Host: FreeBSD/powerpc
+NATDEPFILES= fbsd-nat.o fork-child.o inf-ptrace.o ppcfbsd-nat.o bsd-kvm.o
+
+LOADLIBES= -lkvm
+
Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.1217
diff -u -r1.1217 Makefile.in
--- Makefile.in	15 Nov 2012 16:12:16 -0000	1.1217
+++ Makefile.in	19 Nov 2012 21:24:15 -0000
@@ -557,7 +557,8 @@
 	moxie-tdep.o \
 	mt-tdep.o \
 	nto-tdep.o \
-	ppc-linux-tdep.o ppcnbsd-tdep.o ppcobsd-tdep.o ppc-sysv-tdep.o \
+	ppc-linux-tdep.o ppcfbsd-tdep.o ppcnbsd-tdep.o ppcobsd-tdep.o \
+	ppc-sysv-tdep.o \
 	rl78-tdep.o \
 	rs6000-aix-tdep.o rs6000-tdep.o \
 	rx-tdep.o \
@@ -769,7 +770,7 @@
 osf-share/cma_sched.h \
 common/gdb_signals.h common/gdb_thread_db.h common/gdb_vecs.h \
 common/i386-xstate.h common/linux-ptrace.h \
-proc-utils.h arm-tdep.h ax-gdb.h ppcnbsd-tdep.h	\
+proc-utils.h arm-tdep.h ax-gdb.h ppcfbsd-tdep.h ppcnbsd-tdep.h	\
 cli-out.h gdb_expat.h breakpoint.h infcall.h obsd-tdep.h \
 exec.h m32r-tdep.h osabi.h gdbcore.h solib-som.h amd64bsd-nat.h \
 i386bsd-nat.h xml-support.h xml-tdesc.h alphabsd-tdep.h gdb_obstack.h \
@@ -1479,6 +1480,7 @@
 	somread.c solib-som.c \
 	posix-hdep.c \
 	ppc-sysv-tdep.c ppc-linux-nat.c ppc-linux-tdep.c \
+	ppcfbsd-nat.c ppcfbsd-tdep.c \
 	ppcnbsd-nat.c ppcnbsd-tdep.c \
 	ppcobsd-nat.c ppcobsd-tdep.c \
 	procfs.c \
Index: configure.host
===================================================================
RCS file: /cvs/src/src/gdb/configure.host,v
retrieving revision 1.107
diff -u -r1.107 configure.host
--- configure.host	30 May 2012 19:41:34 -0000	1.107
+++ configure.host	19 Nov 2012 21:24:15 -0000
@@ -125,6 +125,7 @@
 
 powerpc-*-aix* | rs6000-*-*)
 			gdb_host=aix ;;
+powerpc*-*-freebsd*)	gdb_host=fbsd ;;
 powerpc-*-linux*)	gdb_host=linux ;;
 powerpc-*-netbsd* | powerpc-*-knetbsd*-gnu)
 			gdb_host=nbsd ;;
Index: configure.tgt
===================================================================
RCS file: /cvs/src/src/gdb/configure.tgt,v
retrieving revision 1.256
diff -u -r1.256 configure.tgt
--- configure.tgt	1 Aug 2012 19:34:29 -0000	1.256
+++ configure.tgt	19 Nov 2012 21:24:15 -0000
@@ -383,6 +383,12 @@
 	gdb_target_obs="mt-tdep.o"
 	;;
 
+powerpc*-*-freebsd*)
+	# Target: FreeBSD/powerpc
+	gdb_target_obs="rs6000-tdep.o ppc-sysv-tdep.o ppcfbsd-tdep.o \
+			solib-svr4.o"
+	;;
+
 powerpc-*-netbsd* | powerpc-*-knetbsd*-gnu)
 	# Target: NetBSD/powerpc
 	gdb_target_obs="rs6000-tdep.o ppc-sysv-tdep.o ppcnbsd-tdep.o \

^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FreeBSD powerpc support
  2012-11-19 21:44 [PATCH] FreeBSD powerpc support Andreas Tobler
@ 2012-11-23 19:34 ` Pedro Alves
  2012-11-27 17:45   ` Andreas Tobler
  0 siblings, 1 reply; 12+ messages in thread
From: Pedro Alves @ 2012-11-23 19:34 UTC (permalink / raw)
  To: Andreas Tobler; +Cc: gdb-patches

Hello,

On 11/19/2012 09:43 PM, Andreas Tobler wrote:
> Hi all,
>
> After a longer timeout here again :)
>
> The attached patch adds support for FreeBSD PowerPC, 32-bit and 64-bit.
> It is derived from ppcobsd* and ppc-linux with FreeBSD additions.
>
> There is room for improvement :) And I will continue, but I'd like to
> see this patch in the gdb cvs because it will be much easier for me fix
> outstanding issues when I can work with cvs iso. of local revisions.

Eh.  If it's easier, then maybe you're not using the proper tools; there's
always quilt.  :-)  Or better nowadays, you could also put it
in a public git repo somewhere.  We have a git mirror of cvs.
That said, I'm really not against putting it in early, if it's not riddled
with hacks.

> Also, other people might have a use of this work, even if not complete.
>
> Currently missing/incomplete:
> - Altivec support, kernel bits are missing.
> - HW watchpoints, also kernel bits are missing.
> - thread support.
> - tls support.
> - some sig tests.

I've skimmed the patch, and didn't notice anything horrible.
Then again, I'm on the low end of the scale that measures
PowerPC or FreeBSD expertness...

- Please make sure there's a blank line between introductory comment
  and function.

- I noticed that a few functions don't have introductory comment.

- If the function implements of a target/gdbarch/etc. method, then
  comment it as such.  E.g.,

  /* This is the implementation of gdbarch method FOOBAR.  */

- I noticed some functions with long comments are copies of existing
  code of other ports.  I wonder if we could perhaps share more code.


> +/* Read a PPC instruction from memory.  PPC instructions are always
> + *  big-endian, no matter what endianness the program is running in, so
> + *  we can't use read_memory_integer or one of its friends here.

read_memory_unsigned_integer nowadays has a byte_order parameter,
so just pass it BFD_ENDIAN_BIG, and you're set.

> + */
> +static unsigned int
> +read_insn (CORE_ADDR pc)
> +{
> +  unsigned char buf[4];
> +
> +  read_memory (pc, buf, 4);
> +  return (buf[0] << 24) | (buf[1] << 16) | (buf[2] << 8) | buf[3];
> +}
> +

> +
> +#define PPC64_STANDARD_LINKAGE2_LEN \
> +  (sizeof (ppc64_standard_linkage2) / sizeof (ppc64_standard_linkage2[0]))
> +

Use the existing ARRAY_SIZE macro.

+/* Signal trampolines.  */
> +
> +static int
> +ppcfbsd_sigtramp_frame_sniffer (const struct frame_unwind *self,
> +				struct frame_info *this_frame,
> +				void **this_cache)
> +{
> +  struct gdbarch *gdbarch = get_frame_arch (this_frame);
> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
> +  CORE_ADDR pc = get_frame_pc (this_frame);
> +  CORE_ADDR start_pc = (pc & ~(ppcfbsd_page_size - 1));
> +  const int *offset;
> +  const char *name;
> +
> +  find_pc_partial_function (pc, &name, NULL, NULL);
> +  if (name)
> +    return 0;

For some reason this bailing out if name is not null jumped at me.
It's not obvious to me what that means, so it felt like it deserves
a comment.

On 11/19/2012 09:43 PM, Andreas Tobler wrote:
> --- configure.host	30 May 2012 19:41:34 -0000	1.107
> +++ configure.host	19 Nov 2012 21:24:15 -0000
> @@ -125,6 +125,7 @@
>
>  powerpc-*-aix* | rs6000-*-*)
>  			gdb_host=aix ;;
> +powerpc*-*-freebsd*)	gdb_host=fbsd ;;

This seems to be 'powerpc-*-freebsd*' elsewhere I looked (top level, bfd).
Why the extra wildcard?

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FreeBSD powerpc support
  2012-11-23 19:34 ` Pedro Alves
@ 2012-11-27 17:45   ` Andreas Tobler
  2012-12-11 15:48     ` PING " Andreas Tobler
  2012-12-11 20:07     ` Pedro Alves
  0 siblings, 2 replies; 12+ messages in thread
From: Andreas Tobler @ 2012-11-27 17:45 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

[-- Attachment #1: Type: text/plain, Size: 4020 bytes --]

Hello again,

took a bit longer.

On 23.11.12 20:33, Pedro Alves wrote:

>> The attached patch adds support for FreeBSD PowerPC, 32-bit and 64-bit.
>> It is derived from ppcobsd* and ppc-linux with FreeBSD additions.
>>
>> There is room for improvement :) And I will continue, but I'd like to
>> see this patch in the gdb cvs because it will be much easier for me fix
>> outstanding issues when I can work with cvs iso. of local revisions.
> 
> Eh.  If it's easier, then maybe you're not using the proper tools; there's
> always quilt.  :-)  Or better nowadays, you could also put it
> in a public git repo somewhere.  We have a git mirror of cvs.
> That said, I'm really not against putting it in early, if it's not riddled
> with hacks.

Might be that I do not use the latest and greatest tools.
The room for improvement, above, is in the direction of general FreeBSD
stuff, not only limited to this particular port.

>> Also, other people might have a use of this work, even if not complete.
>>
>> Currently missing/incomplete:
>> - Altivec support, kernel bits are missing.
>> - HW watchpoints, also kernel bits are missing.
>> - thread support.
>> - tls support.
>> - some sig tests.
> 
> I've skimmed the patch, and didn't notice anything horrible.
> Then again, I'm on the low end of the scale that measures
> PowerPC or FreeBSD expertness...
> 
> - Please make sure there's a blank line between introductory comment
>   and function.

I hope I didn't miss them.

> - I noticed that a few functions don't have introductory comment.

Also, I put one in where I could.

> - If the function implements of a target/gdbarch/etc. method, then
>   comment it as such.  E.g.,
> 
>   /* This is the implementation of gdbarch method FOOBAR.  */
> 
> - I noticed some functions with long comments are copies of existing
>   code of other ports.  I wonder if we could perhaps share more code.

True, here I do not know how to share, maybe a common ppc64-tdep-common.c?

>> +/* Read a PPC instruction from memory.  PPC instructions are always
>> + *  big-endian, no matter what endianness the program is running in, so
>> + *  we can't use read_memory_integer or one of its friends here.
> 
> read_memory_unsigned_integer nowadays has a byte_order parameter,
> so just pass it BFD_ENDIAN_BIG, and you're set.

Done. Even tested on ppc64-linux. I might send a patch for
ppc-linux-tdep.c as well. Likewise for the below.

>> +#define PPC64_STANDARD_LINKAGE2_LEN \
>> +  (sizeof (ppc64_standard_linkage2) / sizeof (ppc64_standard_linkage2[0]))
>> +
> 
> Use the existing ARRAY_SIZE macro.

Done.

> +/* Signal trampolines.  */
>> +
>> +static int
>> +ppcfbsd_sigtramp_frame_sniffer (const struct frame_unwind *self,
>> +				struct frame_info *this_frame,
>> +				void **this_cache)
>> +{
>> +  struct gdbarch *gdbarch = get_frame_arch (this_frame);
>> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
>> +  CORE_ADDR pc = get_frame_pc (this_frame);
>> +  CORE_ADDR start_pc = (pc & ~(ppcfbsd_page_size - 1));
>> +  const int *offset;
>> +  const char *name;
>> +
>> +  find_pc_partial_function (pc, &name, NULL, NULL);
>> +  if (name)
>> +    return 0;
> 
> For some reason this bailing out if name is not null jumped at me.
> It's not obvious to me what that means, so it felt like it deserves
> a comment.

Also done, I hope I match the expectations.

> On 11/19/2012 09:43 PM, Andreas Tobler wrote:
>> --- configure.host	30 May 2012 19:41:34 -0000	1.107
>> +++ configure.host	19 Nov 2012 21:24:15 -0000
>> @@ -125,6 +125,7 @@
>>
>>  powerpc-*-aix* | rs6000-*-*)
>>  			gdb_host=aix ;;
>> +powerpc*-*-freebsd*)	gdb_host=fbsd ;;
> 
> This seems to be 'powerpc-*-freebsd*' elsewhere I looked (top level, bfd).
> Why the extra wildcard?


Hm, here I'm not sure. My targets report as powerpc-unknown-freebsd*
(32-bit) and powerpc64-unknown-freebsd* (64-bit). So I thought I have to
match both. Is this not correct?

Attached a revised version of the diff.

Pedro, again thank you very much for the feedback.

Andreas


[-- Attachment #2: gdb_ppc_20121127-1.diff --]
[-- Type: text/plain, Size: 34844 bytes --]

Index: Makefile.in
===================================================================
RCS file: /cvs/src/src/gdb/Makefile.in,v
retrieving revision 1.1218
diff -u -r1.1218 Makefile.in
--- Makefile.in	26 Nov 2012 19:23:50 -0000	1.1218
+++ Makefile.in	27 Nov 2012 17:13:27 -0000
@@ -560,7 +560,8 @@
 	moxie-tdep.o \
 	mt-tdep.o \
 	nto-tdep.o \
-	ppc-linux-tdep.o ppcnbsd-tdep.o ppcobsd-tdep.o ppc-sysv-tdep.o \
+	ppc-linux-tdep.o ppcfbsd-tdep.o ppcnbsd-tdep.o ppcobsd-tdep.o \
+	ppc-sysv-tdep.o \
 	rl78-tdep.o \
 	rs6000-aix-tdep.o rs6000-tdep.o \
 	rx-tdep.o \
@@ -772,7 +773,7 @@
 osf-share/cma_sched.h \
 common/gdb_signals.h common/gdb_thread_db.h common/gdb_vecs.h \
 common/i386-xstate.h common/linux-ptrace.h \
-proc-utils.h arm-tdep.h ax-gdb.h ppcnbsd-tdep.h	\
+proc-utils.h arm-tdep.h ax-gdb.h ppcfbsd-tdep.h ppcnbsd-tdep.h	\
 cli-out.h gdb_expat.h breakpoint.h infcall.h obsd-tdep.h \
 exec.h m32r-tdep.h osabi.h gdbcore.h solib-som.h amd64bsd-nat.h \
 i386bsd-nat.h xml-support.h xml-tdesc.h alphabsd-tdep.h gdb_obstack.h \
@@ -1483,6 +1484,7 @@
 	somread.c solib-som.c \
 	posix-hdep.c \
 	ppc-sysv-tdep.c ppc-linux-nat.c ppc-linux-tdep.c \
+	ppcfbsd-nat.c ppcfbsd-tdep.c \
 	ppcnbsd-nat.c ppcnbsd-tdep.c \
 	ppcobsd-nat.c ppcobsd-tdep.c \
 	procfs.c \
Index: configure.host
===================================================================
RCS file: /cvs/src/src/gdb/configure.host,v
retrieving revision 1.107
diff -u -r1.107 configure.host
--- configure.host	30 May 2012 19:41:34 -0000	1.107
+++ configure.host	27 Nov 2012 17:13:27 -0000
@@ -125,6 +125,7 @@
 
 powerpc-*-aix* | rs6000-*-*)
 			gdb_host=aix ;;
+powerpc*-*-freebsd*)	gdb_host=fbsd ;;
 powerpc-*-linux*)	gdb_host=linux ;;
 powerpc-*-netbsd* | powerpc-*-knetbsd*-gnu)
 			gdb_host=nbsd ;;
Index: configure.tgt
===================================================================
RCS file: /cvs/src/src/gdb/configure.tgt,v
retrieving revision 1.256
diff -u -r1.256 configure.tgt
--- configure.tgt	1 Aug 2012 19:34:29 -0000	1.256
+++ configure.tgt	27 Nov 2012 17:13:27 -0000
@@ -383,6 +383,12 @@
 	gdb_target_obs="mt-tdep.o"
 	;;
 
+powerpc*-*-freebsd*)
+	# Target: FreeBSD/powerpc
+	gdb_target_obs="rs6000-tdep.o ppc-sysv-tdep.o ppcfbsd-tdep.o \
+			solib-svr4.o"
+	;;
+
 powerpc-*-netbsd* | powerpc-*-knetbsd*-gnu)
 	# Target: NetBSD/powerpc
 	gdb_target_obs="rs6000-tdep.o ppc-sysv-tdep.o ppcnbsd-tdep.o \
Index: ./ppcfbsd-tdep.h
--- /dev/null
+++ ./ppcfbsd-tdep.h
@@ -0,0 +1,34 @@
+/* Target-dependent code for GDB on PowerPC systems running FreeBSD.
+
+   Copyright (C) 2012
+   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 <http://www.gnu.org/licenses/>.  */
+
+#ifndef PPCFBSD_TDEP_H
+#define PPCFBSD_TDEP_H
+
+struct regset;
+
+/* From ppcfbsd-tdep.c ...  */
+const struct regset *ppc_fbsd_gregset (int);
+const struct regset *ppc_fbsd_fpregset (void);
+
+/* FreeBSD target descriptions.  */
+extern struct target_desc *tdesc_powerpc_32l;
+extern struct target_desc *tdesc_powerpc_64l;
+
+#endif /* PPCFBSD_TDEP_H  */
Index: ./ppcfbsd-tdep.c
--- /dev/null
+++ ./ppcfbsd-tdep.c
@@ -0,0 +1,747 @@
+/* Target-dependent code for PowerPC systems running FreeBSD.
+
+   Copyright (C) 2012
+   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 <http://www.gnu.org/licenses/>.  */
+
+#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 "gdb_assert.h"
+#include "gdb_string.h"
+
+#include "ppc-tdep.h"
+#include "ppcfbsd-tdep.h"
+#include "solib-svr4.h"
+
+#include "features/rs6000/powerpc-32l.c"
+#include "features/rs6000/powerpc-64l.c"
+
+/* Macros for matching instructions.  Note that, since all the
+   operands are masked off before they're or-ed into the instruction,
+   you can use -1 to make masks.  */
+
+#define insn_d(opcd, rts, ra, d)                \
+  ((((opcd) & 0x3f) << 26)                      \
+   | (((rts) & 0x1f) << 21)                     \
+   | (((ra) & 0x1f) << 16)                      \
+   | ((d) & 0xffff))
+
+#define insn_ds(opcd, rts, ra, d, xo)           \
+  ((((opcd) & 0x3f) << 26)                      \
+   | (((rts) & 0x1f) << 21)                     \
+   | (((ra) & 0x1f) << 16)                      \
+   | ((d) & 0xfffc)                             \
+   | ((xo) & 0x3))
+
+#define insn_xfx(opcd, rts, spr, xo)            \
+  ((((opcd) & 0x3f) << 26)                      \
+   | (((rts) & 0x1f) << 21)                     \
+   | (((spr) & 0x1f) << 16)                     \
+   | (((spr) & 0x3e0) << 6)                     \
+   | (((xo) & 0x3ff) << 1))
+
+/* Read a PPC instruction from memory.  PPC instructions are always
+   big-endian, no matter what endianness the program is running in, so
+   we can hardcode BFD_ENDIAN_BIG for read_memory_unsigned_integer.  */
+
+static unsigned int
+read_insn (CORE_ADDR pc)
+{
+  return read_memory_unsigned_integer (pc, 4, BFD_ENDIAN_BIG);
+}
+
+/* An instruction to match.  */
+
+struct insn_pattern
+{
+  unsigned int mask;            /* mask the insn with this...  */
+  unsigned int data;            /* ...and see if it matches this.  */
+  int optional;                 /* If non-zero, this insn may be absent.  */
+};
+
+/* Return non-zero if the instructions at PC match the series
+   described in PATTERN, or zero otherwise.  PATTERN is an array of
+   'struct insn_pattern' objects, terminated by an entry whose mask is
+   zero.
+
+   When the match is successful, fill INSN[i] with what PATTERN[i]
+   matched.  If PATTERN[i] is optional, and the instruction wasn't
+   present, set INSN[i] to 0 (which is not a valid PPC instruction).
+   INSN should have as many elements as PATTERN.  Note that, if
+   PATTERN contains optional instructions which aren't present in
+   memory, then INSN will have holes, so INSN[i] isn't necessarily the
+   i'th instruction in memory.  */
+
+static int
+insns_match_pattern (CORE_ADDR pc, struct insn_pattern *pattern,
+		     unsigned int *insn)
+{
+  int i;
+
+  for (i = 0; pattern[i].mask; i++)
+    {
+      insn[i] = read_insn (pc);
+      if ((insn[i] & pattern[i].mask) == pattern[i].data)
+	pc += 4;
+      else if (pattern[i].optional)
+	insn[i] = 0;
+      else
+	return 0;
+    }
+
+  return 1;
+}
+
+/* Return the 'd' field of the d-form instruction INSN, properly
+   sign-extended.  */
+
+static CORE_ADDR
+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.  */
+
+static CORE_ADDR
+insn_ds_field (unsigned int insn)
+{
+  return ((((CORE_ADDR) insn & 0xfffc) ^ 0x8000) - 0x8000);
+}
+
+/* If DESC is the address of a 64-bit PowerPC FreeBSD function
+   descriptor, return the descriptor's entry point.  */
+
+static CORE_ADDR
+ppc64_desc_entry_point (struct gdbarch *gdbarch, CORE_ADDR desc)
+{
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  /* The first word of the descriptor is the entry point.  */
+  return (CORE_ADDR) read_memory_unsigned_integer (desc, 8, byte_order);
+}
+
+/* Pattern for the standard linkage function.  These are built by
+   build_plt_stub in elf64-ppc.c, whose GLINK argument is always
+   zero.  */
+
+static struct insn_pattern ppc64_standard_linkage1[] =
+  {
+    /* addis r12, r2, <any> */
+    { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 },
+
+    /* std r2, 40(r1) */
+    { -1, insn_ds (62, 2, 1, 40, 0), 0 },
+
+    /* ld r11, <any>(r12) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 },
+
+    /* addis r12, r12, 1 <optional> */
+    { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 },
+
+    /* ld r2, <any>(r12) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 },
+
+    /* addis r12, r12, 1 <optional> */
+    { insn_d (-1, -1, -1, -1), insn_d (15, 12, 12, 1), 1 },
+
+    /* mtctr r11 */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
+
+    /* ld r11, <any>(r12) <optional> */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 },
+
+    /* bctr */
+    { -1, 0x4e800420, 0 },
+
+    { 0, 0, 0 }
+  };
+
+#define PPC64_STANDARD_LINKAGE1_LEN ARRAY_SIZE (ppc64_standard_linkage1)
+
+static struct insn_pattern ppc64_standard_linkage2[] =
+  {
+    /* addis r12, r2, <any> */
+    { insn_d (-1, -1, -1, 0), insn_d (15, 12, 2, 0), 0 },
+
+    /* std r2, 40(r1) */
+    { -1, insn_ds (62, 2, 1, 40, 0), 0 },
+
+    /* ld r11, <any>(r12) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 0 },
+
+    /* addi r12, r12, <any> <optional> */
+    { insn_d (-1, -1, -1, 0), insn_d (14, 12, 12, 0), 1 },
+
+    /* mtctr r11 */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
+
+    /* ld r2, <any>(r12) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 12, 0, 0), 0 },
+
+    /* ld r11, <any>(r12) <optional> */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 12, 0, 0), 1 },
+
+    /* bctr */
+    { -1, 0x4e800420, 0 },
+
+    { 0, 0, 0 }
+  };
+
+#define PPC64_STANDARD_LINKAGE2_LEN ARRAY_SIZE (ppc64_standard_linkage2)
+
+static struct insn_pattern ppc64_standard_linkage3[] =
+  {
+    /* std r2, 40(r1) */
+    { -1, insn_ds (62, 2, 1, 40, 0), 0 },
+
+    /* ld r11, <any>(r2) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 0 },
+
+    /* addi r2, r2, <any> <optional> */
+    { insn_d (-1, -1, -1, 0), insn_d (14, 2, 2, 0), 1 },
+
+    /* mtctr r11 */
+    { insn_xfx (-1, -1, -1, -1), insn_xfx (31, 11, 9, 467), 0 },
+
+    /* ld r11, <any>(r2) <optional> */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 11, 2, 0, 0), 1 },
+
+    /* ld r2, <any>(r2) */
+    { insn_ds (-1, -1, -1, 0, -1), insn_ds (58, 2, 2, 0, 0), 0 },
+
+    /* bctr */
+    { -1, 0x4e800420, 0 },
+
+    { 0, 0, 0 }
+  };
+
+#define PPC64_STANDARD_LINKAGE3_LEN ARRAY_SIZE (ppc64_standard_linkage3)
+
+/* When the dynamic linker is doing lazy symbol resolution, the first
+   call to a function in another object will go like this:
+
+   - The user's function calls the linkage function:
+
+	 100007c4:	4b ff fc d5		bl	10000498
+	 100007c8:	e8 41 00 28		ld	r2,40(r1)
+
+   - The linkage function loads the entry point (and other stuff) from
+	 the function descriptor in the PLT, and jumps to it:
+
+	 10000498:	3d 82 00 00		addis	r12,r2,0
+	 1000049c:	f8 41 00 28		std	r2,40(r1)
+	 100004a0:	e9 6c 80 98		ld	r11,-32616(r12)
+	 100004a4:	e8 4c 80 a0		ld	r2,-32608(r12)
+	 100004a8:	7d 69 03 a6		mtctr	r11
+	 100004ac:	e9 6c 80 a8		ld	r11,-32600(r12)
+	 100004b0:	4e 80 04 20		bctr
+
+   - But since this is the first time that PLT entry has been used, it
+	 sends control to its glink entry.  That loads the number of the
+	 PLT entry and jumps to the common glink0 code:
+
+	 10000c98:	38 00 00 00		li	r0,0
+	 10000c9c:	4b ff ff dc		b	10000c78
+
+   - The common glink0 code then transfers control to the dynamic
+	 linker's fixup code:
+
+	 10000c78:	e8 41 00 28		ld	r2,40(r1)
+	 10000c7c:	3d 82 00 00		addis	r12,r2,0
+	 10000c80:	e9 6c 80 80		ld	r11,-32640(r12)
+	 10000c84:	e8 4c 80 88		ld	r2,-32632(r12)
+	 10000c88:	7d 69 03 a6		mtctr	r11
+	 10000c8c:	e9 6c 80 90		ld	r11,-32624(r12)
+	 10000c90:	4e 80 04 20		bctr
+
+   Eventually, this code will figure out how to skip all of this,
+   including the dynamic linker.  At the moment, we just get through
+   the linkage function.  */
+
+/* If the current thread is about to execute a series of instructions
+   at PC matching the ppc64_standard_linkage pattern, and INSN is the result
+   from that pattern match, return the code address to which the
+   standard linkage function will send them.  (This doesn't deal with
+   dynamic linker lazy symbol resolution stubs.)  */
+
+static CORE_ADDR
+ppc64_standard_linkage1_target (struct frame_info *frame,
+				CORE_ADDR pc, unsigned int *insn)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* The address of the function descriptor this linkage function
+     references.  */
+  CORE_ADDR desc
+    = ((CORE_ADDR) get_frame_register_unsigned (frame,
+						tdep->ppc_gp0_regnum + 2)
+       + (insn_d_field (insn[0]) << 16)
+       + insn_ds_field (insn[2]));
+
+  /* The first word of the descriptor is the entry point.  Return that.  */
+  return ppc64_desc_entry_point (gdbarch, desc);
+}
+
+static CORE_ADDR
+ppc64_standard_linkage2_target (struct frame_info *frame,
+				CORE_ADDR pc, unsigned int *insn)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* The address of the function descriptor this linkage function
+     references.  */
+  CORE_ADDR desc
+    = ((CORE_ADDR) get_frame_register_unsigned (frame,
+						tdep->ppc_gp0_regnum + 2)
+       + (insn_d_field (insn[0]) << 16)
+       + insn_ds_field (insn[2]));
+
+  /* The first word of the descriptor is the entry point.  Return that.  */
+  return ppc64_desc_entry_point (gdbarch, desc);
+}
+
+static CORE_ADDR
+ppc64_standard_linkage3_target (struct frame_info *frame,
+				CORE_ADDR pc, unsigned int *insn)
+{
+  struct gdbarch *gdbarch = get_frame_arch (frame);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* The address of the function descriptor this linkage function
+     references.  */
+  CORE_ADDR desc
+    = ((CORE_ADDR) get_frame_register_unsigned (frame,
+						tdep->ppc_gp0_regnum + 2)
+       + insn_ds_field (insn[1]));
+
+  /* The first word of the descriptor is the entry point.  Return that.  */
+  return ppc64_desc_entry_point (gdbarch, desc);
+}
+
+
+/* Given that we've begun executing a call trampoline at PC, return
+   the entry point of the function the trampoline will go to.  */
+
+static CORE_ADDR
+ppc64_skip_trampoline_code (struct frame_info *frame, CORE_ADDR pc)
+{
+  unsigned int ppc64_standard_linkage1_insn[PPC64_STANDARD_LINKAGE1_LEN];
+  unsigned int ppc64_standard_linkage2_insn[PPC64_STANDARD_LINKAGE2_LEN];
+  unsigned int ppc64_standard_linkage3_insn[PPC64_STANDARD_LINKAGE3_LEN];
+  CORE_ADDR target;
+
+  if (insns_match_pattern (pc, ppc64_standard_linkage1,
+			   ppc64_standard_linkage1_insn))
+    pc = ppc64_standard_linkage1_target (frame, pc,
+					 ppc64_standard_linkage1_insn);
+  else if (insns_match_pattern (pc, ppc64_standard_linkage2,
+				ppc64_standard_linkage2_insn))
+    pc = ppc64_standard_linkage2_target (frame, pc,
+					 ppc64_standard_linkage2_insn);
+  else if (insns_match_pattern (pc, ppc64_standard_linkage3,
+				ppc64_standard_linkage3_insn))
+    pc = ppc64_standard_linkage3_target (frame, pc,
+					 ppc64_standard_linkage3_insn);
+  else
+    return 0;
+
+  /* The PLT descriptor will either point to the already resolved target
+     address, or else to a glink stub.  As the latter carry synthetic @plt
+     symbols, find_solib_trampoline_target should be able to resolve them.  */
+  target = find_solib_trampoline_target (frame, pc);
+  return target ? target : pc;
+}
+
+/* 32-bit regset descriptions.  */
+
+static const struct ppc_reg_offsets ppc32_fbsd_reg_offsets =
+  {
+	/* General-purpose registers.  */
+	/* .r0_offset = */     0,
+	/* .gpr_size = */      4,
+	/* .xr_size = */       4,
+	/* .pc_offset = */     144,
+	/* .ps_offset = */     -1,
+	/* .cr_offset = */     132,
+	/* .lr_offset = */     128,
+	/* .ctr_offset = */    140,
+	/* .xer_offset = */    136,
+	/* .mq_offset = */     -1,
+
+	/* Floating-point registers.  */
+	/* .f0_offset = */     0,
+	/* .fpscr_offset = */  256,
+	/* .fpscr_size = */    8,
+#ifdef NOTYET
+	/* AltiVec registers.  */
+	/* .vr0_offset = */    0,
+	/* .vscr_offset = */   512 + 12,
+	/* .vrsave_offset = */ 512
+#endif
+  };
+
+/* 64-bit regset descriptions.  */
+
+static const struct ppc_reg_offsets ppc64_fbsd_reg_offsets =
+  {
+	/* General-purpose registers.  */
+	/* .r0_offset = */     0,
+	/* .gpr_size = */      8,
+	/* .xr_size = */       8,
+	/* .pc_offset = */     288,
+	/* .ps_offset = */     -1,
+	/* .cr_offset = */     264,
+	/* .lr_offset = */     256,
+	/* .ctr_offset = */    280,
+	/* .xer_offset = */    272,
+	/* .mq_offset = */     -1,
+
+	/* Floating-point registers.  */
+	/* .f0_offset = */     0,
+	/* .fpscr_offset = */  256,
+	/* .fpscr_size = */    8,
+#ifdef NOYET
+	/* AltiVec registers.  */
+	/* .vr0_offset = */    0,
+	/* .vscr_offset = */   512 + 12,
+	/* .vrsave_offset = */ 528
+#endif
+  };
+
+/* 32-bit general-purpose register set.  */
+
+static const struct regset ppc32_fbsd_gregset = {
+  &ppc32_fbsd_reg_offsets,
+  ppc_supply_gregset,
+  ppc_collect_gregset,
+  NULL
+};
+
+/* 64-bit general-purpose register set.  */
+
+static const struct regset ppc64_fbsd_gregset = {
+  &ppc64_fbsd_reg_offsets,
+  ppc_supply_gregset,
+  ppc_collect_gregset,
+  NULL
+};
+
+/* 32-/64-bit floating-point register set.  */
+
+static struct regset ppc32_fbsd_fpregset = {
+  &ppc32_fbsd_reg_offsets,
+  ppc_supply_fpregset,
+  ppc_collect_fpregset
+};
+
+const struct regset *
+ppc_fbsd_gregset (int wordsize)
+{
+  return wordsize == 8 ? &ppc64_fbsd_gregset : &ppc32_fbsd_gregset;
+}
+
+const struct regset *
+ppc_fbsd_fpregset (void)
+{
+  return &ppc32_fbsd_fpregset;
+}
+
+/* Return the appropriate register set for the core section identified
+   by SECT_NAME and SECT_SIZE.  */
+
+static const struct regset *
+ppcfbsd_regset_from_core_section (struct gdbarch *gdbarch,
+				  const char *sect_name, size_t sect_size)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  if (strcmp (sect_name, ".reg") == 0 && sect_size >= 148)
+    {
+      if (tdep->wordsize == 4)
+	return &ppc32_fbsd_gregset;
+      else
+	return &ppc64_fbsd_gregset;
+    }
+  if (strcmp (sect_name, ".reg2") == 0 && sect_size >= 264)
+    return &ppc32_fbsd_fpregset;
+  return NULL;
+}
+
+/* Default page size.  */
+
+static const int ppcfbsd_page_size = 4096;
+
+/* Offset for sigreturn(2).  */
+
+static const int ppcfbsd_sigreturn_offset[] = {
+  0xc,				/* FreeBSD 32-bit  */
+  -1
+};
+
+/* Signal trampolines.  */
+
+static int
+ppcfbsd_sigtramp_frame_sniffer (const struct frame_unwind *self,
+				struct frame_info *this_frame,
+				void **this_cache)
+{
+  struct gdbarch *gdbarch = get_frame_arch (this_frame);
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  CORE_ADDR pc = get_frame_pc (this_frame);
+  CORE_ADDR start_pc = (pc & ~(ppcfbsd_page_size - 1));
+  const int *offset;
+  const char *name;
+
+  /* A stack trampoline is detected if no name is associated
+   to the current pc and if it points inside a trampoline
+   sequence.  */
+
+  find_pc_partial_function (pc, &name, NULL, NULL);
+
+  /* If we have a name, we have no trampoline, return.  */
+  if (name)
+    return 0;
+
+  for (offset = ppcfbsd_sigreturn_offset; *offset != -1; offset++)
+    {
+      gdb_byte buf[2 * PPC_INSN_SIZE];
+      unsigned long insn;
+
+      if (!safe_frame_unwind_memory (this_frame, start_pc + *offset,
+				     buf, sizeof buf))
+	continue;
+
+      /* Check for "li r0,SYS_sigreturn".  */
+      insn = extract_unsigned_integer (buf, PPC_INSN_SIZE, byte_order);
+      if (insn != 0x380001a1)
+	continue;
+
+      /* Check for "sc".  */
+      insn = extract_unsigned_integer (buf + PPC_INSN_SIZE,
+				       PPC_INSN_SIZE, byte_order);
+      if (insn != 0x44000002)
+	continue;
+
+      return 1;
+    }
+
+  return 0;
+}
+
+static struct trad_frame_cache *
+ppcfbsd_sigtramp_frame_cache (struct frame_info *this_frame, void **this_cache)
+{
+  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 trad_frame_cache *cache;
+  CORE_ADDR addr, base, func;
+  gdb_byte buf[PPC_INSN_SIZE];
+  int i;
+
+  if (*this_cache)
+    return *this_cache;
+
+  cache = trad_frame_cache_zalloc (this_frame);
+  *this_cache = cache;
+
+  func = get_frame_pc (this_frame);
+  func &= ~(ppcfbsd_page_size - 1);
+  if (!safe_frame_unwind_memory (this_frame, func, buf, sizeof buf))
+    return cache;
+
+  base = get_frame_register_unsigned (this_frame, gdbarch_sp_regnum (gdbarch));
+  addr = base + 0x10 + 2 * tdep->wordsize;
+  for (i = 0; i < ppc_num_gprs; i++, addr += tdep->wordsize)
+    {
+      int regnum = i + tdep->ppc_gp0_regnum;
+      trad_frame_set_reg_addr (cache, regnum, addr);
+    }
+  trad_frame_set_reg_addr (cache, tdep->ppc_lr_regnum, addr);
+  addr += tdep->wordsize;
+  trad_frame_set_reg_addr (cache, tdep->ppc_cr_regnum, addr);
+  addr += tdep->wordsize;
+  trad_frame_set_reg_addr (cache, tdep->ppc_xer_regnum, addr);
+  addr += tdep->wordsize;
+  trad_frame_set_reg_addr (cache, tdep->ppc_ctr_regnum, addr);
+  addr += tdep->wordsize;
+  trad_frame_set_reg_addr (cache, gdbarch_pc_regnum (gdbarch), addr);
+  /* SRR0?  */
+  addr += tdep->wordsize;
+
+  /* Construct the frame ID using the function start.  */
+  trad_frame_set_id (cache, frame_id_build (base, func));
+
+  return cache;
+}
+
+static void
+ppcfbsd_sigtramp_frame_this_id (struct frame_info *this_frame,
+				void **this_cache, struct frame_id *this_id)
+{
+  struct trad_frame_cache *cache =
+    ppcfbsd_sigtramp_frame_cache (this_frame, this_cache);
+
+  trad_frame_get_id (cache, this_id);
+}
+
+static struct value *
+ppcfbsd_sigtramp_frame_prev_register (struct frame_info *this_frame,
+				      void **this_cache, int regnum)
+{
+  struct trad_frame_cache *cache =
+    ppcfbsd_sigtramp_frame_cache (this_frame, this_cache);
+
+  return trad_frame_get_register (cache, this_frame, regnum);
+}
+
+static const struct frame_unwind ppcfbsd_sigtramp_frame_unwind = {
+  SIGTRAMP_FRAME,
+  default_frame_unwind_stop_reason,
+  ppcfbsd_sigtramp_frame_this_id,
+  ppcfbsd_sigtramp_frame_prev_register,
+  NULL,
+  ppcfbsd_sigtramp_frame_sniffer
+};
+
+static enum return_value_convention
+ppcfbsd_return_value (struct gdbarch *gdbarch, struct value *function,
+		      struct type *valtype, struct regcache *regcache,
+		      gdb_byte *readbuf, const gdb_byte *writebuf)
+{
+  return ppc_sysv_abi_broken_return_value (gdbarch, function, valtype,
+					   regcache, readbuf, writebuf);
+}
+
+/* Return real function address.  */
+
+static CORE_ADDR
+ppc64_fbsd_convert_from_func_ptr_addr (struct gdbarch *gdbarch,
+				       CORE_ADDR addr,
+				       struct target_ops *targ)
+{
+  struct gdbarch_tdep *tdep;
+  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
+  struct target_section *s = target_section_by_addr (targ, addr);
+  tdep = gdbarch_tdep (gdbarch);
+
+  /* Check if ADDR points to a function descriptor.  */
+  if (s && strcmp (s->the_bfd_section->name, ".opd") == 0)
+    {
+      /* There may be relocations that need to be applied to the .opd
+	 section.  Unfortunately, this function may be called at a time
+	 where these relocations have not yet been performed -- this can
+	 happen for example shortly after a library has been loaded with
+	 dlopen, but ld.so has not yet applied the relocations.
+
+	 To cope with both the case where the relocation has been applied,
+	 and the case where it has not yet been applied, we do *not* read
+	 the (maybe) relocated value from target memory, but we instead
+	 read the non-relocated value from the BFD, and apply the relocation
+	 offset manually.
+
+	 This makes the assumption that all .opd entries are always relocated
+	 by the same offset the section itself was relocated.  This should
+	 always be the case for GNU/Linux executables and shared libraries.
+	 Note that other kind of object files (e.g. those added via
+	 add-symbol-files) will currently never end up here anyway, as this
+	 function accesses *target* sections only; only the main exec and
+	 shared libraries are ever added to the target.  */
+
+      gdb_byte buf[8];
+      int res;
+
+      res = bfd_get_section_contents (s->bfd, s->the_bfd_section,
+				      &buf, addr - s->addr, 8);
+      if (res != 0)
+	return extract_unsigned_integer (buf, 8, byte_order)
+	  - bfd_section_vma (s->bfd, s->the_bfd_section) + s->addr;
+    }
+
+  return addr;
+}
+
+static void
+ppcfbsd_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* FreeBSD doesn't support the 128-bit `long double' from the psABI.  */
+  set_gdbarch_long_double_bit (gdbarch, 64);
+  set_gdbarch_long_double_format (gdbarch, floatformats_ieee_double);
+
+  if (tdep->wordsize == 4)
+    {
+      set_gdbarch_return_value (gdbarch, ppcfbsd_return_value);
+
+      set_gdbarch_skip_trampoline_code (gdbarch, find_solib_trampoline_target);
+      set_solib_svr4_fetch_link_map_offsets (gdbarch,
+					     svr4_ilp32_fetch_link_map_offsets);
+
+      frame_unwind_append_unwinder (gdbarch, &ppcfbsd_sigtramp_frame_unwind);
+      set_gdbarch_gcore_bfd_target (gdbarch, "elf32-powerpc");
+    }
+
+  if (tdep->wordsize == 8)
+    {
+      set_gdbarch_convert_from_func_ptr_addr
+	(gdbarch, ppc64_fbsd_convert_from_func_ptr_addr);
+      set_gdbarch_skip_trampoline_code (gdbarch, ppc64_skip_trampoline_code);
+      set_solib_svr4_fetch_link_map_offsets (gdbarch,
+					     svr4_lp64_fetch_link_map_offsets);
+      set_gdbarch_gcore_bfd_target (gdbarch, "elf64-powerpc");
+    }
+
+  set_gdbarch_regset_from_core_section
+    (gdbarch, ppcfbsd_regset_from_core_section);
+
+  set_gdbarch_fetch_tls_load_module_address (gdbarch,
+					     svr4_fetch_objfile_link_map);
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+
+void _initialize_ppcfbsd_tdep (void);
+
+void
+_initialize_ppcfbsd_tdep (void)
+{
+  gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc, GDB_OSABI_FREEBSD_ELF,
+			  ppcfbsd_init_abi);
+  gdbarch_register_osabi (bfd_arch_powerpc, bfd_mach_ppc64,
+			  GDB_OSABI_FREEBSD_ELF,
+			  ppcfbsd_init_abi);
+  gdbarch_register_osabi (bfd_arch_rs6000, 0, GDB_OSABI_FREEBSD_ELF,
+			  ppcfbsd_init_abi);
+  /* Initialize the FreeBSD target descriptions.  */
+  initialize_tdesc_powerpc_32l ();
+  initialize_tdesc_powerpc_64l ();
+}
Index: ./ppcfbsd-nat.c
--- /dev/null
+++ ./ppcfbsd-nat.c
@@ -0,0 +1,225 @@
+/* Native-dependent code for PowerPC's running FreeBSD, for GDB.
+
+   Copyright (C) 2012
+   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 <http://www.gnu.org/licenses/>.  */
+
+#include "defs.h"
+#include "gdbcore.h"
+#include "inferior.h"
+#include "regcache.h"
+
+#include "gdb_assert.h"
+#include <stddef.h>
+#include <sys/types.h>
+#include <sys/procfs.h>
+#include <sys/ptrace.h>
+#include <sys/signal.h>
+#include <machine/frame.h>
+#include <machine/pcb.h>
+#include <machine/reg.h>
+
+#include "fbsd-nat.h"
+#include "gregset.h"
+#include "ppc-tdep.h"
+#include "ppcfbsd-tdep.h"
+#include "inf-ptrace.h"
+#include "bsd-kvm.h"
+
+/* Fill GDB's register array with the general-purpose register values
+   in *GREGSETP.  */
+
+void
+supply_gregset (struct regcache *regcache, const gdb_gregset_t *gregsetp)
+{
+  const struct regset *regset = ppc_fbsd_gregset (sizeof (long));
+
+  ppc_supply_gregset (regset, regcache, -1, gregsetp, sizeof (*gregsetp));
+}
+
+/* Fill register REGNO (if a gpr) in *GREGSETP with the value in GDB's
+   register array. If REGNO is -1 do it for all registers.  */
+
+void
+fill_gregset (const struct regcache *regcache,
+	      gdb_gregset_t *gregsetp, int regno)
+{
+  const struct regset *regset = ppc_fbsd_gregset (sizeof (long));
+
+  if (regno == -1)
+    memset (gregsetp, 0, sizeof (*gregsetp));
+  ppc_collect_gregset (regset, regcache, regno, gregsetp, sizeof (*gregsetp));
+}
+
+/* Fill GDB's register array with the floating-point register values
+   in *FPREGSETP.  */
+
+void
+supply_fpregset (struct regcache *regcache, const gdb_fpregset_t * fpregsetp)
+{
+  const struct regset *regset = ppc_fbsd_fpregset ();
+
+  ppc_supply_fpregset (regset, regcache, -1,
+		       fpregsetp, sizeof (*fpregsetp));
+}
+
+/* Fill register REGNO in *FGREGSETP with the value in GDB's
+   register array. If REGNO is -1 do it for all registers.  */
+
+void
+fill_fpregset (const struct regcache *regcache,
+	       gdb_fpregset_t *fpregsetp, int regno)
+{
+  const struct regset *regset = ppc_fbsd_fpregset ();
+
+  ppc_collect_fpregset (regset, regcache, regno,
+			fpregsetp, sizeof (*fpregsetp));
+}
+
+/* Returns true if PT_GETFPREGS fetches this register.  */
+
+static int
+getfpregs_supplies (struct gdbarch *gdbarch, int regno)
+{
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+
+  /* FIXME: jimb/2004-05-05: Some PPC variants don't have floating
+	 point registers.  Traditionally, GDB's register set has still
+	 listed the floating point registers for such machines, so this
+	 code is harmless.  However, the new E500 port actually omits the
+	 floating point registers entirely from the register set --- they
+	 don't even have register numbers assigned to them.
+
+	 It's not clear to me how best to update this code, so this assert
+	 will alert the first person to encounter the NetBSD/E500
+	 combination to the problem.  */
+
+  gdb_assert (ppc_floating_point_unit_p (gdbarch));
+
+  return ((regno >= tdep->ppc_fp0_regnum
+	   && regno < tdep->ppc_fp0_regnum + ppc_num_fprs)
+	  || regno == tdep->ppc_fpscr_regnum);
+}
+
+/* Fetch register REGNO from the child process. If REGNO is -1, do it
+   for all registers.  */
+
+static void
+ppcfbsd_fetch_inferior_registers (struct target_ops *ops,
+				  struct regcache *regcache, int regno)
+{
+  gdb_gregset_t regs;
+
+  if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
+    perror_with_name (_("Couldn't get registers"));
+
+  supply_gregset (regcache, &regs);
+
+  if (regno == -1 || getfpregs_supplies (get_regcache_arch (regcache), regno))
+    {
+      const struct regset *fpregset = ppc_fbsd_fpregset ();
+      gdb_fpregset_t fpregs;
+
+      if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+	perror_with_name (_("Couldn't get FP registers"));
+
+      ppc_supply_fpregset (fpregset, regcache, regno, &fpregs, sizeof fpregs);
+    }
+}
+
+/* Store register REGNO back into the child process. If REGNO is -1,
+   do this for all registers.  */
+
+static void
+ppcfbsd_store_inferior_registers (struct target_ops *ops,
+				  struct regcache *regcache, int regno)
+{
+  gdb_gregset_t regs;
+
+  if (ptrace (PT_GETREGS, PIDGET (inferior_ptid),
+	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
+    perror_with_name (_("Couldn't get registers"));
+
+  fill_gregset (regcache, &regs, regno);
+
+  if (ptrace (PT_SETREGS, PIDGET (inferior_ptid),
+	      (PTRACE_TYPE_ARG3) &regs, 0) == -1)
+    perror_with_name (_("Couldn't write registers"));
+
+  if (regno == -1 || getfpregs_supplies (get_regcache_arch (regcache), regno))
+    {
+      gdb_fpregset_t fpregs;
+
+      if (ptrace (PT_GETFPREGS, PIDGET (inferior_ptid),
+		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+	perror_with_name (_("Couldn't get FP registers"));
+
+      fill_fpregset (regcache, &fpregs, regno);
+
+      if (ptrace (PT_SETFPREGS, PIDGET (inferior_ptid),
+		  (PTRACE_TYPE_ARG3) &fpregs, 0) == -1)
+	perror_with_name (_("Couldn't set FP registers"));
+    }
+}
+
+/* Architecture specific function that reconstructs the
+   register state from PCB (Process Control Block) and supplies it
+   to REGCACHE.  */
+
+static int
+ppcfbsd_supply_pcb (struct regcache *regcache, struct pcb *pcb)
+{
+  struct gdbarch *gdbarch = get_regcache_arch (regcache);
+  struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
+  int i, regnum;
+
+  /* The stack pointer shouldn't be zero.  */
+  if (pcb->pcb_sp == 0)
+    return 0;
+
+  regcache_raw_supply (regcache, gdbarch_sp_regnum (gdbarch), &pcb->pcb_sp);
+  regcache_raw_supply (regcache, tdep->ppc_cr_regnum, &pcb->pcb_cr);
+  regcache_raw_supply (regcache, tdep->ppc_lr_regnum, &pcb->pcb_lr);
+  for (i = 0, regnum = tdep->ppc_gp0_regnum + 14; i < 20; i++, regnum++)
+    regcache_raw_supply (regcache, regnum, &pcb->pcb_context[i]);
+
+  return 1;
+}
+
+/* Provide a prototype to silence -Wmissing-prototypes.  */
+
+void _initialize_ppcfbsd_nat (void);
+
+void
+_initialize_ppcfbsd_nat (void)
+{
+  struct target_ops *t;
+
+  /* Add in local overrides.  */
+  t = inf_ptrace_target ();
+  t->to_fetch_registers = ppcfbsd_fetch_inferior_registers;
+  t->to_store_registers = ppcfbsd_store_inferior_registers;
+  t->to_pid_to_exec_file = fbsd_pid_to_exec_file;
+  t->to_find_memory_regions = fbsd_find_memory_regions;
+  t->to_make_corefile_notes = fbsd_make_corefile_notes;
+  add_target (t);
+
+  /* Support debugging kernel virtual memory images.  */
+  bsd_kvm_add_target (ppcfbsd_supply_pcb);
+}
Index: config/powerpc/fbsd.mh
--- /dev/null
+++ config/powerpc/fbsd.mh
@@ -0,0 +1,5 @@
+# Host: FreeBSD/powerpc
+NATDEPFILES= fbsd-nat.o fork-child.o inf-ptrace.o ppcfbsd-nat.o bsd-kvm.o
+
+LOADLIBES= -lkvm
+

^ permalink raw reply	[flat|nested] 12+ messages in thread

* PING Re: [PATCH] FreeBSD powerpc support
  2012-11-27 17:45   ` Andreas Tobler
@ 2012-12-11 15:48     ` Andreas Tobler
  2012-12-11 16:14       ` Pedro Alves
  2012-12-11 20:07     ` Pedro Alves
  1 sibling, 1 reply; 12+ messages in thread
From: Andreas Tobler @ 2012-12-11 15:48 UTC (permalink / raw)
  To: Pedro Alves, gdb-patches

On 27.11.12 18:45, Andreas Tobler wrote:
> Hello again,
> 
> took a bit longer.
> 
> On 23.11.12 20:33, Pedro Alves wrote:
> 
>>> The attached patch adds support for FreeBSD PowerPC, 32-bit and 64-bit.
>>> It is derived from ppcobsd* and ppc-linux with FreeBSD additions.
>>>
>>> There is room for improvement :) And I will continue, but I'd like to
>>> see this patch in the gdb cvs because it will be much easier for me fix
>>> outstanding issues when I can work with cvs iso. of local revisions.
>>
>> Eh.  If it's easier, then maybe you're not using the proper tools; there's
>> always quilt.  :-)  Or better nowadays, you could also put it
>> in a public git repo somewhere.  We have a git mirror of cvs.
>> That said, I'm really not against putting it in early, if it's not riddled
>> with hacks.
> 
> Might be that I do not use the latest and greatest tools.
> The room for improvement, above, is in the direction of general FreeBSD
> stuff, not only limited to this particular port.
> 
>>> Also, other people might have a use of this work, even if not complete.
>>>
>>> Currently missing/incomplete:
>>> - Altivec support, kernel bits are missing.
>>> - HW watchpoints, also kernel bits are missing.
>>> - thread support.
>>> - tls support.
>>> - some sig tests.
>>
>> I've skimmed the patch, and didn't notice anything horrible.
>> Then again, I'm on the low end of the scale that measures
>> PowerPC or FreeBSD expertness...
>>
>> - Please make sure there's a blank line between introductory comment
>>   and function.
> 
> I hope I didn't miss them.
> 
>> - I noticed that a few functions don't have introductory comment.
> 
> Also, I put one in where I could.
> 
>> - If the function implements of a target/gdbarch/etc. method, then
>>   comment it as such.  E.g.,
>>
>>   /* This is the implementation of gdbarch method FOOBAR.  */
>>
>> - I noticed some functions with long comments are copies of existing
>>   code of other ports.  I wonder if we could perhaps share more code.
> 
> True, here I do not know how to share, maybe a common ppc64-tdep-common.c?
> 
>>> +/* Read a PPC instruction from memory.  PPC instructions are always
>>> + *  big-endian, no matter what endianness the program is running in, so
>>> + *  we can't use read_memory_integer or one of its friends here.
>>
>> read_memory_unsigned_integer nowadays has a byte_order parameter,
>> so just pass it BFD_ENDIAN_BIG, and you're set.
> 
> Done. Even tested on ppc64-linux. I might send a patch for
> ppc-linux-tdep.c as well. Likewise for the below.
> 
>>> +#define PPC64_STANDARD_LINKAGE2_LEN \
>>> +  (sizeof (ppc64_standard_linkage2) / sizeof (ppc64_standard_linkage2[0]))
>>> +
>>
>> Use the existing ARRAY_SIZE macro.
> 
> Done.
> 
>> +/* Signal trampolines.  */
>>> +
>>> +static int
>>> +ppcfbsd_sigtramp_frame_sniffer (const struct frame_unwind *self,
>>> +				struct frame_info *this_frame,
>>> +				void **this_cache)
>>> +{
>>> +  struct gdbarch *gdbarch = get_frame_arch (this_frame);
>>> +  enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
>>> +  CORE_ADDR pc = get_frame_pc (this_frame);
>>> +  CORE_ADDR start_pc = (pc & ~(ppcfbsd_page_size - 1));
>>> +  const int *offset;
>>> +  const char *name;
>>> +
>>> +  find_pc_partial_function (pc, &name, NULL, NULL);
>>> +  if (name)
>>> +    return 0;
>>
>> For some reason this bailing out if name is not null jumped at me.
>> It's not obvious to me what that means, so it felt like it deserves
>> a comment.
> 
> Also done, I hope I match the expectations.
> 
>> On 11/19/2012 09:43 PM, Andreas Tobler wrote:
>>> --- configure.host	30 May 2012 19:41:34 -0000	1.107
>>> +++ configure.host	19 Nov 2012 21:24:15 -0000
>>> @@ -125,6 +125,7 @@
>>>
>>>  powerpc-*-aix* | rs6000-*-*)
>>>  			gdb_host=aix ;;
>>> +powerpc*-*-freebsd*)	gdb_host=fbsd ;;
>>
>> This seems to be 'powerpc-*-freebsd*' elsewhere I looked (top level, bfd).
>> Why the extra wildcard?
> 
> 
> Hm, here I'm not sure. My targets report as powerpc-unknown-freebsd*
> (32-bit) and powerpc64-unknown-freebsd* (64-bit). So I thought I have to
> match both. Is this not correct?
> 
> Attached a revised version of the diff.
> 
> Pedro, again thank you very much for the feedback.

ping, anything I miss? Or is it the usual pre x-mas business ;)

TIA,
Andreas


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: PING Re: [PATCH] FreeBSD powerpc support
  2012-12-11 15:48     ` PING " Andreas Tobler
@ 2012-12-11 16:14       ` Pedro Alves
  2012-12-11 16:33         ` Andreas Tobler
  0 siblings, 1 reply; 12+ messages in thread
From: Pedro Alves @ 2012-12-11 16:14 UTC (permalink / raw)
  To: Andreas Tobler; +Cc: gdb-patches

On 12/11/2012 03:48 PM, Andreas Tobler wrote:

> ping, anything I miss? Or is it the usual pre x-mas business ;)

Yeah, sorry.  I was away a big chunk of last week, and I still
have a truck of backlog of patches to review...  (and I'll be
supposedly on vacation for two weeks starting next week...)

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: PING Re: [PATCH] FreeBSD powerpc support
  2012-12-11 16:14       ` Pedro Alves
@ 2012-12-11 16:33         ` Andreas Tobler
  0 siblings, 0 replies; 12+ messages in thread
From: Andreas Tobler @ 2012-12-11 16:33 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On 11.12.12 17:14, Pedro Alves wrote:
> On 12/11/2012 03:48 PM, Andreas Tobler wrote:
> 
>> ping, anything I miss? Or is it the usual pre x-mas business ;)
> 
> Yeah, sorry.  I was away a big chunk of last week, and I still
> have a truck of backlog of patches to review...  (and I'll be
> supposedly on vacation for two weeks starting next week...)
> 

No problem then. Just wanted to make sure that it is in the queue.

Thanks,

Andreas


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FreeBSD powerpc support
  2012-11-27 17:45   ` Andreas Tobler
  2012-12-11 15:48     ` PING " Andreas Tobler
@ 2012-12-11 20:07     ` Pedro Alves
  2012-12-12 20:07       ` Andreas Tobler
  1 sibling, 1 reply; 12+ messages in thread
From: Pedro Alves @ 2012-12-11 20:07 UTC (permalink / raw)
  To: Andreas Tobler; +Cc: gdb-patches

On 11/27/2012 05:45 PM, Andreas Tobler wrote:

>> - If the function implements of a target/gdbarch/etc. method, then
>>   comment it as such.  E.g.,
>>
>>   /* This is the implementation of gdbarch method FOOBAR.  */
>>
>> - I noticed some functions with long comments are copies of existing
>>   code of other ports.  I wonder if we could perhaps share more code.
> 
> True, here I do not know how to share, maybe a common ppc64-tdep-common.c?

The tdep files are usually called ARCH-OS-tdep.c, so that would be
ppc64-common-tdep.c.  That raises the question of what's  different between
ppc64-common-tdep.c and ppc64-tdep.c.  Clearer alternatives could be
ppc64-unix-tdep.c or some other token that describes the commonality between
what's being shared (as opposed to just the fact that something is shared,
as in "common").  In any case, the name of the file is the minor detail.


>> read_memory_unsigned_integer nowadays has a byte_order parameter,
>> so just pass it BFD_ENDIAN_BIG, and you're set.
> 
> Done. Even tested on ppc64-linux. I might send a patch for
> ppc-linux-tdep.c as well. Likewise for the below.

That'd be nice.

>> For some reason this bailing out if name is not null jumped at me.
>> It's not obvious to me what that means, so it felt like it deserves
>> a comment.
> 
> Also done, I hope I match the expectations.

You have, thanks.

> 
>> On 11/19/2012 09:43 PM, Andreas Tobler wrote:
>>> --- configure.host	30 May 2012 19:41:34 -0000	1.107
>>> +++ configure.host	19 Nov 2012 21:24:15 -0000
>>> @@ -125,6 +125,7 @@
>>>
>>>  powerpc-*-aix* | rs6000-*-*)
>>>  			gdb_host=aix ;;
>>> +powerpc*-*-freebsd*)	gdb_host=fbsd ;;
>>
>> This seems to be 'powerpc-*-freebsd*' elsewhere I looked (top level, bfd).
>> Why the extra wildcard?
> 
> 
> Hm, here I'm not sure. My targets report as powerpc-unknown-freebsd*
> (32-bit) and powerpc64-unknown-freebsd* (64-bit). So I thought I have to
> match both. Is this not correct?

I guess that's fine then.

> Attached a revised version of the diff.

Thanks.  Please always paste the ChangeLog entry along with the patch
too, even if it hadn't needed changes.


> +#include "features/rs6000/powerpc-32l.c"
> +#include "features/rs6000/powerpc-64l.c"

This is a problem.  I notice you have tdesc related things in your patch,
but nothing is actually making use of the target descriptions -- neither
the core support, nor the native debugger support code is implementing
the "return target's target description" hooks.  Furthermore, you're
using the target descriptions and calling the same initialization
functions that ppc-linux-tdep.c calls.  Please try an --enable-targets=all
build -- I'm guessing you'll see multiple-definition link errors.

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FreeBSD powerpc support
  2012-12-11 20:07     ` Pedro Alves
@ 2012-12-12 20:07       ` Andreas Tobler
  2012-12-13 20:04         ` Pedro Alves
  0 siblings, 1 reply; 12+ messages in thread
From: Andreas Tobler @ 2012-12-12 20:07 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On 11.12.12 21:07, Pedro Alves wrote:
> On 11/27/2012 05:45 PM, Andreas Tobler wrote:
> 
>>> - If the function implements of a target/gdbarch/etc. method, then
>>>   comment it as such.  E.g.,
>>>
>>>   /* This is the implementation of gdbarch method FOOBAR.  */
>>>
>>> - I noticed some functions with long comments are copies of existing
>>>   code of other ports.  I wonder if we could perhaps share more code.
>>
>> True, here I do not know how to share, maybe a common ppc64-tdep-common.c?
> 
> The tdep files are usually called ARCH-OS-tdep.c, so that would be
> ppc64-common-tdep.c.  That raises the question of what's  different between
> ppc64-common-tdep.c and ppc64-tdep.c.  Clearer alternatives could be
> ppc64-unix-tdep.c or some other token that describes the commonality between
> what's being shared (as opposed to just the fact that something is shared,
> as in "common").  In any case, the name of the file is the minor detail.


Ok. I'll try to prepare something. Hopefully I'll find some time over
the next weeks :)

>>> read_memory_unsigned_integer nowadays has a byte_order parameter,
>>> so just pass it BFD_ENDIAN_BIG, and you're set.
>>
>> Done. Even tested on ppc64-linux. I might send a patch for
>> ppc-linux-tdep.c as well. Likewise for the below.
> 
> That'd be nice.

Ok, will do so.

>>> For some reason this bailing out if name is not null jumped at me.
>>> It's not obvious to me what that means, so it felt like it deserves
>>> a comment.
>>
>> Also done, I hope I match the expectations.
> 
> You have, thanks.
> 
>>
>>> On 11/19/2012 09:43 PM, Andreas Tobler wrote:
>>>> --- configure.host	30 May 2012 19:41:34 -0000	1.107
>>>> +++ configure.host	19 Nov 2012 21:24:15 -0000
>>>> @@ -125,6 +125,7 @@
>>>>
>>>>  powerpc-*-aix* | rs6000-*-*)
>>>>  			gdb_host=aix ;;
>>>> +powerpc*-*-freebsd*)	gdb_host=fbsd ;;
>>>
>>> This seems to be 'powerpc-*-freebsd*' elsewhere I looked (top level, bfd).
>>> Why the extra wildcard?
>>
>>
>> Hm, here I'm not sure. My targets report as powerpc-unknown-freebsd*
>> (32-bit) and powerpc64-unknown-freebsd* (64-bit). So I thought I have to
>> match both. Is this not correct?
> 
> I guess that's fine then.
> 
>> Attached a revised version of the diff.
> 
> Thanks.  Please always paste the ChangeLog entry along with the patch
> too, even if it hadn't needed changes.

Will do so next time.

>> +#include "features/rs6000/powerpc-32l.c"
>> +#include "features/rs6000/powerpc-64l.c"
> 
> This is a problem.  I notice you have tdesc related things in your patch,
> but nothing is actually making use of the target descriptions -- neither
> the core support, nor the native debugger support code is implementing
> the "return target's target description" hooks.  Furthermore, you're
> using the target descriptions and calling the same initialization
> functions that ppc-linux-tdep.c calls.  Please try an --enable-targets=all
> build -- I'm guessing you'll see multiple-definition link errors.

Ok, I didn't try the enable-targets=all yet.

I must have gotten something wrong here. Back when I started this patch
I thought this was needed to pass the 'xml' tests. But now I see that I
pass these test w/o this tdesc stuff.

I removed it now.

Pedro, thanks for the feedback.

If you're ok I try to update the patch with a new file which contains
the 'common' code for ppc64.

Andreas



^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FreeBSD powerpc support
  2012-12-12 20:07       ` Andreas Tobler
@ 2012-12-13 20:04         ` Pedro Alves
  2012-12-13 20:20           ` Andreas Tobler
  0 siblings, 1 reply; 12+ messages in thread
From: Pedro Alves @ 2012-12-13 20:04 UTC (permalink / raw)
  To: Andreas Tobler; +Cc: gdb-patches

On 12/12/2012 08:07 PM, Andreas Tobler wrote:
> If you're ok I try to update the patch with a new file which contains
> the 'common' code for ppc64.

FAOD, I'm fine with that.

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FreeBSD powerpc support
  2012-12-13 20:04         ` Pedro Alves
@ 2012-12-13 20:20           ` Andreas Tobler
  2012-12-13 20:27             ` Pedro Alves
  0 siblings, 1 reply; 12+ messages in thread
From: Andreas Tobler @ 2012-12-13 20:20 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On 13.12.12 21:03, Pedro Alves wrote:
> On 12/12/2012 08:07 PM, Andreas Tobler wrote:
>> If you're ok I try to update the patch with a new file which contains
>> the 'common' code for ppc64.
> 
> FAOD, I'm fine with that.

Ok. Thinking a bit more about makes me feel that a separate patch would
be more clean. Iow, a patch which extracts the 'common' functions from
ppc-linux-tdep.c into ppc64-common-tdep.c.

Once this is tested (ppc64-linux) and in, I can bring the FreeBSD
support on top of it.

Mixing these two issues together might cause troubles....

Do you agree?

Andreas


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FreeBSD powerpc support
  2012-12-13 20:20           ` Andreas Tobler
@ 2012-12-13 20:27             ` Pedro Alves
  2012-12-13 20:35               ` Andreas Tobler
  0 siblings, 1 reply; 12+ messages in thread
From: Pedro Alves @ 2012-12-13 20:27 UTC (permalink / raw)
  To: Andreas Tobler; +Cc: gdb-patches

On 12/13/2012 08:20 PM, Andreas Tobler wrote:
> On 13.12.12 21:03, Pedro Alves wrote:
>> On 12/12/2012 08:07 PM, Andreas Tobler wrote:
>>> If you're ok I try to update the patch with a new file which contains
>>> the 'common' code for ppc64.
>>
>> FAOD, I'm fine with that.
> 
> Ok. Thinking a bit more about makes me feel that a separate patch would
> be more clean. Iow, a patch which extracts the 'common' functions from
> ppc-linux-tdep.c into ppc64-common-tdep.c.
> 
> Once this is tested (ppc64-linux) and in, I can bring the FreeBSD
> support on top of it.
> 
> Mixing these two issues together might cause troubles....
> 
> Do you agree?

That's fine, but it'd make sense to see both patches together, so we
don't have to imagine the uses outside GNU/Linux.  This is where quilt
or git would pay off a lot for you.
The reverse would be fine with me too.  Extract the commonality after
the FreeBSD patch is in.

-- 
Pedro Alves


^ permalink raw reply	[flat|nested] 12+ messages in thread

* Re: [PATCH] FreeBSD powerpc support
  2012-12-13 20:27             ` Pedro Alves
@ 2012-12-13 20:35               ` Andreas Tobler
  0 siblings, 0 replies; 12+ messages in thread
From: Andreas Tobler @ 2012-12-13 20:35 UTC (permalink / raw)
  To: Pedro Alves; +Cc: gdb-patches

On 13.12.12 21:26, Pedro Alves wrote:
> On 12/13/2012 08:20 PM, Andreas Tobler wrote:
>> On 13.12.12 21:03, Pedro Alves wrote:
>>> On 12/12/2012 08:07 PM, Andreas Tobler wrote:
>>>> If you're ok I try to update the patch with a new file which contains
>>>> the 'common' code for ppc64.
>>>
>>> FAOD, I'm fine with that.
>>
>> Ok. Thinking a bit more about makes me feel that a separate patch would
>> be more clean. Iow, a patch which extracts the 'common' functions from
>> ppc-linux-tdep.c into ppc64-common-tdep.c.
>>
>> Once this is tested (ppc64-linux) and in, I can bring the FreeBSD
>> support on top of it.
>>
>> Mixing these two issues together might cause troubles....
>>
>> Do you agree?
> 
> That's fine, but it'd make sense to see both patches together, so we
> don't have to imagine the uses outside GNU/Linux.  This is where quilt
> or git would pay off a lot for you.

Ok, time to learn something new :)

> The reverse would be fine with me too.  Extract the commonality after
> the FreeBSD patch is in.

That would mean that the FreeBSD patch would need approval first ;)

Anyway, I see what is going best.

Thanks,
Andreas


^ permalink raw reply	[flat|nested] 12+ messages in thread

end of thread, other threads:[~2012-12-13 20:35 UTC | newest]

Thread overview: 12+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2012-11-19 21:44 [PATCH] FreeBSD powerpc support Andreas Tobler
2012-11-23 19:34 ` Pedro Alves
2012-11-27 17:45   ` Andreas Tobler
2012-12-11 15:48     ` PING " Andreas Tobler
2012-12-11 16:14       ` Pedro Alves
2012-12-11 16:33         ` Andreas Tobler
2012-12-11 20:07     ` Pedro Alves
2012-12-12 20:07       ` Andreas Tobler
2012-12-13 20:04         ` Pedro Alves
2012-12-13 20:20           ` Andreas Tobler
2012-12-13 20:27             ` Pedro Alves
2012-12-13 20:35               ` Andreas Tobler

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox