This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

[PATCH 4/5 v5] Tracepoint for ppc64


Hi Ulrich,

All the bugs are fixed, except the ppc_fast_tracepoint_valid_at issue.
I need some time to think about the issue.

Here is the revised patch for your review :)

On Sat, Jul 4, 2015 at 12:36 AM, Ulrich Weigand <uweigand@de.ibm.com> wrote:
> Wei-cheng Wang wrote:
> > Ulrich Weigand wrote:
> > Changing timeout in tspeed.exp is reverted in this patch.  Recently I
> > tested the patch on gcc112 server and timeout should be 540 instead of 360
> > in order to pass tspeed.exp.  I am not sure what's the proper value for timeout.
> > Maybe someone will test it in another environment, and 540 is not enough again.
> 
> OK.  Do we know why the test case is taking so long?  Is this simply to be
> expected, or is the slowness due to some hidden issue that should be fixed?

I don't think there is any issue (in GDB) causing the slowness.
The overhead for slow tracepoint is significantly lower on PPC than on X86 system.
For example, the time for 1,600,000 iterations

on gcc10 (x86_64):
  real:  45,120,000
  user:     180,011
  sys :   4,116,257

on gcc112 (ppc64):
  real: 149,400,000
  user:      91,719
  sys :   2,344,530

The test case tries to find an iteration count that takes user+sys time
between 2 and 5 seconds.   If user/sys time overhead is lower, it takes
longer real-time to finish.
 
> However, in this specific case, since the lock value is itself a
> pointer to a data structure, you *do* want to have a lwsync between
> storing that data structure and taking the lock.
> 
> It's probably best to move the lwsync out of this subroutine and
> place the two lwsyncs in the caller.

Change gen_atomic_xchg to (remove lwsync)

  1: lwarx   TMP, 0, LOCK
     cmpwi   TMP, OLD
     bne     1b
     stwcx.  NEW, 0, LOCK
     bne     1b */

And at the call site

  p += GEN_LWSYNC (p);
  p += gen_atomic_xchg (p, lockaddr, 0, 5);
  p += GEN_LWSYNC (p);

> Also, a couple of comments from an earlier review still apply:
> > +#if __PPC64__
> Please use #ifdef __powerpc64__ throughout.

Ok, fix now.

$ git grep __PPC | wc -l
0

__PPC64__ in linux-ppc-ipa.c are also fixed.

> This is still incorrect if bit 31 of imm is set.
> (The lis will fill the 32 high bits of the register
> with 1 instead 0 in that case.)

  p += GEN_LIS (p, reg, (imm >> 16) & 0xffff);
  p += GEN_ORI (p, reg, reg, imm & 0xffff);
  /* Clear upper 32-bit if sign-bit is set.  */
  if (imm & (1 << 31))
    p += GEN_RLDICL (p, reg, reg, 0, 32);

> This should check for (PPC_BO (insn) & 0x14) == 0.
> Note that (PPC_BO (insn) & 0x14) == 0x14 is the "branch always"
> case, which should be replaced simply by an unconditional branch.

Fixed as such

  else if ((PPC_BO (insn) & 0x14) == 0)
    { .... }
  else /* (BO & 0x14) == 0x14, branch always.  */
    {
      /* Out of range. Cannot relocate instruction.  */
      if (newrel >= (1 << 25) || newrel < -(1 << 25))
        return;
      
      /* Build a unconditional branch and copy LK bit.  */
      insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3);
      write_inferior_memory (*to, (unsigned char *) &insn, 4);
      *to += 4;
      
      return;
    }

> > +     {
> > +       uint32_t bdnz_insn = (16 << 26) | (0x10 << 21) | 12;
> > +       uint32_t bf_insn = (16 << 26) | (0x4 << 21) | 8;
> > +
> > +       newrel -= 12;
> 
> That should be -= 8, shouldn't it?

  Yes, fixed.

> > +static void
> > +ppc64_emit_stack_adjust (int n)
> > +{
> > +  uint32_t buf[4];
> > +  uint32_t *p = buf;
> > +
> > +  n = n << 3;
> > +  if ((n >> 7) != 0)
> > +    {
> > +      emit_error = 1;
> > +      return;
> > +    }
> > +
> > +  p += GEN_ADDI (p, 30, 30, n);
> 
> ADDI supports up to 15-bit unsigned operands,
> so this seems overly strict.

  if ((n >> 15) != 0)

Wei-cheng

---

gdb/ChangeLog

2015-07-13  Wei-cheng Wang  <cole945@gmail.com>

	* rs6000-tdep.c (ppc_fast_tracepoint_valid_at,
	ppc_gen_return_address): New functions.
	(rs6000_gdbarch_init): Hook ppc_fast_tracepoint_valid_at,
	and ppc_gen_return_address.

gdb/gdbserver/ChangeLog

2015-07-13  Wei-cheng Wang  <cole945@gmail.com>

	* Makefile.in (linux-ppc-ipa.o, powerpc-64l-ipa.o,
	powerpc-32l-ipa.o): New rules.
	* configure.srv (powerpc*-*-linux*): Add powerpc-64l-ipa.o,
	powerpc-32l-ipa.o, and linux-ppc-ipa.o in ipa_obj
	* linux-ppc-ipa.c: New file.
	* linux-ppc-low.c (gen_ds_form, gen_d_form, gen_xfx_form, gen_x_form,
	gen_md_form, gen_i_form, gen_b_form, gen_limm,
	gen_atomic_xchg, gen_call, ppc_supports_tracepoints,
	ppc_install_fast_tracepoint_jump_pad,
	ppc_get_min_fast_tracepoint_insn_len, emit_insns, ppc64_emit_prologue,
	ppc64_emit_epilogue, ppc64_emit_add, ppc64_emit_sub, ppc64_emit_mul,
	ppc64_emit_lsh, ppc64_emit_rsh_signed, ppc64_emit_rsh_unsigned,
	ppc64_emit_ext, ppc64_emit_zero_ext, ppc64_emit_log_not,
	ppc64_emit_bit_and, ppc64_emit_bit_or, ppc64_emit_bit_xor,
	ppc64_emit_bit_not, ppc64_emit_equal, ppc64_emit_less_signed,
	ppc64_emit_less_unsigned, ppc64_emit_ref, ppc64_emit_const,
	ppc64_emit_reg, ppc64_emit_pop, ppc64_emit_stack_flush,
	ppc64_emit_swap, ppc64_emit_stack_adjust, ppc64_emit_call,
	ppc64_emit_int_call_1, ppc64_emit_void_call_2, ppc64_emit_if_goto,
	ppc64_emit_goto, ppc64_emit_eq_goto, ppc64_emit_ne_goto,
	ppc64_emit_lt_goto, ppc64_emit_le_goto, ppc64_emit_gt_goto,
	ppc64_emit_ge_goto, ppc_write_goto_address, ppc_emit_ops,
	ppc_supports_range_stepping, ppc_fast_tracepoint_valid_at,
	ppc_relocate_instruction): New functions.
	(ppc64_emit_ops_vector): New struct for bytecode compilation.
	(the_low_target): Add target ops - ppc_supports_tracepoints,
	ppc_install_fast_tracepoint_jump_pad, ppc_emit_ops,
	ppc_get_min_fast_tracepoint_insn_len, ppc_supports_range_stepping.

gdb/testsuite/ChangeLog

2015-07-13  Wei-cheng Wang  <cole945@gmail.com>

	* gdb.trace/backtrace.exp: Set registers for powerpc*-*-*.
	* gdb.trace/collection.exp: Ditto.
	* gdb.trace/entry-values.exp: Ditto.
	* gdb.trace/mi-trace-frame-collected.exp: Ditto.
	* gdb.trace/mi-trace-unavailable.exp: Ditto.
	* gdb.trace/pending.exp: Ditto.
	* gdb.trace/report.exp: Ditto.
	* gdb.trace/trace-break.exp: Ditto.
	* gdb.trace/while-dyn.exp: Ditto.
	* gdb.trace/change-loc.h: set_point for powerpc.
	* gdb.trace/ftrace.c: Ditto
	* gdb.trace/pendshr1.c: Ditto.
	* gdb.trace/pendshr2.c: Ditto.
	* gdb.trace/range-stepping.c: Ditto.
	* gdb.trace/trace-break.c: Ditto.
	* gdb.trace/trace-mt.c: Ditto.
	* gdb.trace/ftrace.exp: Enable testing for powerpc*-*-*.
---
 gdb/gdbserver/Makefile.in                          |    9 +
 gdb/gdbserver/configure.srv                        |    1 +
 gdb/gdbserver/linux-ppc-ipa.c                      |  120 ++
 gdb/gdbserver/linux-ppc-low.c                      | 1428 +++++++++++++++++++-
 gdb/rs6000-tdep.c                                  |  117 ++
 gdb/testsuite/gdb.trace/actions.c                  |    9 +-
 gdb/testsuite/gdb.trace/backtrace.exp              |    3 +
 gdb/testsuite/gdb.trace/change-loc.h               |    2 +
 gdb/testsuite/gdb.trace/collection.exp             |    4 +
 gdb/testsuite/gdb.trace/entry-values.exp           |    4 +-
 gdb/testsuite/gdb.trace/ftrace.c                   |    4 +
 gdb/testsuite/gdb.trace/ftrace.exp                 |    7 +-
 .../gdb.trace/mi-trace-frame-collected.exp         |    2 +
 gdb/testsuite/gdb.trace/mi-trace-unavailable.exp   |    2 +
 gdb/testsuite/gdb.trace/pending.exp                |    2 +
 gdb/testsuite/gdb.trace/pendshr1.c                 |    2 +
 gdb/testsuite/gdb.trace/pendshr2.c                 |    2 +
 gdb/testsuite/gdb.trace/range-stepping.c           |    2 +
 gdb/testsuite/gdb.trace/report.exp                 |    4 +
 gdb/testsuite/gdb.trace/trace-break.c              |    4 +
 gdb/testsuite/gdb.trace/trace-break.exp            |    4 +
 gdb/testsuite/gdb.trace/trace-mt.c                 |    2 +
 gdb/testsuite/gdb.trace/unavailable.exp            |    4 +
 gdb/testsuite/gdb.trace/while-dyn.exp              |    2 +
 24 files changed, 1732 insertions(+), 8 deletions(-)
 create mode 100644 gdb/gdbserver/linux-ppc-ipa.c

diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index fc250fb..6dab7e3 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -499,6 +499,15 @@ linux-amd64-ipa.o: linux-amd64-ipa.c
 amd64-linux-ipa.o: amd64-linux.c
 	$(IPAGENT_COMPILE) $<
 	$(POSTCOMPILE)
+linux-ppc-ipa.o: linux-ppc-ipa.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-64l-ipa.o: powerpc-64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-32l-ipa.o: powerpc-32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
 tdesc-ipa.o: tdesc.c
 	$(IPAGENT_COMPILE) $<
 	$(POSTCOMPILE)
diff --git a/gdb/gdbserver/configure.srv b/gdb/gdbserver/configure.srv
index 7f89f2f..4f34bd8 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -246,6 +246,7 @@ case "${target}" in
 			srv_linux_usrregs=yes
 			srv_linux_regsets=yes
 			srv_linux_thread_db=yes
+			ipa_obj="powerpc-64l-ipa.o powerpc-32l-ipa.o linux-ppc-ipa.o"
 			;;
   powerpc-*-lynxos*)	srv_regobj="powerpc-32.o"
 			srv_tgtobj="lynx-low.o lynx-ppc-low.o"
diff --git a/gdb/gdbserver/linux-ppc-ipa.c b/gdb/gdbserver/linux-ppc-ipa.c
new file mode 100644
index 0000000..94fc625
--- /dev/null
+++ b/gdb/gdbserver/linux-ppc-ipa.c
@@ -0,0 +1,120 @@
+/* GNU/Linux/PowerPC specific low level interface, for the in-process
+   agent library for GDB.
+
+   Copyright (C) 2010-2015 Free Software Foundation, Inc.
+
+   This file is part of GDB.
+
+   This program is free software; you can redistribute it and/or modify
+   it under the terms of the GNU General Public License as published by
+   the Free Software Foundation; either version 3 of the License, or
+   (at your option) any later version.
+
+   This program is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+   GNU General Public License for more details.
+
+   You should have received a copy of the GNU General Public License
+   along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
+
+#include "server.h"
+#include "tracepoint.h"
+
+#ifdef __powerpc64__
+void init_registers_powerpc_64l (void);
+extern const struct target_desc *tdesc_powerpc_64l;
+#define REGSZ		8
+#else
+void init_registers_powerpc_32l (void);
+extern const struct target_desc *tdesc_powerpc_32l;
+#define REGSZ		4
+#endif
+
+/* These macros define the position of registers in the buffer collected
+   by the fast tracepoint jump pad.  */
+#define FT_CR_R0	0
+#define FT_CR_CR	32
+#define FT_CR_XER	33
+#define FT_CR_LR	34
+#define FT_CR_CTR	35
+#define FT_CR_PC	36
+#define FT_CR_GPR(n)	(FT_CR_R0 + (n))
+
+static const int ppc_ft_collect_regmap[] = {
+  /* GPRs */
+  FT_CR_GPR (0), FT_CR_GPR (1), FT_CR_GPR (2),
+  FT_CR_GPR (3), FT_CR_GPR (4), FT_CR_GPR (5),
+  FT_CR_GPR (6), FT_CR_GPR (7), FT_CR_GPR (8),
+  FT_CR_GPR (9), FT_CR_GPR (10), FT_CR_GPR (11),
+  FT_CR_GPR (12), FT_CR_GPR (13), FT_CR_GPR (14),
+  FT_CR_GPR (15), FT_CR_GPR (16), FT_CR_GPR (17),
+  FT_CR_GPR (18), FT_CR_GPR (19), FT_CR_GPR (20),
+  FT_CR_GPR (21), FT_CR_GPR (22), FT_CR_GPR (23),
+  FT_CR_GPR (24), FT_CR_GPR (25), FT_CR_GPR (26),
+  FT_CR_GPR (27), FT_CR_GPR (28), FT_CR_GPR (29),
+  FT_CR_GPR (30), FT_CR_GPR (31),
+  /* FPRs - not collected.  */
+  -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1,
+  -1, -1, -1, -1, -1, -1, -1, -1,
+  FT_CR_PC, /* PC */
+  -1, /* MSR */
+  FT_CR_CR, /* CR */
+  FT_CR_LR, /* LR */
+  FT_CR_CTR, /* CTR */
+  FT_CR_XER, /* XER */
+  -1, /* FPSCR */
+};
+
+#define PPC_NUM_FT_COLLECT_GREGS \
+  (sizeof (ppc_ft_collect_regmap) / sizeof(ppc_ft_collect_regmap[0]))
+
+/* Supply registers collected by the fast tracepoint jump pad.
+   BUF is the second argument we pass to gdb_collect in jump pad.  */
+
+void
+supply_fast_tracepoint_registers (struct regcache *regcache,
+				  const unsigned char *buf)
+{
+  int i;
+
+  for (i = 0; i < PPC_NUM_FT_COLLECT_GREGS; i++)
+    {
+      if (ppc_ft_collect_regmap[i] == -1)
+	continue;
+      supply_register (regcache, i,
+		       ((char *) buf)
+			+ ppc_ft_collect_regmap[i] * REGSZ);
+    }
+}
+
+/* Return the value of register REGNUM.  RAW_REGS is collected buffer
+   by jump pad.  This function is called by emit_reg.  */
+
+IP_AGENT_EXPORT_FUNC ULONGEST
+gdb_agent_get_raw_reg (const unsigned char *raw_regs, int regnum)
+{
+  if (regnum >= PPC_NUM_FT_COLLECT_GREGS)
+    return 0;
+  if (ppc_ft_collect_regmap[regnum] == -1)
+    return 0;
+
+  return *(ULONGEST *) (raw_regs
+			+ ppc_ft_collect_regmap[regnum] * REGSZ);
+}
+
+/* Initialize ipa_tdesc and others.  */
+
+void
+initialize_low_tracepoint (void)
+{
+#ifdef __powerpc64__
+  init_registers_powerpc_64l ();
+  ipa_tdesc = tdesc_powerpc_64l;
+#else
+  init_registers_powerpc_32l ();
+  ipa_tdesc = tdesc_powerpc_32l;
+#endif
+}
diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c
index 41ec281..2f6c492 100644
--- a/gdb/gdbserver/linux-ppc-low.c
+++ b/gdb/gdbserver/linux-ppc-low.c
@@ -24,6 +24,19 @@
 #include <asm/ptrace.h>
 
 #include "nat/ppc-linux.h"
+#include "ax.h"
+#include "tracepoint.h"
+
+#define PPC_FIELD(value, from, len) \
+	(((value) >> (32 - (from) - (len))) & ((1 << (len)) - 1))
+#define PPC_SEXT(v, bs) \
+	((((CORE_ADDR) (v) & (((CORE_ADDR) 1 << (bs)) - 1)) \
+	  ^ ((CORE_ADDR) 1 << ((bs) - 1))) \
+	 - ((CORE_ADDR) 1 << ((bs) - 1)))
+#define PPC_OP6(insn)	PPC_FIELD (insn, 0, 6)
+#define PPC_BO(insn)	PPC_FIELD (insn, 6, 5)
+#define PPC_LI(insn)	(PPC_SEXT (PPC_FIELD (insn, 6, 24), 24) << 2)
+#define PPC_BD(insn)	(PPC_SEXT (PPC_FIELD (insn, 16, 14), 14) << 2)
 
 static unsigned long ppc_hwcap;
 
@@ -575,6 +588,1397 @@ ppc_remove_point (enum raw_bkpt_type type, CORE_ADDR addr,
     }
 }
 
+/* Generate a ds-form instruction in BUF and return the number of bytes written
+
+   0      6     11   16          30 32
+   | OPCD | RST | RA |     DS    |XO|  */
+
+__attribute__((unused)) /* Maybe unused due to conditional compilation.  */
+static int
+gen_ds_form (uint32_t *buf, int opcd, int rst, int ra, int ds, int xo)
+{
+  uint32_t insn;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((rst & ~0x1f) == 0);
+  gdb_assert ((ra & ~0x1f) == 0);
+  gdb_assert ((xo & ~0x3) == 0);
+
+  insn = (rst << 21) | (ra << 16) | (ds & 0xfffc) | (xo & 0x3);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* Followings are frequently used ds-form instructions.  */
+
+#define GEN_STD(buf, rs, ra, offset)	gen_ds_form (buf, 62, rs, ra, offset, 0)
+#define GEN_STDU(buf, rs, ra, offset)	gen_ds_form (buf, 62, rs, ra, offset, 1)
+#define GEN_LD(buf, rt, ra, offset)	gen_ds_form (buf, 58, rt, ra, offset, 0)
+#define GEN_LDU(buf, rt, ra, offset)	gen_ds_form (buf, 58, rt, ra, offset, 1)
+
+/* Generate a d-form instruction in BUF.
+
+   0      6     11   16             32
+   | OPCD | RST | RA |       D      |  */
+
+static int
+gen_d_form (uint32_t *buf, int opcd, int rst, int ra, int si)
+{
+  uint32_t insn;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((rst & ~0x1f) == 0);
+  gdb_assert ((ra & ~0x1f) == 0);
+
+  insn = (rst << 21) | (ra << 16) | (si & 0xffff);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* Followings are frequently used d-form instructions.  */
+
+#define GEN_ADDI(buf, rt, ra, si)	gen_d_form (buf, 14, rt, ra, si)
+#define GEN_ADDIS(buf, rt, ra, si)	gen_d_form (buf, 15, rt, ra, si)
+#define GEN_LI(buf, rt, si)		GEN_ADDI (buf, rt, 0, si)
+#define GEN_LIS(buf, rt, si)		GEN_ADDIS (buf, rt, 0, si)
+#define GEN_ORI(buf, rt, ra, si)	gen_d_form (buf, 24, rt, ra, si)
+#define GEN_ORIS(buf, rt, ra, si)	gen_d_form (buf, 25, rt, ra, si)
+#define GEN_LWZ(buf, rt, ra, si)	gen_d_form (buf, 32, rt, ra, si)
+#define GEN_STW(buf, rt, ra, si)	gen_d_form (buf, 36, rt, ra, si)
+
+/* Generate a xfx-form instruction in BUF and return the number of bytes
+   written.
+
+   0      6     11         21        31 32
+   | OPCD | RST |    RI    |    XO   |/|  */
+
+static int
+gen_xfx_form (uint32_t *buf, int opcd, int rst, int ri, int xo)
+{
+  uint32_t insn;
+  unsigned int n = ((ri & 0x1f) << 5) | ((ri >> 5) & 0x1f);
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((rst & ~0x1f) == 0);
+  gdb_assert ((xo & ~0x3ff) == 0);
+
+  insn = (rst << 21) | (n << 11) | (xo << 1);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* Followings are frequently used xfx-form instructions.  */
+
+#define GEN_MFSPR(buf, rt, spr)		gen_xfx_form (buf, 31, rt, spr, 339)
+#define GEN_MTSPR(buf, rt, spr)		gen_xfx_form (buf, 31, rt, spr, 467)
+#define GEN_MFCR(buf, rt)		gen_xfx_form (buf, 31, rt, 0, 19)
+#define GEN_MTCR(buf, rt)		gen_xfx_form (buf, 31, rt, 0x3cf, 144)
+#define GEN_SYNC(buf, L, E)             gen_xfx_form (buf, 31, L & 0x3, \
+						      E & 0xf, 598)
+#define GEN_LWSYNC(buf)			GEN_SYNC (buf, 1, 0)
+
+
+/* Generate a x-form instruction in BUF and return the number of bytes written.
+
+   0      6     11   16   21       31 32
+   | OPCD | RST | RA | RB |   XO   |RC|  */
+
+static int
+gen_x_form (uint32_t *buf, int opcd, int rst, int ra, int rb, int xo, int rc)
+{
+  uint32_t insn;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((rst & ~0x1f) == 0);
+  gdb_assert ((ra & ~0x1f) == 0);
+  gdb_assert ((rb & ~0x1f) == 0);
+  gdb_assert ((xo & ~0x3ff) == 0);
+  gdb_assert ((rc & ~1) == 0);
+
+  insn = (rst << 21) | (ra << 16) | (rb << 11) | (xo << 1) | rc;
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* Followings are frequently used x-form instructions.  */
+
+#define GEN_OR(buf, ra, rs, rb)		gen_x_form (buf, 31, rs, ra, rb, 444, 0)
+#define GEN_MR(buf, ra, rs)		GEN_OR (buf, ra, rs, rs)
+#define GEN_LWARX(buf, rt, ra, rb)	gen_x_form (buf, 31, rt, ra, rb, 20, 0)
+#define GEN_STWCX(buf, rs, ra, rb)	gen_x_form (buf, 31, rs, ra, rb, 150, 1)
+/* Assume bf = cr7.  */
+#define GEN_CMPW(buf, ra, rb)		gen_x_form (buf, 31, 28, ra, rb, 0, 0)
+
+
+/* Generate a md-form instruction in BUF and return the number of bytes written.
+
+   0      6    11   16   21   27   30 31 32
+   | OPCD | RS | RA | sh | mb | XO |sh|Rc|  */
+
+static int
+gen_md_form (uint32_t *buf, int opcd, int rs, int ra, int sh, int mb,
+	     int xo, int rc)
+{
+  uint32_t insn;
+  unsigned int n = ((mb & 0x1f) << 1) | ((mb >> 5) & 0x1);
+  unsigned int sh0_4 = sh & 0x1f;
+  unsigned int sh5 = (sh >> 5) & 1;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((rs & ~0x1f) == 0);
+  gdb_assert ((ra & ~0x1f) == 0);
+  gdb_assert ((sh & ~0x3f) == 0);
+  gdb_assert ((mb & ~0x3f) == 0);
+  gdb_assert ((xo & ~0x7) == 0);
+  gdb_assert ((rc & ~0x1) == 0);
+
+  insn = (rs << 21) | (ra << 16) | (sh0_4 << 11) | (n << 5)
+	 | (sh5 << 1) | (xo << 2) | (rc & 1);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* The following are frequently used md-form instructions.  */
+
+#define GEN_RLDICL(buf, ra, rs ,sh, mb) \
+				gen_md_form (buf, 30, rs, ra, sh, mb, 0, 0)
+#define GEN_RLDICR(buf, ra, rs ,sh, mb) \
+				gen_md_form (buf, 30, rs, ra, sh, mb, 1, 0)
+
+/* Generate a i-form instruction in BUF and return the number of bytes written.
+
+   0      6                          30 31 32
+   | OPCD |            LI            |AA|LK|  */
+
+static int
+gen_i_form (uint32_t *buf, int opcd, int li, int aa, int lk)
+{
+  uint32_t insn;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+
+  insn = (li & 0x3fffffc) | (aa & 1) | (lk & 1);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* The following are frequently used i-form instructions.  */
+
+#define GEN_B(buf, li)		gen_i_form (buf, 18, li, 0, 0)
+#define GEN_BL(buf, li)		gen_i_form (buf, 18, li, 0, 1)
+
+/* Generate a b-form instruction in BUF and return the number of bytes written.
+
+   0      6    11   16               30 31 32
+   | OPCD | BO | BI |      BD        |AA|LK|  */
+
+static int
+gen_b_form (uint32_t *buf, int opcd, int bo, int bi, int bd,
+	    int aa, int lk)
+{
+  uint32_t insn;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((bo & ~0x1f) == 0);
+  gdb_assert ((bi & ~0x1f) == 0);
+
+  insn = (bo << 21) | (bi << 16) | (bd & 0xfffc) | (aa & 1) | (lk & 1);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* The following are frequently used b-form instructions.  */
+/* Assume bi = cr7.  */
+#define GEN_BNE(buf, bd)  gen_b_form (buf, 16, 0x4, (7 << 2) | 2, bd, 0 ,0)
+
+/* GEN_LOAD and GEN_STORE generate 64- or 32-bit load/store for ppc64 or ppc32
+   respectively.  They are primary used for save/restore GPRs in jump-pad,
+   not used for bytecode compiling.  */
+
+#if defined __powerpc64__
+#define GEN_LOAD(buf, rt, ra, si)	GEN_LD (buf, rt, ra, si)
+#define GEN_STORE(buf, rt, ra, si)	GEN_STD (buf, rt, ra, si)
+#else
+#define GEN_LOAD(buf, rt, ra, si)	GEN_LWZ (buf, rt, ra, si)
+#define GEN_STORE(buf, rt, ra, si)	GEN_STW (buf, rt, ra, si)
+#endif
+
+/* Generate a sequence of instructions to load IMM in the register REG.
+   Write the instructions in BUF and return the number of bytes written.  */
+
+static int
+gen_limm (uint32_t *buf, int reg, uint64_t imm)
+{
+  uint32_t *p = buf;
+
+  if ((imm + 32768) < 65536)
+    {
+      /* li	reg, imm[7:0] */
+      p += GEN_LI (p, reg, imm);
+    }
+  else if ((imm >> 16) == 0)
+    {
+      /* li	reg, 0
+	 ori	reg, reg, imm[15:0] */
+      p += GEN_LI (p, reg, 0);
+      p += GEN_ORI (p, reg, reg, imm);
+    }
+  else if ((imm >> 32) == 0)
+    {
+      /* lis	reg, imm[31:16]
+	 ori	reg, reg, imm[15:0]
+	 rldicr reg, reg, 0, 32 */
+      p += GEN_LIS (p, reg, (imm >> 16) & 0xffff);
+      p += GEN_ORI (p, reg, reg, imm & 0xffff);
+      /* Clear upper 32-bit if sign-bit is set.  */
+      if (imm & (1 << 31))
+	p += GEN_RLDICL (p, reg, reg, 0, 32);
+    }
+  else
+    {
+      /* lis    reg, <imm[63:48]>
+	 ori    reg, reg, <imm[48:32]>
+	 rldicr reg, reg, 32, 31
+	 oris   reg, reg, <imm[31:16]>
+	 ori    reg, reg, <imm[15:0]> */
+      p += GEN_LIS (p, reg, ((imm >> 48) & 0xffff));
+      p += GEN_ORI (p, reg, reg, ((imm >> 32) & 0xffff));
+      p += GEN_RLDICR (p, reg, reg, 32, 31);
+      p += GEN_ORIS (p, reg, reg, ((imm >> 16) & 0xffff));
+      p += GEN_ORI (p, reg, reg, (imm & 0xffff));
+    }
+
+  return p - buf;
+}
+
+/* Generate a sequence for atomically exchange at location LOCK.
+   This code sequence clobbers r6, r7, r8.  LOCK is the location for
+   the atomic-xchg, OLD_VALUE is expected old value stored in the
+   location, and R_NEW is a register for the new value.  */
+
+static int
+gen_atomic_xchg (uint32_t *buf, CORE_ADDR lock, int old_value, int r_new)
+{
+  const int r_lock = 6;
+  const int r_old = 7;
+  const int r_tmp = 8;
+  uint32_t *p = buf;
+
+  /*
+  1: lwarx   TMP, 0, LOCK
+     cmpwi   TMP, OLD
+     bne     1b
+     stwcx.  NEW, 0, LOCK
+     bne     1b */
+
+  p += gen_limm (p, r_lock, lock);
+  p += gen_limm (p, r_old, old_value);
+
+  p += GEN_LWARX (p, r_tmp, 0, r_lock);
+  p += GEN_CMPW (p, r_tmp, r_old);
+  p += GEN_BNE (p, -8);
+  p += GEN_STWCX (p, r_new, 0, r_lock);
+  p += GEN_BNE (p, -16);
+
+  return p - buf;
+}
+
+/* Generate a sequence of instructions for calling a function
+   at address of FN.  Return the number of bytes are written in BUF.
+
+   FIXME: For ppc64be, FN should be the address to the function
+   descriptor, so we should load 8(FN) to R2, 16(FN) to R11
+   and then call the function-entry at 0(FN).  However, current GDB
+   implicitly convert the address from function descriptor to the actual
+   function address. See qSymbol handling in remote.c.  Although it
+   seems we can successfully call however, things go wrong when callee
+   trying to access global variable.  */
+
+static int
+gen_call (uint32_t *buf, CORE_ADDR fn)
+{
+  uint32_t *p = buf;
+
+  /* Must be called by r12 for caller to calculate TOC address. */
+  p += gen_limm (p, 12, fn);
+  p += GEN_MTSPR (p, 12, 9);		/* mtctr  r12 */
+  *p++ = 0x4e800421;			/* bctrl */
+
+  return p - buf;
+}
+
+/* Implement supports_tracepoints hook of target_ops.
+   Always return true.  */
+
+static int
+ppc_supports_tracepoints (void)
+{
+#if defined (__powerpc64__) && _CALL_ELF == 2
+  return 1;
+#else
+  return 0;
+#endif
+}
+
+/* Get the thread area address.  This is used to recognize which
+   thread is which when tracing with the in-process agent library.  We
+   don't read anything from the address, and treat it as opaque; it's
+   the address itself that we assume is unique per-thread.  */
+
+static int
+ppc_get_thread_area (int lwpid, CORE_ADDR *addr)
+{
+  struct lwp_info *lwp = find_lwp_pid (pid_to_ptid (lwpid));
+  struct thread_info *thr = get_lwp_thread (lwp);
+  struct regcache *regcache = get_thread_regcache (thr, 1);
+  ULONGEST tp = 0;
+
+#ifdef __powerpc64__
+  collect_register_by_name (regcache, "r13", &tp);
+#else
+  collect_register_by_name (regcache, "r2", &tp);
+#endif
+
+  *addr = tp;
+  return 0;
+}
+
+/* Copy the instruction from OLDLOC to *TO, and update *TO to *TO + size
+   of instruction.  This function is used to adjust pc-relative instructions
+   when copying.  */
+
+static void
+ppc_relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc)
+{
+  uint32_t insn, op6;
+  long rel, newrel;
+
+  read_inferior_memory (oldloc, (unsigned char *) &insn, 4);
+  op6 = PPC_OP6 (insn);
+
+  if (op6 == 18 && (insn & 2) == 0)
+    {
+      /* branch && AA = 0 */
+      rel = PPC_LI (insn);
+      newrel = (oldloc - *to) + rel;
+
+      /* Out of range. Cannot relocate instruction.  */
+      if (newrel >= (1 << 25) || newrel < -(1 << 25))
+	return;
+
+      insn = (insn & ~0x3fffffc) | (newrel & 0x3fffffc);
+    }
+  else if (op6 == 16 && (insn & 2) == 0)
+    {
+      /* conditional branch && AA = 0 */
+
+      /* If the new relocation is too big for even a 26-bit unconditional
+	 branch, there is nothing we can do.  Just abort.
+
+	 Otherwise, if it can be fit in 16-bit conditional branch, just
+	 copy the instruction and relocate the address.
+
+	 If the it's  big for conditional-branch (16-bit), try to invert the
+	 condition and jump with 26-bit branch.  For example,
+
+	 beq  .Lgoto
+	 INSN1
+
+	 =>
+
+	 bne  1f (+8)
+	 b    .Lgoto
+       1:INSN1
+
+	 After this transform, we are actually jump from *TO+4 instead of *TO,
+	 so check the relocation again because it will be 1-insn farther then
+	 before if *TO is after OLDLOC.
+
+
+	 For BDNZT (or so) is transformed from
+
+	 bdnzt  eq, .Lgoto
+	 INSN1
+
+	 =>
+
+	 bdz    1f (+12)
+	 bf     eq, 1f (+8)
+	 b      .Lgoto
+       1:INSN1
+
+	 See also "BO field encodings".  */
+
+      rel = PPC_BD (insn);
+      newrel = (oldloc - *to) + rel;
+
+      if (newrel < (1 << 15) && newrel >= -(1 << 15))
+	insn = (insn & ~0xfffc) | (newrel & 0xfffc);
+      else if ((PPC_BO (insn) & 0x14) == 0x4 || (PPC_BO (insn) & 0x14) == 0x10)
+	{
+	  newrel -= 4;
+
+	  /* Out of range. Cannot relocate instruction.  */
+	  if (newrel >= (1 << 25) || newrel < -(1 << 25))
+	    return;
+
+	  if ((PPC_BO (insn) & 0x14) == 0x4)
+	    insn ^= (1 << 24);
+	  else if ((PPC_BO (insn) & 0x14) == 0x10)
+	    insn ^= (1 << 22);
+
+	  /* Jump over the unconditional branch.  */
+	  insn = (insn & ~0xfffc) | 0x8;
+	  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+	  *to += 4;
+
+	  /* Build a unconditional branch and copy LK bit.  */
+	  insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3);
+	  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+	  *to += 4;
+
+	  return;
+	}
+      else if ((PPC_BO (insn) & 0x14) == 0)
+	{
+	  uint32_t bdnz_insn = (16 << 26) | (0x10 << 21) | 12;
+	  uint32_t bf_insn = (16 << 26) | (0x4 << 21) | 8;
+
+	  newrel -= 8;
+
+	  /* Out of range. Cannot relocate instruction.  */
+	  if (newrel >= (1 << 25) || newrel < -(1 << 25))
+	    return;
+
+	  /* Copy BI field.  */
+	  bf_insn |= (insn & 0x1f0000);
+
+	  /* Invert condition.  */
+	  bdnz_insn |= (insn ^ (1 << 22)) & (1 << 22);
+	  bf_insn |= (insn ^ (1 << 24)) & (1 << 24);
+
+	  write_inferior_memory (*to, (unsigned char *) &bdnz_insn, 4);
+	  *to += 4;
+	  write_inferior_memory (*to, (unsigned char *) &bf_insn, 4);
+	  *to += 4;
+
+	  /* Build a unconditional branch and copy LK bit.  */
+	  insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3);
+	  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+	  *to += 4;
+
+	  return;
+	}
+      else /* (BO & 0x14) == 0x14, branch always.  */
+	{
+	  /* Out of range. Cannot relocate instruction.  */
+	  if (newrel >= (1 << 25) || newrel < -(1 << 25))
+	    return;
+
+	  /* Build a unconditional branch and copy LK bit.  */
+	  insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3);
+	  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+	  *to += 4;
+
+	  return;
+	}
+    }
+
+  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+  *to += 4;
+}
+
+/* Implement install_fast_tracepoint_jump_pad of target_ops.
+   See target.h for details.  */
+
+static int
+ppc_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
+				      CORE_ADDR collector,
+				      CORE_ADDR lockaddr,
+				      ULONGEST orig_size,
+				      CORE_ADDR *jump_entry,
+				      CORE_ADDR *trampoline,
+				      ULONGEST *trampoline_size,
+				      unsigned char *jjump_pad_insn,
+				      ULONGEST *jjump_pad_insn_size,
+				      CORE_ADDR *adjusted_insn_addr,
+				      CORE_ADDR *adjusted_insn_addr_end,
+				      char *err)
+{
+  uint32_t buf[256];
+  uint32_t *p = buf;
+  int j, offset;
+  CORE_ADDR buildaddr = *jump_entry;
+  const CORE_ADDR entryaddr = *jump_entry;
+#ifdef __powerpc64__
+  /* Minimum frame size is 32 bytes for ELFv2, and 112 bytes for ELFv1.  */
+  const int rsz = 8;
+  const int min_frame = 112;
+  const int frame_size = (40 * rsz) + min_frame;
+  const int tp_reg = 13;
+#else
+  const int rsz = 4;
+  const int min_frame = 16;
+  const int frame_size = (40 * rsz) + min_frame;
+  const int tp_reg = 2;
+#endif
+
+  /* Stack frame layout for this jump pad,
+
+     High	thread_area (r13/r2)    |
+		tpoint			- collecting_t obj
+		PC/<tpaddr>		| +36
+		CTR			| +35
+		LR			| +34
+		XER			| +33
+		CR			| +32
+		R31			|
+		R29			|
+		...			|
+		R1			| +1
+		R0			- collected registers
+		...			|
+		...			|
+     Low	Back-chain		-
+
+
+     The code flow of this jump pad,
+
+     1. Adjust SP
+     2. Save GPR and SPR
+     3. Prepare argument
+     4. Call gdb_collector
+     5. Restore GPR and SPR
+     6. Restore SP
+     7. Build a jump for back to the program
+     8. Copy/relocate original instruction
+     9. Build a jump for replacing orignal instruction.  */
+
+  /* Adjust stack pointer.  */
+  p += GEN_STDU (p, 1, 1, -frame_size);		/* stdu   r1,-frame_size(r1) */
+
+  /* Store GPRs.  Save R1 later, because it had just been modified, but
+     we want the original value.  */
+  for (j = 2; j < 32; j++)
+    p += GEN_STORE (p, j, 1, min_frame + j * rsz);
+  p += GEN_STORE (p, 0, 1, min_frame + 0 * rsz);
+  /* Set r0 to the original value of r1 before adjusting stack frame,
+     and then save it.  */
+  p += GEN_ADDI (p, 0, 1, frame_size);
+  p += GEN_STORE (p, 0, 1, min_frame + 1 * rsz);
+
+  /* Save CR, XER, LR, and CTR.  */
+  p += GEN_MFCR (p, 3);					/* mfcr   r3 */
+  p += GEN_MFSPR (p, 4, 1);				/* mfxer  r4 */
+  p += GEN_MFSPR (p, 5, 8);				/* mflr   r5 */
+  p += GEN_MFSPR (p, 6, 9);				/* mfctr  r6 */
+  p += GEN_STORE (p, 3, 1, min_frame + 32 * rsz);	/* std    r3, 32(r1) */
+  p += GEN_STORE (p, 4, 1, min_frame + 33 * rsz);	/* std    r4, 33(r1) */
+  p += GEN_STORE (p, 5, 1, min_frame + 34 * rsz);	/* std    r5, 34(r1) */
+  p += GEN_STORE (p, 6, 1, min_frame + 35 * rsz);	/* std    r6, 35(r1) */
+
+  /* Save PC<tpaddr>  */
+  p += gen_limm (p, 3, tpaddr);
+  p += GEN_STORE (p, 3, 1, min_frame + 36 * rsz);
+
+
+  /* Setup arguments to collector.  */
+  /* Set r4 to collected registers.  */
+  p += GEN_ADDI (p, 4, 1, min_frame);
+  /* Set r3 to TPOINT.  */
+  p += gen_limm (p, 3, tpoint);
+
+  /* Prepare collecting_t object for lock.  */
+  p += GEN_STORE (p, 3, 1, min_frame + 37 * rsz);
+  p += GEN_STORE (p, tp_reg, 1, min_frame + 38 *rsz);
+  /* Set R5 to collecting object.  */
+  p += GEN_ADDI (p, 5, 1, 37 * rsz);
+
+  p += GEN_LWSYNC (p);
+  p += gen_atomic_xchg (p, lockaddr, 0, 5);
+  p += GEN_LWSYNC (p);
+
+  /* Call to collector.  */
+  p += gen_call (p, collector);
+
+  /* Simply write 0 to release the lock.  */
+  p += gen_limm (p, 3, lockaddr);
+  p += gen_limm (p, 4, 0);
+  p += GEN_LWSYNC (p);
+  p += GEN_STORE (p, 4, 3, 0);
+
+  /* Restore stack and registers.  */
+  p += GEN_LOAD (p, 3, 1, min_frame + 32 * rsz);	/* ld	r3, 32(r1) */
+  p += GEN_LOAD (p, 4, 1, min_frame + 33 * rsz);	/* ld	r4, 33(r1) */
+  p += GEN_LOAD (p, 5, 1, min_frame + 34 * rsz);	/* ld	r5, 34(r1) */
+  p += GEN_LOAD (p, 6, 1, min_frame + 35 * rsz);	/* ld	r6, 35(r1) */
+  p += GEN_MTCR (p, 3);					/* mtcr	  r3 */
+  p += GEN_MTSPR (p, 4, 1);				/* mtxer  r4 */
+  p += GEN_MTSPR (p, 5, 8);				/* mtlr   r5 */
+  p += GEN_MTSPR (p, 6, 9);				/* mtctr  r6 */
+
+  /* Restore GPRs.  */
+  for (j = 2; j < 32; j++)
+    p += GEN_LOAD (p, j, 1, min_frame + j * rsz);
+  p += GEN_LOAD (p, 0, 1, min_frame + 0 * rsz);
+  /* Restore SP.  */
+  p += GEN_ADDI (p, 1, 1, frame_size);
+
+  /* Flush instructions to inferior memory.  */
+  write_inferior_memory (buildaddr, (unsigned char *) buf, (p - buf) * 4);
+
+  /* Now, insert the original instruction to execute in the jump pad.  */
+  *adjusted_insn_addr = buildaddr + (p - buf) * 4;
+  *adjusted_insn_addr_end = *adjusted_insn_addr;
+  ppc_relocate_instruction (adjusted_insn_addr_end, tpaddr);
+
+  /* Verify the relocation size.  If should be 4 for normal copy,
+     8 or 12 for some conditional branch.  */
+  if ((*adjusted_insn_addr_end - *adjusted_insn_addr == 0)
+      || (*adjusted_insn_addr_end - *adjusted_insn_addr > 12))
+    {
+      sprintf (err, "E.Unexpected instruction length = %d"
+		    "when relocate instruction.",
+		    (int) (*adjusted_insn_addr_end - *adjusted_insn_addr));
+      return 1;
+    }
+
+  buildaddr = *adjusted_insn_addr_end;
+  p = buf;
+  /* Finally, write a jump back to the program.  */
+  offset = (tpaddr + 4) - buildaddr;
+  if (offset >= (1 << 25) || offset < -(1 << 25))
+    {
+      sprintf (err, "E.Jump back from jump pad too far from tracepoint "
+		    "(offset 0x%x > 26-bit).", offset);
+      return 1;
+    }
+  /* b <tpaddr+4> */
+  p += GEN_B (p, offset);
+  write_inferior_memory (buildaddr, (unsigned char *) buf, (p - buf) * 4);
+  *jump_entry = buildaddr + (p - buf) * 4;
+
+  /* The jump pad is now built.  Wire in a jump to our jump pad.  This
+     is always done last (by our caller actually), so that we can
+     install fast tracepoints with threads running.  This relies on
+     the agent's atomic write support.  */
+  offset = entryaddr - tpaddr;
+  if (offset >= (1 << 25) || offset < -(1 << 25))
+    {
+      sprintf (err, "E.Jump back from jump pad too far from tracepoint "
+		    "(offset 0x%x > 26-bit).", offset);
+      return 1;
+    }
+  /* b <jentry> */
+  GEN_B ((uint32_t *) jjump_pad_insn, offset);
+  *jjump_pad_insn_size = 4;
+
+  return 0;
+}
+
+/* Returns the minimum instruction length for installing a tracepoint.  */
+
+static int
+ppc_get_min_fast_tracepoint_insn_len ()
+{
+  return 4;
+}
+
+#ifdef __powerpc64__
+
+static void
+emit_insns (uint32_t *buf, int n)
+{
+  n = n * sizeof (uint32_t);
+  write_inferior_memory (current_insn_ptr, (unsigned char *) buf, n);
+  current_insn_ptr += n;
+}
+
+#define __EMIT_ASM(NAME, INSNS)					\
+  do								\
+    {								\
+      extern uint32_t start_bcax_ ## NAME [];			\
+      extern uint32_t end_bcax_ ## NAME [];			\
+      emit_insns (start_bcax_ ## NAME,				\
+		  end_bcax_ ## NAME - start_bcax_ ## NAME);	\
+      __asm__ (".section .text.__ppcbcax\n\t"			\
+	       "start_bcax_" #NAME ":\n\t"			\
+	       INSNS "\n\t"					\
+	       "end_bcax_" #NAME ":\n\t"			\
+	       ".previous\n\t");				\
+    } while (0)
+
+#define _EMIT_ASM(NAME, INSNS)		__EMIT_ASM (NAME, INSNS)
+#define EMIT_ASM(INSNS)			_EMIT_ASM (__LINE__, INSNS)
+
+/*
+
+  Bytecode execution stack frame
+
+	|  LR save area           (SP + 16)
+	|  CR save area           (SP + 8)
+ SP' -> +- Back chain             (SP + 0)
+	|  Save r31   for access saved arguments
+	|  Save r30   for bytecode stack pointer
+	|  Save r4    for incoming argument *value
+	|  Save r3    for incoming argument regs
+ r30 -> +- Bytecode execution stack
+	|
+	|  64-byte (8 doublewords) at initial.
+	|  Expand stack as needed.
+	|
+	+-
+        |  Some padding for minimum stack frame.
+        |  112 for ELFv1.
+ SP     +- Back-chain (SP')
+
+  initial frame size
+  = 112 + (4 * 8) + 64
+  = 208
+
+   r30 is the stack-pointer for bytecode machine.
+       It should point to next-empty, so we can use LDU for pop.
+   r3  is used for cache of TOP value.
+       It was the first argument, pointer to regs.
+   r4  is the second argument, pointer to the result.
+       We should set *result = TOP after leaving this function.
+
+ Note:
+ * To restore stack at epilogue
+   => sp = r31 + 208
+ * To check stack is big enough for bytecode execution.
+   => r30 - 8 > SP + 112
+ * To return execution result.
+   => 0(r4) = TOP
+
+ */
+
+/* Emit prologue in inferior memory.  See above comments.  */
+
+static void
+ppc64_emit_prologue (void)
+{
+  EMIT_ASM (/* Save return address.  */
+	    "mflr  0		\n"
+	    "std   0, 16(1)	\n"
+	    /* Save r30 and incoming arguments.  */
+	    "std   31, -8(1)	\n"
+	    "std   30, -16(1)	\n"
+	    "std   4, -24(1)	\n"
+	    "std   3, -32(1)	\n"
+	    /* Point r31 to current r1 for access arguments.  */
+	    "mr    31, 1	\n"
+	    /* Adjust SP.  208 is the initial frame size.  */
+	    "stdu  1, -208(1)	\n"
+	    /* Set r30 to pointing stack-top.  */
+	    "addi  30, 1, 168	\n"
+	    /* Initial r3/TOP to 0.  */
+	    "li	   3, 0		\n");
+}
+
+/* Emit epilogue in inferior memory.  See above comments.  */
+
+static void
+ppc64_emit_epilogue (void)
+{
+  EMIT_ASM (/* Restore SP.  */
+	    "ld    1, 0(1)      \n"
+	    /* *result = TOP */
+	    "ld    4, -24(1)	\n"
+	    "std   3, 0(4)	\n"
+	    /* Restore registers.  */
+	    "ld    31, -8(1)	\n"
+	    "ld    30, -16(1)	\n"
+            /* Restore LR.  */
+	    "ld    0, 16(1)	\n"
+	    /* Return 0 for no-error.  */
+	    "li    3, 0		\n"
+	    "mtlr  0		\n"
+	    "blr		\n");
+}
+
+/* TOP = stack[--sp] + TOP  */
+
+static void
+ppc64_emit_add (void)
+{
+  EMIT_ASM ("ldu  4, 8(30)	\n"
+	    "add  3, 4, 3	\n");
+}
+
+/* TOP = stack[--sp] - TOP  */
+
+static void
+ppc64_emit_sub (void)
+{
+  EMIT_ASM ("ldu  4, 8(30)	\n"
+	    "sub  3, 4, 3	\n");
+}
+
+/* TOP = stack[--sp] * TOP  */
+
+static void
+ppc64_emit_mul (void)
+{
+  EMIT_ASM ("ldu    4, 8(30)	\n"
+	    "mulld  3, 4, 3	\n");
+}
+
+/* TOP = stack[--sp] << TOP  */
+
+static void
+ppc64_emit_lsh (void)
+{
+  EMIT_ASM ("ldu  4, 8(30)	\n"
+	    "sld  3, 4, 3	\n");
+}
+
+/* Top = stack[--sp] >> TOP
+   (Arithmetic shift right)  */
+
+static void
+ppc64_emit_rsh_signed (void)
+{
+  EMIT_ASM ("ldu   4, 8(30)	\n"
+	    "srad  3, 4, 3	\n");
+}
+
+/* Top = stack[--sp] >> TOP
+   (Logical shift right)  */
+
+static void
+ppc64_emit_rsh_unsigned (void)
+{
+  EMIT_ASM ("ldu  4, 8(30)	\n"
+	    "srd  3, 4, 3	\n");
+}
+
+/* Emit code for signed-extension specified by ARG.  */
+
+static void
+ppc64_emit_ext (int arg)
+{
+  switch (arg)
+    {
+    case 8:
+      EMIT_ASM ("extsb  3, 3");
+      break;
+    case 16:
+      EMIT_ASM ("extsh  3, 3");
+      break;
+    case 32:
+      EMIT_ASM ("extsw  3, 3");
+      break;
+    default:
+      emit_error = 1;
+    }
+}
+
+/* Emit code for zero-extension specified by ARG.  */
+
+static void
+ppc64_emit_zero_ext (int arg)
+{
+  switch (arg)
+    {
+    case 8:
+      EMIT_ASM ("rldicl 3,3,0,56");
+      break;
+    case 16:
+      EMIT_ASM ("rldicl 3,3,0,48");
+      break;
+    case 32:
+      EMIT_ASM ("rldicl 3,3,0,32");
+      break;
+    default:
+      emit_error = 1;
+    }
+}
+
+/* TOP = !TOP
+   i.e., TOP = (TOP == 0) ? 1 : 0;  */
+
+static void
+ppc64_emit_log_not (void)
+{
+  EMIT_ASM ("cntlzd  3, 3	\n"
+	    "srdi    3, 3, 6	\n");
+}
+
+/* TOP = stack[--sp] & TOP  */
+
+static void
+ppc64_emit_bit_and (void)
+{
+  EMIT_ASM ("ldu  4, 8(30)	\n"
+	    "and  3, 4, 3	\n");
+}
+
+/* TOP = stack[--sp] | TOP  */
+
+static void
+ppc64_emit_bit_or (void)
+{
+  EMIT_ASM ("ldu  4, 8(30)	\n"
+	    "or   3, 4, 3	\n");
+}
+
+/* TOP = stack[--sp] ^ TOP  */
+
+static void
+ppc64_emit_bit_xor (void)
+{
+  EMIT_ASM ("ldu  4, 8(30)	\n"
+	    "xor  3, 4, 3	\n");
+}
+
+/* TOP = ~TOP
+   i.e., TOP = ~(TOP | TOP)  */
+
+static void
+ppc64_emit_bit_not (void)
+{
+  EMIT_ASM ("nor  3, 3, 3	\n");
+}
+
+/* TOP = stack[--sp] == TOP  */
+
+static void
+ppc64_emit_equal (void)
+{
+  EMIT_ASM ("ldu     4, 8(30)	\n"
+	    "xor     3, 3, 4	\n"
+	    "cntlzd  3, 3	\n"
+	    "srdi    3, 3, 6	\n");
+}
+
+/* TOP = stack[--sp] < TOP
+   (Signed comparison)  */
+
+static void
+ppc64_emit_less_signed (void)
+{
+  EMIT_ASM ("ldu     4, 8(30)		\n"
+	    "cmpd    7, 4, 3		\n"
+	    "mfocrf  3, 1		\n"
+	    "rlwinm  3, 3, 29, 31, 31	\n");
+}
+
+/* TOP = stack[--sp] < TOP
+   (Unsigned comparison)  */
+
+static void
+ppc64_emit_less_unsigned (void)
+{
+  EMIT_ASM ("ldu     4, 8(30)		\n"
+	    "cmpld   7, 4, 3		\n"
+	    "mfocrf  3, 1		\n"
+	    "rlwinm  3, 3, 29, 31, 31	\n");
+}
+
+/* Access the memory address in TOP in size of SIZE.
+   Zero-extend the read value.  */
+
+static void
+ppc64_emit_ref (int size)
+{
+  switch (size)
+    {
+    case 1:
+      EMIT_ASM ("lbz   3, 0(3)");
+      break;
+    case 2:
+      EMIT_ASM ("lhz   3, 0(3)");
+      break;
+    case 4:
+      EMIT_ASM ("lwz   3, 0(3)");
+      break;
+    case 8:
+      EMIT_ASM ("ld    3, 0(3)");
+      break;
+    }
+}
+
+/* TOP = NUM  */
+
+static void
+ppc64_emit_const (LONGEST num)
+{
+  uint32_t buf[5];
+  uint32_t *p = buf;
+
+  p += gen_limm (p, 3, num);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= sizeof (buf));
+}
+
+/* Set TOP to the value of register REG by calling get_raw_reg function
+   with two argument, collected buffer and register number.  */
+
+static void
+ppc64_emit_reg (int reg)
+{
+  uint32_t buf[10];
+  uint32_t *p = buf;
+
+  /* fctx->regs is passed in r3 and then saved in 176(1).  */
+  p += GEN_LOAD (p, 3, 31, -32);
+  p += GEN_LI (p, 4, reg);	/* li	r4, reg */
+  p += gen_call (p, get_raw_reg_func_addr ());
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= sizeof (buf));
+}
+
+/* TOP = stack[--sp] */
+
+static void
+ppc64_emit_pop (void)
+{
+  EMIT_ASM ("ldu  3, 8(30)");
+}
+
+/* stack[sp++] = TOP
+
+   Because we may use up bytecode stack, expand 8 doublewords more
+   if needed.  */
+
+static void
+ppc64_emit_stack_flush (void)
+{
+  /* Make sure bytecode stack is big enough before push.
+     Otherwise, expand 64-byte more.  */
+
+  EMIT_ASM ("  std   3, 0(30)		\n"
+	    "  addi  4, 30, -(112 + 8)	\n"
+	    "  cmpd  7, 4, 1		\n"
+	    "  bgt   7, 1f		\n"
+	    "  ld    4, 0(1)		\n"
+	    "  stdu  4, -64(1)		\n"
+	    "1:addi  30, 30, -8		\n");
+}
+
+/* Swap TOP and stack[sp-1]  */
+
+static void
+ppc64_emit_swap (void)
+{
+  EMIT_ASM ("ld   4, 8(30)	\n"
+	    "std  3, 8(30)	\n"
+	    "mr   3, 4		\n");
+}
+
+/* Discard N elements in the stack.  */
+
+static void
+ppc64_emit_stack_adjust (int n)
+{
+  uint32_t buf[6];
+  uint32_t *p = buf;
+
+  n = n << 3;
+  if ((n >> 15) != 0)
+    {
+      emit_error = 1;
+      return;
+    }
+
+  p += GEN_ADDI (p, 30, 30, n);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= sizeof (buf));
+}
+
+/* Call function FN.  */
+
+static void
+ppc64_emit_call (CORE_ADDR fn)
+{
+  uint32_t buf[8];
+  uint32_t *p = buf;
+
+  p += gen_call (p, fn);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= sizeof (buf));
+}
+
+/* FN's prototype is `LONGEST(*fn)(int)'.
+   TOP = fn (arg1)
+  */
+
+static void
+ppc64_emit_int_call_1 (CORE_ADDR fn, int arg1)
+{
+  uint32_t buf[8];
+  uint32_t *p = buf;
+
+  /* Setup argument.  arg1 is a 16-bit value.  */
+  p += gen_limm (p, 3, arg1);
+  p += gen_call (p, fn);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= sizeof (buf));
+}
+
+/* FN's prototype is `void(*fn)(int,LONGEST)'.
+   fn (arg1, TOP)
+
+   TOP should be preserved/restored before/after the call.  */
+
+static void
+ppc64_emit_void_call_2 (CORE_ADDR fn, int arg1)
+{
+  uint32_t buf[12];
+  uint32_t *p = buf;
+
+  /* Save TOP.  0(30) is next-empty.  */
+  p += GEN_STORE (p, 3, 30, 0);
+
+  /* Setup argument.  arg1 is a 16-bit value.  */
+  p += GEN_MR (p, 4, 3);		/* mr	r4, r3 */
+  p += gen_limm (p, 3, arg1);
+  p += gen_call (p, fn);
+
+  /* Restore TOP */
+  p += GEN_LOAD (p, 3, 30, 0);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= sizeof (buf));
+}
+
+/* Note in the following goto ops:
+
+   When emitting goto, the target address is later relocated by
+   write_goto_address.  OFFSET_P is the offset of the branch instruction
+   in the code sequence, and SIZE_P is how to relocate the instruction,
+   recognized by ppc_write_goto_address.  In current implementation,
+   SIZE can be either 24 or 14 for branch of conditional-branch instruction.
+ */
+
+/* If TOP is true, goto somewhere.  Otherwise, just fall-through.  */
+
+static void
+ppc64_emit_if_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("cmpdi  7, 3, 0	\n"
+	    "ldu    3, 8(30)	\n"
+	    "1:bne  7, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 12;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Unconditional goto.  */
+
+static void
+ppc64_emit_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("1:b	1b");
+
+  if (offset_p)
+    *offset_p = 0;
+  if (size_p)
+    *size_p = 24;
+}
+
+/* Goto if stack[--sp] == TOP  */
+
+static void
+ppc64_emit_eq_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("ldu     4, 8(30)	\n"
+	    "cmpd    7, 4, 3	\n"
+	    "ldu     3, 8(30)	\n"
+	    "1:beq   7, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 12;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Goto if stack[--sp] != TOP  */
+
+static void
+ppc64_emit_ne_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("ldu     4, 8(30)	\n"
+	    "cmpd    7, 4, 3	\n"
+	    "ldu     3, 8(30)	\n"
+	    "1:bne   7, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 12;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Goto if stack[--sp] < TOP  */
+
+static void
+ppc64_emit_lt_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("ldu     4, 8(30)	\n"
+	    "cmpd    7, 4, 3	\n"
+	    "ldu     3, 8(30)	\n"
+	    "1:blt   7, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 12;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Goto if stack[--sp] <= TOP  */
+
+static void
+ppc64_emit_le_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("ldu     4, 8(30)	\n"
+	    "cmpd    7, 4, 3	\n"
+	    "ldu     3, 8(30)	\n"
+	    "1:ble   7, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 12;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Goto if stack[--sp] > TOP  */
+
+static void
+ppc64_emit_gt_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("ldu     4, 8(30)	\n"
+	    "cmpd    7, 4, 3	\n"
+	    "ldu     3, 8(30)	\n"
+	    "1:bgt   7, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 12;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Goto if stack[--sp] >= TOP  */
+
+static void
+ppc64_emit_ge_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("ldu     4, 8(30)	\n"
+	    "cmpd    7, 4, 3	\n"
+	    "ldu     3, 8(30)	\n"
+	    "1:bge   7, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 12;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Relocate previous emitted branch instruction.  FROM is the address
+   of the branch instruction, TO is the goto target address, and SIZE
+   if the value we set by *SIZE_P before.  Currently, it is either
+   24 or 14 of branch and conditional-branch instruction.  */
+
+static void
+ppc_write_goto_address (CORE_ADDR from, CORE_ADDR to, int size)
+{
+  int rel = to - from;
+  uint32_t insn;
+  int opcd;
+
+  read_inferior_memory (from, (unsigned char *) &insn, 4);
+  opcd = (insn >> 26) & 0x3f;
+
+  switch (size)
+    {
+    case 14:
+      if (opcd != 16
+	  || (rel >= (1 << 15) || rel < -(1 << 15)))
+	emit_error = 1;
+      insn = (insn & ~0xfffc) | (rel & 0xfffc);
+      break;
+    case 24:
+      if (opcd != 18
+	  || (rel >= (1 << 25) || rel < -(1 << 25)))
+	emit_error = 1;
+      insn = (insn & ~0x3fffffc) | (rel & 0x3fffffc);
+      break;
+    default:
+      emit_error = 1;
+    }
+
+  if (!emit_error)
+    write_inferior_memory (from, (unsigned char *) &insn, 4);
+}
+
+/* Vector of emit ops for PowerPC64.  */
+
+static struct emit_ops ppc64_emit_ops_vector =
+{
+  ppc64_emit_prologue,
+  ppc64_emit_epilogue,
+  ppc64_emit_add,
+  ppc64_emit_sub,
+  ppc64_emit_mul,
+  ppc64_emit_lsh,
+  ppc64_emit_rsh_signed,
+  ppc64_emit_rsh_unsigned,
+  ppc64_emit_ext,
+  ppc64_emit_log_not,
+  ppc64_emit_bit_and,
+  ppc64_emit_bit_or,
+  ppc64_emit_bit_xor,
+  ppc64_emit_bit_not,
+  ppc64_emit_equal,
+  ppc64_emit_less_signed,
+  ppc64_emit_less_unsigned,
+  ppc64_emit_ref,
+  ppc64_emit_if_goto,
+  ppc64_emit_goto,
+  ppc_write_goto_address,
+  ppc64_emit_const,
+  ppc64_emit_call,
+  ppc64_emit_reg,
+  ppc64_emit_pop,
+  ppc64_emit_stack_flush,
+  ppc64_emit_zero_ext,
+  ppc64_emit_swap,
+  ppc64_emit_stack_adjust,
+  ppc64_emit_int_call_1,
+  ppc64_emit_void_call_2,
+  ppc64_emit_eq_goto,
+  ppc64_emit_ne_goto,
+  ppc64_emit_lt_goto,
+  ppc64_emit_le_goto,
+  ppc64_emit_gt_goto,
+  ppc64_emit_ge_goto
+};
+
+/*  Implementation of emit_ops target ops.   */
+
+__attribute__ ((unused))
+static struct emit_ops *
+ppc_emit_ops (void)
+{
+  return &ppc64_emit_ops_vector;
+}
+#endif
+
+/* Returns true for supporting range-stepping.  */
+
+static int
+ppc_supports_range_stepping (void)
+{
+  return 1;
+}
+
 /* Provide only a fill function for the general register set.  ps_lgetregs
    will use this for NPTL support.  */
 
@@ -750,16 +2154,32 @@ struct linux_target_ops the_low_target = {
   ppc_set_pc,
   (const unsigned char *) &ppc_breakpoint,
   ppc_breakpoint_len,
-  NULL,
-  0,
+  NULL, /* breakpoint_reinsert_addr */
+  0, /* decr_pc_after_break */
   ppc_breakpoint_at,
   ppc_supports_z_point_type,
   ppc_insert_point,
   ppc_remove_point,
-  NULL,
-  NULL,
+  NULL, /* stopped_by_watchpoint */
+  NULL, /* stopped_data_address */
   ppc_collect_ptrace_register,
   ppc_supply_ptrace_register,
+  NULL, /* siginfo_fixup */
+  NULL, /* linux_new_process */
+  NULL, /* linux_new_thread */
+  NULL, /* linux_new_fork */
+  NULL, /* linux_prepare_to_resume */
+  NULL, /* linux_process_qsupported */
+  ppc_supports_tracepoints,
+  ppc_get_thread_area,
+  ppc_install_fast_tracepoint_jump_pad,
+#ifdef __powerpc64__
+  ppc_emit_ops,
+#else
+  NULL, /* Use interpreter for ppc32.  */
+#endif
+  ppc_get_min_fast_tracepoint_insn_len,
+  ppc_supports_range_stepping,
 };
 
 void
diff --git a/gdb/rs6000-tdep.c b/gdb/rs6000-tdep.c
index d947879..50370ba 100644
--- a/gdb/rs6000-tdep.c
+++ b/gdb/rs6000-tdep.c
@@ -83,6 +83,9 @@
 #include "features/rs6000/powerpc-e500.c"
 #include "features/rs6000/rs6000.c"
 
+#include "ax.h"
+#include "ax-gdb.h"
+
 /* Determine if regnum is an SPE pseudo-register.  */
 #define IS_SPE_PSEUDOREG(tdep, regnum) ((tdep)->ppc_ev0_regnum >= 0 \
     && (regnum) >= (tdep)->ppc_ev0_regnum \
@@ -966,6 +969,53 @@ rs6000_breakpoint_from_pc (struct gdbarch *gdbarch, CORE_ADDR *bp_addr,
     return little_breakpoint;
 }
 
+/* Return true if ADDR is a valid address for tracepoint.  Set *ISZIE
+   to the number of bytes the target should copy elsewhere for the
+   tracepoint.  */
+
+static int
+ppc_fast_tracepoint_valid_at (struct gdbarch *gdbarch,
+			      CORE_ADDR addr, int *isize, char **msg)
+{
+  CORE_ADDR base, pagesz;
+  const int SCRATCH_BUFFER_NPAGES = 20;
+  int isValid = 1;
+
+  if (isize)
+    *isize = gdbarch_max_insn_length (gdbarch);
+
+  /* If we can figure out where is the jump-pad, check whether
+     the address for tracepoint is too far away.  Otherwise,
+     assume it is valid.  */
+  if (target_auxv_search (&current_target, AT_PHDR, &base) > 0
+      && target_auxv_search (&current_target, AT_PAGESZ, &pagesz) > 0)
+    {
+      /* The jump-pad is supposed to be mapped here.
+	 See gdbserver/linux-ppc-ipa.c and gdbserver/tracepoint.c.  */
+      long dist;
+      CORE_ADDR jpad_base
+	= (base & ~(pagesz - 1)) - SCRATCH_BUFFER_NPAGES * pagesz;
+
+      dist = jpad_base - addr;
+      if (dist >= (1 << 25) || dist < -(1 << 25))
+	isValid = 0;
+    }
+
+  if (isValid)
+    {
+      if (msg)
+	*msg = NULL;
+    }
+  else
+    {
+      if (msg)
+	*msg = xstrdup (_("The address is too far for "
+			  "inserting fast tracepoint."));
+    }
+
+  return isValid;
+}
+
 /* Instruction masks for displaced stepping.  */
 #define BRANCH_MASK 0xfc000000
 #define BP_MASK 0xFC0007FE
@@ -3709,6 +3759,8 @@ bfd_uses_spe_extensions (bfd *abfd)
 #define PPC_LK(insn)	PPC_BIT (insn, 31)
 #define PPC_TX(insn)	PPC_BIT (insn, 31)
 #define PPC_LEV(insn)	PPC_FIELD (insn, 20, 7)
+#define PPC_LI(insn)	(PPC_SEXT (PPC_FIELD (insn, 6, 24), 24) << 2)
+#define PPC_BD(insn)	(PPC_SEXT (PPC_FIELD (insn, 16, 14), 14) << 2)
 
 #define PPC_XT(insn)	((PPC_TX (insn) << 5) | PPC_T (insn))
 #define PPC_XER_NB(xer)	(xer & 0x7f)
@@ -5362,6 +5414,68 @@ UNKNOWN_OP:
   return 0;
 }
 
+/* Implement gdbarch_gen_return_address.  Generate a bytecode expression
+   to get the value of the saved PC.  SCOPE is the address we want to
+   get return address for.  SCOPE maybe in the middle of a function.  */
+
+static void
+ppc_gen_return_address (struct gdbarch *gdbarch,
+			struct agent_expr *ax, struct axs_value *value,
+			CORE_ADDR scope)
+{
+  struct rs6000_framedata frame;
+  CORE_ADDR func_addr;
+
+  /* Try to find the start of the function and analyze the prologue.  */
+  if (find_pc_partial_function (scope, NULL, &func_addr, NULL))
+    {
+      skip_prologue (gdbarch, func_addr, scope, &frame);
+
+      if (frame.lr_offset == 0)
+	{
+	  value->type = register_type (gdbarch, PPC_LR_REGNUM);
+	  value->kind = axs_lvalue_register;
+	  value->u.reg = PPC_LR_REGNUM;
+	  return;
+	}
+    }
+  else
+    {
+      /* If we don't know where the function starts, we cannot analyze it.
+	 Assuming it's not a leaf function, not frameless, and LR is
+	 saved at back-chain +16 (or +4 for 32-bit ABI).  */
+
+      frame.frameless = 0;
+#ifdef __powerpc64__
+      frame.lr_offset = 16;
+#else
+      frame.lr_offset = 4;
+#endif
+    }
+
+  /* if (frameless)
+       load 16(SP)
+     else
+       BC = 0(SP)
+       load 16(BC) */
+
+  ax_reg (ax, gdbarch_sp_regnum (gdbarch));
+
+  /* Load back-chain.  */
+  if (!frame.frameless)
+    {
+      if (register_size (gdbarch, PPC_LR_REGNUM) == 8)
+	ax_simple (ax, aop_ref64);
+      else
+	ax_simple (ax, aop_ref32);
+    }
+
+  ax_const_l (ax, frame.lr_offset);
+  ax_simple (ax, aop_add);
+  value->type = register_type (gdbarch, PPC_LR_REGNUM);
+  value->kind = axs_lvalue_memory;
+}
+
 /* Initialize the current architecture based on INFO.  If possible, re-use an
    architecture from ARCHES, which is a list of architectures already created
    during this debugging session.
@@ -5922,6 +6036,7 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
 
   set_gdbarch_inner_than (gdbarch, core_addr_lessthan);
   set_gdbarch_breakpoint_from_pc (gdbarch, rs6000_breakpoint_from_pc);
+  set_gdbarch_fast_tracepoint_valid_at (gdbarch, ppc_fast_tracepoint_valid_at);
 
   /* The value of symbols of type N_SO and N_FUN maybe null when
      it shouldn't be.  */
@@ -5959,6 +6074,8 @@ rs6000_gdbarch_init (struct gdbarch_info info, struct gdbarch_list *arches)
   set_gdbarch_displaced_step_location (gdbarch,
 				       displaced_step_at_entry_point);
 
+  set_gdbarch_gen_return_address (gdbarch, ppc_gen_return_address);
+
   set_gdbarch_max_insn_length (gdbarch, PPC_INSN_SIZE);
 
   /* Hook in ABI-specific overrides, if they have been registered.  */
diff --git a/gdb/testsuite/gdb.trace/actions.c b/gdb/testsuite/gdb.trace/actions.c
index 4b7b887..f4ec871 100644
--- a/gdb/testsuite/gdb.trace/actions.c
+++ b/gdb/testsuite/gdb.trace/actions.c
@@ -46,6 +46,11 @@ static union GDB_UNION_TEST
 } gdb_union1_test;
 
 void gdb_recursion_test (int, int, int, int,  int,  int,  int);
+/* This function pointer is used to force the function called via
+   global entry instead of local entry; otherwise, breakpoints set
+   at the global entry (i.e., '*foo') will not be hit.  */
+typedef void (*gdb_recursion_test_fp) (int, int, int, int,  int,  int,  int);
+gdb_recursion_test_fp gdb_recursion_test_ptr = gdb_recursion_test;
 
 void gdb_recursion_test (int depth, 
 			 int q1, 
@@ -64,7 +69,7 @@ void gdb_recursion_test (int depth,
   q5 = q6;						/* gdbtestline 6 */
   q6 = q;						/* gdbtestline 7 */
   if (depth--)						/* gdbtestline 8 */
-    gdb_recursion_test (depth, q1, q2, q3, q4, q5, q6);	/* gdbtestline 9 */
+    gdb_recursion_test_ptr (depth, q1, q2, q3, q4, q5, q6);	/* gdbtestline 9 */
 }
 
 
@@ -103,7 +108,7 @@ unsigned long   gdb_c_test( unsigned long *parm )
    gdb_structp_test      = &gdb_struct1_test;
    gdb_structpp_test     = &gdb_structp_test;
 
-   gdb_recursion_test (3, (long) parm[1], (long) parm[2], (long) parm[3],
+   gdb_recursion_test_ptr (3, (long) parm[1], (long) parm[2], (long) parm[3],
 		       (long) parm[4], (long) parm[5], (long) parm[6]);
 
    gdb_char_test = gdb_short_test = gdb_long_test = 0;
diff --git a/gdb/testsuite/gdb.trace/backtrace.exp b/gdb/testsuite/gdb.trace/backtrace.exp
index 045778e..3094074 100644
--- a/gdb/testsuite/gdb.trace/backtrace.exp
+++ b/gdb/testsuite/gdb.trace/backtrace.exp
@@ -146,6 +146,9 @@ if [is_amd64_regs_target] {
 } elseif [is_x86_like_target] {
     set fpreg "\$ebp"
     set spreg "\$esp"
+} elseif [istarget "powerpc*-*-*"] {
+    set fpreg "\$r31"
+    set spreg "\$r1"
 } else {
     set fpreg "\$fp"
     set spreg "\$sp"
diff --git a/gdb/testsuite/gdb.trace/change-loc.h b/gdb/testsuite/gdb.trace/change-loc.h
index e8e2e86..070a137 100644
--- a/gdb/testsuite/gdb.trace/change-loc.h
+++ b/gdb/testsuite/gdb.trace/change-loc.h
@@ -36,6 +36,8 @@ func4 (void)
        SYMBOL(set_tracepoint) ":\n"
 #if (defined __x86_64__ || defined __i386__)
        "    call " SYMBOL(func5) "\n"
+#elif (defined __powerpc64__ || defined __powerpc__)
+       "    nop\n"
 #endif
        );
 
diff --git a/gdb/testsuite/gdb.trace/collection.exp b/gdb/testsuite/gdb.trace/collection.exp
index bd42cfa..ed562c9 100644
--- a/gdb/testsuite/gdb.trace/collection.exp
+++ b/gdb/testsuite/gdb.trace/collection.exp
@@ -44,6 +44,10 @@ if [is_amd64_regs_target] {
     set fpreg "ebp"
     set spreg "esp"
     set pcreg "eip"
+} elseif [istarget "powerpc*-*-*"] {
+    set fpreg "r31"
+    set spreg "r1"
+    set pcreg "pc"
 } else {
     set fpreg "fp"
     set spreg "sp"
diff --git a/gdb/testsuite/gdb.trace/entry-values.exp b/gdb/testsuite/gdb.trace/entry-values.exp
index 0cf5615..7295a1f 100644
--- a/gdb/testsuite/gdb.trace/entry-values.exp
+++ b/gdb/testsuite/gdb.trace/entry-values.exp
@@ -42,7 +42,7 @@ if { [istarget "arm*-*-*"] || [istarget "aarch64*-*-*"] } {
 } elseif { [istarget "s390*-*-*"] } {
     set call_insn "brasl"
 } elseif { [istarget "powerpc*-*-*"] } {
-    set call_insn "bl"
+    set call_insn {bl\y}
 } elseif { [istarget "mips*-*-*"] } {
     # Skip the delay slot after the instruction used to make a call
     # (which can be a jump or a branch) if it has one.
@@ -218,6 +218,8 @@ if [is_amd64_regs_target] {
     set spreg "\$rsp"
 } elseif [is_x86_like_target] {
     set spreg "\$esp"
+} elseif [istarget "powerpc*-*-*"] {
+    set spreg "\$r1"
 } else {
     set spreg "\$sp"
 }
diff --git a/gdb/testsuite/gdb.trace/ftrace.c b/gdb/testsuite/gdb.trace/ftrace.c
index f522e6f..dc727d2 100644
--- a/gdb/testsuite/gdb.trace/ftrace.c
+++ b/gdb/testsuite/gdb.trace/ftrace.c
@@ -42,6 +42,8 @@ marker (int anarg)
        SYMBOL(set_point) ":\n"
 #if (defined __x86_64__ || defined __i386__)
        "    call " SYMBOL(func) "\n"
+#elif (defined __powerpc64__ || defined __powerpc__)
+       "    nop\n"
 #endif
        );
 
@@ -53,6 +55,8 @@ marker (int anarg)
        SYMBOL(four_byter) ":\n"
 #if (defined __i386__)
        "    cmpl $0x1,0x8(%ebp) \n"
+#elif (defined __powerpc64__ || defined __powerpc__)
+       "    nop\n"
 #endif
        );
 }
diff --git a/gdb/testsuite/gdb.trace/ftrace.exp b/gdb/testsuite/gdb.trace/ftrace.exp
index a8eb515..328c1d1 100644
--- a/gdb/testsuite/gdb.trace/ftrace.exp
+++ b/gdb/testsuite/gdb.trace/ftrace.exp
@@ -84,7 +84,8 @@ proc test_fast_tracepoints {} {
 
     gdb_test "print gdb_agent_gdb_trampoline_buffer_error" ".*" ""
 
-    if { [istarget "x86_64-*-*"] || [istarget "i\[34567\]86-*-*"] } {
+    if { [istarget "x86_64-*-*"] || [istarget "i\[34567\]86-*-*"] \
+	 || [istarget "powerpc*-*-*"] } {
 
 	gdb_test "ftrace set_point" "Fast tracepoint .*" \
 	    "fast tracepoint at a long insn"
@@ -243,6 +244,10 @@ if [is_amd64_regs_target] {
     set arg0exp "\$rdi"
 } elseif [is_x86_like_target] {
     set arg0exp "*(int *) (\$ebp + 8)"
+} elseif [istarget "powerpc*-*-*"] {
+    set arg0exp "\$r3"
+} elseif [istarget "aarch64*"] {
+    set arg0exp "\$x0"
 } else {
     set arg0exp ""
 }
diff --git a/gdb/testsuite/gdb.trace/mi-trace-frame-collected.exp b/gdb/testsuite/gdb.trace/mi-trace-frame-collected.exp
index 51ed479..1df4d65 100644
--- a/gdb/testsuite/gdb.trace/mi-trace-frame-collected.exp
+++ b/gdb/testsuite/gdb.trace/mi-trace-frame-collected.exp
@@ -56,6 +56,8 @@ if [is_amd64_regs_target] {
     set pcreg "rip"
 } elseif [is_x86_like_target] {
     set pcreg "eip"
+} elseif [istarget "powerpc*-*-*"] {
+    set pcreg "pc"
 } else {
     # Other ports that support tracepoints should set the name of pc
     # register here.
diff --git a/gdb/testsuite/gdb.trace/mi-trace-unavailable.exp b/gdb/testsuite/gdb.trace/mi-trace-unavailable.exp
index 6b97d9d..1e6e541 100644
--- a/gdb/testsuite/gdb.trace/mi-trace-unavailable.exp
+++ b/gdb/testsuite/gdb.trace/mi-trace-unavailable.exp
@@ -135,6 +135,8 @@ proc test_trace_unavailable { data_source } {
 	    set pcnum 16
 	} elseif [is_x86_like_target] {
 	    set pcnum 8
+	} elseif [istarget "powerpc*-*-*"] {
+	    set pcnum 64
 	} else {
 	    # Other ports support tracepoint should define the number
 	    # of its own pc register.
diff --git a/gdb/testsuite/gdb.trace/pending.exp b/gdb/testsuite/gdb.trace/pending.exp
index 0399807..ed36cac 100644
--- a/gdb/testsuite/gdb.trace/pending.exp
+++ b/gdb/testsuite/gdb.trace/pending.exp
@@ -441,6 +441,8 @@ proc pending_tracepoint_with_action_resolved { trace_type } \
 	set pcreg "rip"
     } elseif [is_x86_like_target] {
 	set pcreg "eip"
+    } elseif [istarget "powerpc*-*-*"] {
+	set pcreg "pc"
     }
 
     gdb_trace_setactions "set action for pending tracepoint" "" \
diff --git a/gdb/testsuite/gdb.trace/pendshr1.c b/gdb/testsuite/gdb.trace/pendshr1.c
index d3b5463..5ab3fbe 100644
--- a/gdb/testsuite/gdb.trace/pendshr1.c
+++ b/gdb/testsuite/gdb.trace/pendshr1.c
@@ -38,6 +38,8 @@ pendfunc (int x)
        SYMBOL(set_point1) ":\n"
 #if (defined __x86_64__ || defined __i386__)
        "    call " SYMBOL(pendfunc1) "\n"
+#elif (defined __powerpc64__ || defined __powerpc__)
+       "    nop\n"
 #endif
        );
 }
diff --git a/gdb/testsuite/gdb.trace/pendshr2.c b/gdb/testsuite/gdb.trace/pendshr2.c
index b8a51a5..8b21e75 100644
--- a/gdb/testsuite/gdb.trace/pendshr2.c
+++ b/gdb/testsuite/gdb.trace/pendshr2.c
@@ -35,6 +35,8 @@ pendfunc2 (int x)
        SYMBOL(set_point2) ":\n"
 #if (defined __x86_64__ || defined __i386__)
        "    call " SYMBOL(foo) "\n"
+#elif (defined __powerpc64__ || defined __powerpc__)
+       "    nop\n"
 #endif
        );
 }
diff --git a/gdb/testsuite/gdb.trace/range-stepping.c b/gdb/testsuite/gdb.trace/range-stepping.c
index 113f0e2..f87464c 100644
--- a/gdb/testsuite/gdb.trace/range-stepping.c
+++ b/gdb/testsuite/gdb.trace/range-stepping.c
@@ -26,6 +26,8 @@
    tracepoint jump.  */
 #if (defined __x86_64__ || defined __i386__)
 #  define NOP "   .byte 0xe9,0x00,0x00,0x00,0x00\n" /* jmp $+5 (5-byte nop) */
+#elif (defined __powerpc64__ || defined __powerpc__)
+#  define NOP "    nop\n"
 #else
 #  define NOP "" /* port me */
 #endif
diff --git a/gdb/testsuite/gdb.trace/report.exp b/gdb/testsuite/gdb.trace/report.exp
index 2fa676b..e0160f7 100644
--- a/gdb/testsuite/gdb.trace/report.exp
+++ b/gdb/testsuite/gdb.trace/report.exp
@@ -158,6 +158,10 @@ if [is_amd64_regs_target] {
     set fpreg "ebp"
     set spreg "esp"
     set pcreg "eip"
+} elseif [istarget "powerpc*-*-*"] {
+    set fpreg "r31"
+    set spreg "r1"
+    set pcreg "pc"
 } else {
     set fpreg "fp"
     set spreg "sp"
diff --git a/gdb/testsuite/gdb.trace/trace-break.c b/gdb/testsuite/gdb.trace/trace-break.c
index f381ec6..43174cc 100644
--- a/gdb/testsuite/gdb.trace/trace-break.c
+++ b/gdb/testsuite/gdb.trace/trace-break.c
@@ -41,6 +41,8 @@ marker (void)
        SYMBOL(set_point) ":\n"
 #if (defined __x86_64__ || defined __i386__)
        "    call " SYMBOL(func) "\n"
+#elif (defined __powerpc64__ || defined __powerpc__)
+       "    nop\n"
 #endif
        );
 
@@ -48,6 +50,8 @@ marker (void)
        SYMBOL(after_set_point) ":\n"
 #if (defined __x86_64__ || defined __i386__)
        "    call " SYMBOL(func) "\n"
+#elif (defined __powerpc64__ || defined __powerpc__)
+       "    nop\n"
 #endif
        );
 }
diff --git a/gdb/testsuite/gdb.trace/trace-break.exp b/gdb/testsuite/gdb.trace/trace-break.exp
index 4283ca6..9d6551a 100644
--- a/gdb/testsuite/gdb.trace/trace-break.exp
+++ b/gdb/testsuite/gdb.trace/trace-break.exp
@@ -49,6 +49,10 @@ if [is_amd64_regs_target] {
     set fpreg "ebp"
     set spreg "esp"
     set pcreg "eip"
+} elseif [istarget "powerpc*-*-*"] {
+    set fpreg "r31"
+    set spreg "r1"
+    set pcreg "pc"
 }
 
 # Set breakpoint and tracepoint at the same address.
diff --git a/gdb/testsuite/gdb.trace/trace-mt.c b/gdb/testsuite/gdb.trace/trace-mt.c
index 38aeff5..0441a89 100644
--- a/gdb/testsuite/gdb.trace/trace-mt.c
+++ b/gdb/testsuite/gdb.trace/trace-mt.c
@@ -37,6 +37,8 @@ thread_function(void *arg)
        SYMBOL(set_point1) ":\n"
 #if (defined __x86_64__ || defined __i386__)
        "    call " SYMBOL(func) "\n"
+#elif (defined __powerpc64__ || defined __powerpc__)
+       "    nop\n"
 #endif
        );
 }
diff --git a/gdb/testsuite/gdb.trace/unavailable.exp b/gdb/testsuite/gdb.trace/unavailable.exp
index 5be9704..ad62e75 100644
--- a/gdb/testsuite/gdb.trace/unavailable.exp
+++ b/gdb/testsuite/gdb.trace/unavailable.exp
@@ -34,6 +34,10 @@ if [is_amd64_regs_target] {
     set fpreg "ebp"
     set spreg "esp"
     set pcreg "eip"
+} elseif [istarget "powerpc*-*-*"] {
+    set fpreg "r31"
+    set spreg "r1"
+    set pcreg "pc"
 } else {
     set fpreg "fp"
     set spreg "sp"
diff --git a/gdb/testsuite/gdb.trace/while-dyn.exp b/gdb/testsuite/gdb.trace/while-dyn.exp
index 198421e..ef92b2d 100644
--- a/gdb/testsuite/gdb.trace/while-dyn.exp
+++ b/gdb/testsuite/gdb.trace/while-dyn.exp
@@ -47,6 +47,8 @@ if [is_amd64_regs_target] {
     set fpreg "\$rbp"
 } elseif [is_x86_like_target] {
     set fpreg "\$ebp"
+} elseif [istarget "powerpc*-*-*"] {
+    set fpreg "\$r31"
 } else {
     set fpreg "\$fp"
 }
-- 
1.9.1


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]