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 v4] Tracepoint for ppc64.


Hi,

The main patch for tracepoint for ppc64 and snippets for
enabling tracepoint tests.

Ulrich Weigand wrote:
> I think if there is no benefit in having this code on the GDB side,
> it would be better to move it to gdbsever.  (Potential benefits could
> be: we need information that isn't available in gdbserver, like symbol
> data; or the code can be shared with other users if in GDB.  But on
> PowerPC, I think none of this applies.)

relocate_instruction is removed from rs6000-tdep.c and move to gdbserver side.

Ulrich Weigand wrote:
> Wei-cheng Wang wrote:
> > Ulrich Weigand wrote:
> > >Wei-cheng Wang wrote:
> > >> +static int
> > >> +ppc_fast_tracepoint_valid_at (struct gdbarch *gdbarch,
> > >> +                        CORE_ADDR addr, int *isize, char **msg)
> > >> +{
> > >> +  if (isize)
> > >> +    *isize = gdbarch_max_insn_length (gdbarch);
> > >> +  if (msg)
> > >> +    *msg = NULL;
> > >> +  return 1;
> > >> +}
> > >
> > > Should/can we check here where the jump to the jump pad will be in
> > > range?  Might be better to detect this early ...
> >
> >Client has no idea about where the jump pad will be installed.
> >If it's out of range, gdbserver will report it right after user
> >entered 'tstart' command
> Well, but we know the logic the stub uses.  For example, we know that
> we certainly cannot install a fast tracepoint in any shared library code,
> since the jump pad will definitely be too far away.  We can check for
> this condition here.  (We could also check for tracepoints in executables
> that have a text section larger than 32 MB ...)

Now in this path, ppc_fast_tracepoint_valid_at will check the distance
and return 0 (invalid) if ADDR is too far from jumppad.

However, if a tracepoint was pending and later found it's not valid,
it will cause an internal-error.  See remote.c

  if (gdbarch_fast_tracepoint_valid_at (target_gdbarch (),
					tpaddr, &isize, NULL))
    xsnprintf (buf + strlen (buf), BUF_SIZE - strlen (buf), ":F%x",
	       isize);
  else
    /* If it passed validation at definition but fails now,
       ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
       something is very wrong.  */
    internal_error (__FILE__, __LINE__, _("Fast tracepoint not "
					  "valid during download"));

If the tracepoint is pending at definition, it won't be checked at all.

  /* Fast tracepoints may have additional restrictions on location.  */
  if (!pending && type_wanted == bp_fast_tracepoint)
      ^^^^^^^^
    {
      for (ix = 0; VEC_iterate (linespec_sals, canonical.sals, ix, iter); ++ix)
	check_fast_tracepoint_sals (gdbarch, &iter->sals);
    }

Maybe we use "error" instead of "internal_error"?


BTW, in this patch, unlock is implemented by simply writing 0 instead
of a full atomic-swap.  It that ok?

  /* 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_atomic_xchg (p, lockaddr, 0, 5);

  /* 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);

Thanks,
Wei-cheng

---

gdb/ChangeLog

2015-06-27  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-06-27  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-06-27  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                      | 1408 +++++++++++++++++++-
 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, 1712 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..73d8899
--- /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"
+
+#if defined __PPC64__
+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)
+{
+#if defined __PPC64__
+  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..064f508 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,1377 @@ 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_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 __PPC64__
+#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] */
+      p += GEN_LIS (p, reg, (imm >> 16) & 0xffff);
+      p += GEN_ORI (p, reg, reg, imm & 0xffff);
+    }
+  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: lwsync
+  2: lwarx   TMP, 0, LOCK
+     cmpwi   TMP, OLD
+     bne     1b
+     stwcx.  NEW, 0, LOCK
+     bne     2b */
+
+  p += gen_limm (p, r_lock, lock);
+  p += gen_limm (p, r_old, old_value);
+
+  p += GEN_LWSYNC (p);
+  p += GEN_LWARX (p, r_tmp, 0, r_lock);
+  p += GEN_CMPW (p, r_tmp, r_old);
+  p += GEN_BNE (p, -12);
+  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 (__PPC64__) && _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;
+
+#if __PPC64__
+  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
+	{
+	  uint32_t bdnz_insn = (16 << 26) | (0x10 << 21) | 12;
+	  uint32_t bf_insn = (16 << 26) | (0x4 << 21) | 8;
+
+	  newrel -= 12;
+
+	  /* 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;
+	}
+    }
+
+  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;
+#if __PPC64__
+  /* 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_atomic_xchg (p, lockaddr, 0, 5);
+
+  /* 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;
+}
+
+#if __PPC64__
+
+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[4];
+  uint32_t *p = buf;
+
+  n = n << 3;
+  if ((n >> 7) != 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 +2134,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,
+#if __PPC64__
+  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..7924227 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;
+#if __PPC64__
+      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]