This is the mail archive of the
gdb-patches@sourceware.org
mailing list for the GDB project.
[PATCH 4/5 v4] Tracepoint for ppc64.
- From: Wei-cheng Wang <cole945 at gmail dot com>
- To: uweigand at de dot ibm dot com, gdb-patches at sourceware dot org
- Cc: Wei-cheng Wang <cole945 at gmail dot com>
- Date: Sun, 28 Jun 2015 00:21:41 +0800
- Subject: [PATCH 4/5 v4] Tracepoint for ppc64.
- Authentication-results: sourceware.org; auth=none
- References: <1435422102-39438-1-git-send-email-cole945 at gmail dot com>
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 (¤t_target, AT_PHDR, &base) > 0
+ && target_auxv_search (¤t_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