public inbox for gdb-patches@sourceware.org
 help / color / mirror / Atom feed
* [PATCH 0/3] gdbserver: Add powerpc fast tracepoint support.
@ 2016-03-13  2:31 Marcin Kościelnicki
  2016-03-13  2:32 ` [PATCH 3/3] " Marcin Kościelnicki
                   ` (3 more replies)
  0 siblings, 4 replies; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-13  2:31 UTC (permalink / raw)
  To: gdb-patches

This patchset enables fast tracepoints on linux powerpc, powerpc64,
powerpc64le.  Agent expression emitter is not included and will follow
in a subsequent patch.

Patches #1 and #2 have no dependencies, patch #3 depends on #1 (for
powerpc64 ELFv1), #2 (for all variants), and
https://sourceware.org/ml/gdb-patches/2016-03/msg00201.html (for powerpc64
ELFv1).

Tested on powerpc, powerpc64, powerpc64le - all ftrace tests pass.
Also tested on i386, x86_64.

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

* [PATCH 2/3] IPA: Add alloc_jump_pad_buffer target hook.
  2016-03-13  2:31 [PATCH 0/3] gdbserver: Add powerpc fast tracepoint support Marcin Kościelnicki
  2016-03-13  2:32 ` [PATCH 3/3] " Marcin Kościelnicki
@ 2016-03-13  2:32 ` Marcin Kościelnicki
  2016-03-18 15:08   ` [PATCH 2/4 v2] " Marcin Kościelnicki
  2016-03-13  2:32 ` [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers Marcin Kościelnicki
  2016-03-14 22:25 ` [PATCH 4/4] gdbserver: Add emit_ops for powerpc Marcin Kościelnicki
  3 siblings, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-13  2:32 UTC (permalink / raw)
  To: gdb-patches; +Cc: Marcin Kościelnicki

Targets may have various requirements on the required location of the jump
pad area.  Currently IPA allocates it at the lowest possible address,
so that it is reachable by branches from the executable.  However, this
fails on powerpc, which has executable link address (0x10000000) much
larger than branch reach (+/- 32MiB).

This makes jump pad buffer allocation a target hook instead.  The current
implementations are as follows:

- i386: Branches can reach anywhere, so just mmap it.  This avoids
  the linear search dance.
- x86_64: Branches have +/-2GiB of reach, and executable is loaded low,
  so just call mmap with MAP_32BIT.  Likewise avoids the linear search.
- aarch64: Branches have +-128MiB of reach, executable loaded at 4MiB.
  Do a linear search from 4MiB-size downwards to page_size.

gdb/gdbserver/ChangeLog:

	* linux-aarch64-ipa.c: Add <sys/mman.h> include.
	(alloc_jump_pad_buffer): New function.
	* linux-amd64-ipa.c: Add <sys/mman.h> include.
	(alloc_jump_pad_buffer): New function.
	* linux-i386-ipa.c (alloc_jump_pad_buffer): New function.
	* tracepoint.c (initialize_tracepoint): Delegate to
	alloc_jump_pad_buffer.
	* tracepoint.h (alloc_jump_pad_buffer): New prototype.
---
This has the same purpose as
https://sourceware.org/ml/gdb-patches/2015-06/msg00586.html , but
delegates more work to the target - this way we can use much simpler
code for x86, take size into account, select the direction of the
search, etc.

 gdb/gdbserver/ChangeLog           | 11 ++++++++++
 gdb/gdbserver/linux-aarch64-ipa.c | 43 +++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/linux-amd64-ipa.c   | 18 ++++++++++++++++
 gdb/gdbserver/linux-i386-ipa.c    | 15 ++++++++++++++
 gdb/gdbserver/tracepoint.c        | 25 ++++++-----------------
 gdb/gdbserver/tracepoint.h        |  1 +
 6 files changed, 94 insertions(+), 19 deletions(-)

diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 31120c5..4a4a9bf 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,14 @@
+2016-03-13  Marcin Kościelnicki  <koriakin@0x04.net>
+
+	* linux-aarch64-ipa.c: Add <sys/mman.h> include.
+	(alloc_jump_pad_buffer): New function.
+	* linux-amd64-ipa.c: Add <sys/mman.h> include.
+	(alloc_jump_pad_buffer): New function.
+	* linux-i386-ipa.c (alloc_jump_pad_buffer): New function.
+	* tracepoint.c (initialize_tracepoint): Delegate to
+	alloc_jump_pad_buffer.
+	* tracepoint.h (alloc_jump_pad_buffer): New prototype.
+
 2016-03-12  Marcin Kościelnicki  <koriakin@0x04.net>
 
 	* linux-aarch64-ipa.c: Rename gdb_agent_get_raw_reg to get_raw_reg.
diff --git a/gdb/gdbserver/linux-aarch64-ipa.c b/gdb/gdbserver/linux-aarch64-ipa.c
index 00cbf3e..b95751b 100644
--- a/gdb/gdbserver/linux-aarch64-ipa.c
+++ b/gdb/gdbserver/linux-aarch64-ipa.c
@@ -19,6 +19,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
+#include <sys/mman.h>
 #include "tracepoint.h"
 
 /* Defined in auto-generated file aarch64.c.  */
@@ -153,6 +154,48 @@ get_ipa_tdesc (int idx)
   return tdesc_aarch64;
 }
 
+/* Allocate buffer for the jump pads.  The branch instruction has a reach
+   of +/- 128MiB, and the executable is loaded at 0x400000 (4MiB).
+   To maximize the area of executable that can use tracepoints, try
+   allocating at 0x400000 - size initially, decreasing until we hit
+   a free area.  */
+
+void *
+alloc_jump_pad_buffer (size_t size)
+{
+  uintptr_t addr;
+  int pagesize;
+  void *res;
+
+  pagesize = sysconf (_SC_PAGE_SIZE);
+  if (pagesize == -1)
+    perror_with_name ("sysconf");
+
+  addr = 0x400000 - size;
+
+  /* size should already be page-aligned, but this can't hurt.  */
+  addr &= ~(pagesize - 1);
+
+  /* Search for a free area.  If we hit 0, we're out of luck.  */
+  for (; addr; addr -= pagesize)
+    {
+      /* No MAP_FIXED - we don't want to zap someone's mapping.  */
+      res = mmap ((void *) addr, size,
+		  PROT_READ | PROT_WRITE | PROT_EXEC,
+		  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+      /* If we got what we wanted, return.  */
+      if ((uintptr_t) res < 0x400000)
+	return res;
+
+      /* If we got a mapping, but at a wrong address, undo it.  */
+      if (res != MAP_FAILED)
+	munmap (res, size);
+    }
+
+  return NULL;
+}
+
 void
 initialize_low_tracepoint (void)
 {
diff --git a/gdb/gdbserver/linux-amd64-ipa.c b/gdb/gdbserver/linux-amd64-ipa.c
index 70889d2..9ee0fe8 100644
--- a/gdb/gdbserver/linux-amd64-ipa.c
+++ b/gdb/gdbserver/linux-amd64-ipa.c
@@ -19,6 +19,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
+#include <sys/mman.h>
 #include "tracepoint.h"
 #include "linux-x86-tdesc.h"
 
@@ -190,6 +191,23 @@ get_ipa_tdesc (int idx)
     }
 }
 
+/* Allocate buffer for the jump pads.  Since we're using 32-bit jumps
+   to reach them, and the executable is at low addresses, MAP_32BIT
+   works just fine.  Shared libraries, being allocated at the top,
+   are unfortunately out of luck.  */
+
+void *
+alloc_jump_pad_buffer (size_t size)
+{
+  void *res = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC,
+		    MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, 1, 0);
+
+  if (res == MAP_FAILED)
+    return NULL;
+
+  return res;
+}
+
 void
 initialize_low_tracepoint (void)
 {
diff --git a/gdb/gdbserver/linux-i386-ipa.c b/gdb/gdbserver/linux-i386-ipa.c
index 7159eee..52c0581 100644
--- a/gdb/gdbserver/linux-i386-ipa.c
+++ b/gdb/gdbserver/linux-i386-ipa.c
@@ -269,6 +269,21 @@ get_ipa_tdesc (int idx)
     }
 }
 
+/* Allocate buffer for the jump pads.  On i386, we can reach an arbitrary
+   address with a jump instruction, so just allocate normally.  */
+
+void *
+alloc_jump_pad_buffer (size_t size)
+{
+  void *res = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC,
+		    MAP_PRIVATE | MAP_ANONYMOUS, 1, 0);
+
+  if (res == MAP_FAILED)
+    return NULL;
+
+  return res;
+}
+
 void
 initialize_low_tracepoint (void)
 {
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index 061e161..0b6d327 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -7400,35 +7400,22 @@ initialize_tracepoint (void)
 
 #ifdef IN_PROCESS_AGENT
   {
-    uintptr_t addr;
     int pagesize;
+    size_t jump_pad_size;
 
     pagesize = sysconf (_SC_PAGE_SIZE);
     if (pagesize == -1)
       perror_with_name ("sysconf");
 
-    gdb_tp_heap_buffer = (char *) xmalloc (5 * 1024 * 1024);
-
 #define SCRATCH_BUFFER_NPAGES 20
 
-    /* Allocate scratch buffer aligned on a page boundary, at a low
-       address (close to the main executable's code).  */
-    for (addr = pagesize; addr != 0; addr += pagesize)
-      {
-	gdb_jump_pad_buffer
-	  = (char *) mmap ((void *) addr,
-			   pagesize * SCRATCH_BUFFER_NPAGES,
-			   PROT_READ | PROT_WRITE | PROT_EXEC,
-			   MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
-			   -1, 0);
-	if (gdb_jump_pad_buffer != MAP_FAILED)
-	  break;
-      }
+    jump_pad_size = pagesize * SCRATCH_BUFFER_NPAGES;
 
-    if (addr == 0)
+    gdb_tp_heap_buffer = (char *) xmalloc (5 * 1024 * 1024);
+    gdb_jump_pad_buffer = alloc_jump_pad_buffer (jump_pad_size);
+    if (gdb_jump_pad_buffer == NULL)
       perror_with_name ("mmap");
-
-    gdb_jump_pad_buffer_end = gdb_jump_pad_buffer + pagesize * SCRATCH_BUFFER_NPAGES;
+    gdb_jump_pad_buffer_end = gdb_jump_pad_buffer + jump_pad_size;
   }
 
   gdb_trampoline_buffer = gdb_trampoline_buffer_end = 0;
diff --git a/gdb/gdbserver/tracepoint.h b/gdb/gdbserver/tracepoint.h
index df815ef..0f4d498 100644
--- a/gdb/gdbserver/tracepoint.h
+++ b/gdb/gdbserver/tracepoint.h
@@ -132,6 +132,7 @@ void supply_static_tracepoint_registers (struct regcache *regcache,
 					 CORE_ADDR pc);
 void set_trampoline_buffer_space (CORE_ADDR begin, CORE_ADDR end,
 				  char *errmsg);
+void *alloc_jump_pad_buffer (size_t size);
 #else
 void stop_tracing (void);
 
-- 
2.7.2

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

* [PATCH 3/3] gdbserver: Add powerpc fast tracepoint support.
  2016-03-13  2:31 [PATCH 0/3] gdbserver: Add powerpc fast tracepoint support Marcin Kościelnicki
@ 2016-03-13  2:32 ` Marcin Kościelnicki
  2016-03-14 22:10   ` [PATCH 3/4 v2] " Marcin Kościelnicki
  2016-03-13  2:32 ` [PATCH 2/3] IPA: Add alloc_jump_pad_buffer target hook Marcin Kościelnicki
                   ` (2 subsequent siblings)
  3 siblings, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-13  2:32 UTC (permalink / raw)
  To: gdb-patches; +Cc: Marcin Kościelnicki

gdb/gdbserver/ChangeLog:

2016-03-13  Wei-cheng Wang  <cole945@gmail.com>
	    Marcin Kościelnicki  <koriakin@0x04.net>

	* Makefile.in: Add powerpc-*-ipa.o
	* configure.srv: Add ipa_obj for powerpc*-linux.
	* linux-ppc-ipa.c: New file.
	* linux-ppc-low.c: Added linux-ppc-tdesc.h, ax.h,
	tracepoint.h includes.
	(PPC_FIELD): New macro.
	(PPC_SEXT): New macro.
	(PPC_OP6): New macro.
	(PPC_BO): New macro.
	(PPC_LI): New macro.
	(PPC_BD): New macro.
	(init_registers_*): Move prototype to linux-ppc-tdesc.h.
	(tdesc_*): Move declaration to linux-ppc-tdesc.h.
	(ppc_get_thread_area): New function.
	(gen_ds_form): New function.
	(GEN_STD): New macro.
	(GEN_STDU): New macro.
	(GEN_LD): New macro.
	(GEN_LDU): New macro.
	(gen_d_form): New function.
	(GEN_ADDI): New macro.
	(GEN_ADDIS): New macro.
	(GEN_LI): New macro.
	(GEN_LIS): New macro.
	(GEN_ORI): New macro.
	(GEN_ORIS): New macro.
	(GEN_LWZ): New macro.
	(GEN_STW): New macro.
	(GEN_STWU): New macro.
	(gen_xfx_form): New function.
	(GEN_MFSPR): New macro.
	(GEN_MTSPR): New macro.
	(GEN_MFCR): New macro.
	(GEN_MTCR): New macro.
	(GEN_SYNC): New macro.
	(GEN_LWSYNC): New macro.
	(gen_x_form): New function.
	(GEN_OR): New macro.
	(GEN_MR): New macro.
	(GEN_LWARX): New macro.
	(GEN_STWCX): New macro.
	(GEN_CMPW): New macro.
	(gen_md_form): New function.
	(GEN_RLDICL): New macro.
	(GEN_RLDICR): New macro.
	(gen_i_form): New function.
	(GEN_B): New macro.
	(GEN_BL): New macro.
	(gen_b_form): New function.
	(GEN_BNE): New macro.
	(GEN_LOAD): New macro.
	(GEN_STORE): New macro.
	(gen_limm): New function.
	(gen_atomic_xchg): New function.
	(gen_call): New function.
	(ppc_relocate_instruction): New function.
	(ppc_install_fast_tracepoint_jump_pad): New function.
	(ppc_get_min_fast_tracepoint_insn_len): New function.
	(ppc_get_ipa_tdesc_idx): New function.
	(the_low_target): Wire in the new functions.
	(initialize_low_arch) [!__powerpc64__]: Don'it initialize 64-bit
	tdescs.
	* linux-ppc-tdesc.h: New file.
---
Most of this patch comes from
https://sourceware.org/ml/gdb-patches/2015-07/msg00353.html , but some
fixes have been added (mostly for 32-bit and 64-bit ELFv1), and some
updates were needed (for get_ipa_tdesc_idx etc.).

I'm not sure how to properly determine whether ELFv1 or ELFv2 is in use
by the target, so I assume it's the same ABI as in gdbserver itself.

Allocating the jump pad buffer needs a mention.  On powerpc64, IPA simply
scans from 0x10000000 (the executable load address) downwards until it
find a free address.  However, on 32-bit, ld.so loads dynamic libraries
there, and they can easily cause us to exceed the 32MiB branch range -
so, instead I aim right after the executable, at sbrk(0).  This will
of course cause further memory allocation via brk to fail, but glibc
transparently falls back to mmap in this case, so that's not a problem.
Of course, given a program with large data/bss section, this might
exceed the branch range as well, so perhaps some better heuristic is
in order here.

 gdb/gdbserver/ChangeLog         |  67 ++++
 gdb/gdbserver/Makefile.in       |  48 +++
 gdb/gdbserver/configure.srv     |   2 +
 gdb/gdbserver/linux-ppc-ipa.c   | 238 +++++++++++
 gdb/gdbserver/linux-ppc-low.c   | 856 +++++++++++++++++++++++++++++++++++++---
 gdb/gdbserver/linux-ppc-tdesc.h | 101 +++++
 6 files changed, 1249 insertions(+), 63 deletions(-)
 create mode 100644 gdb/gdbserver/linux-ppc-ipa.c
 create mode 100644 gdb/gdbserver/linux-ppc-tdesc.h

diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 4a4a9bf..a6bba77 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,70 @@
+2016-03-13  Wei-cheng Wang  <cole945@gmail.com>
+	    Marcin Kościelnicki  <koriakin@0x04.net>
+
+	* Makefile.in: Add powerpc-*-ipa.o
+	* configure.srv: Add ipa_obj for powerpc*-linux.
+	* linux-ppc-ipa.c: New file.
+	* linux-ppc-low.c: Added linux-ppc-tdesc.h, ax.h,
+	tracepoint.h includes.
+	(PPC_FIELD): New macro.
+	(PPC_SEXT): New macro.
+	(PPC_OP6): New macro.
+	(PPC_BO): New macro.
+	(PPC_LI): New macro.
+	(PPC_BD): New macro.
+	(init_registers_*): Move prototype to linux-ppc-tdesc.h.
+	(tdesc_*): Move declaration to linux-ppc-tdesc.h.
+	(ppc_get_thread_area): New function.
+	(gen_ds_form): New function.
+	(GEN_STD): New macro.
+	(GEN_STDU): New macro.
+	(GEN_LD): New macro.
+	(GEN_LDU): New macro.
+	(gen_d_form): New function.
+	(GEN_ADDI): New macro.
+	(GEN_ADDIS): New macro.
+	(GEN_LI): New macro.
+	(GEN_LIS): New macro.
+	(GEN_ORI): New macro.
+	(GEN_ORIS): New macro.
+	(GEN_LWZ): New macro.
+	(GEN_STW): New macro.
+	(GEN_STWU): New macro.
+	(gen_xfx_form): New function.
+	(GEN_MFSPR): New macro.
+	(GEN_MTSPR): New macro.
+	(GEN_MFCR): New macro.
+	(GEN_MTCR): New macro.
+	(GEN_SYNC): New macro.
+	(GEN_LWSYNC): New macro.
+	(gen_x_form): New function.
+	(GEN_OR): New macro.
+	(GEN_MR): New macro.
+	(GEN_LWARX): New macro.
+	(GEN_STWCX): New macro.
+	(GEN_CMPW): New macro.
+	(gen_md_form): New function.
+	(GEN_RLDICL): New macro.
+	(GEN_RLDICR): New macro.
+	(gen_i_form): New function.
+	(GEN_B): New macro.
+	(GEN_BL): New macro.
+	(gen_b_form): New function.
+	(GEN_BNE): New macro.
+	(GEN_LOAD): New macro.
+	(GEN_STORE): New macro.
+	(gen_limm): New function.
+	(gen_atomic_xchg): New function.
+	(gen_call): New function.
+	(ppc_relocate_instruction): New function.
+	(ppc_install_fast_tracepoint_jump_pad): New function.
+	(ppc_get_min_fast_tracepoint_insn_len): New function.
+	(ppc_get_ipa_tdesc_idx): New function.
+	(the_low_target): Wire in the new functions.
+	(initialize_low_arch) [!__powerpc64__]: Don'it initialize 64-bit
+	tdescs.
+	* linux-ppc-tdesc.h: New file.
+
 2016-03-13  Marcin Kościelnicki  <koriakin@0x04.net>
 
 	* linux-aarch64-ipa.c: Add <sys/mman.h> include.
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 257e9bf..11908d2 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -531,6 +531,54 @@ linux-aarch64-ipa.o: linux-aarch64-ipa.c
 aarch64-ipa.o: aarch64.c
 	$(IPAGENT_COMPILE) $<
 	$(POSTCOMPILE)
+linux-ppc-ipa.o: linux-ppc-ipa.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-32l-ipa.o: powerpc-32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-altivec32l-ipa.o: powerpc-altivec32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-cell32l-ipa.o: powerpc-cell32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-vsx32l-ipa.o: powerpc-vsx32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-32l-ipa.o: powerpc-isa205-32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-altivec32l-ipa.o: powerpc-isa205-altivec32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-vsx32l-ipa.o: powerpc-isa205-vsx32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-e500l-ipa.o: powerpc-e500l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-64l-ipa.o: powerpc-64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-altivec64l-ipa.o: powerpc-altivec64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-cell64l-ipa.o: powerpc-cell64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-vsx64l-ipa.o: powerpc-vsx64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-64l-ipa.o: powerpc-isa205-64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-altivec64l-ipa.o: powerpc-isa205-altivec64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-vsx64l-ipa.o: powerpc-isa205-vsx64l.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 a89b1d1..177e0a3 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -31,6 +31,7 @@ srv_amd64_linux_regobj="amd64-linux.o amd64-avx-linux.o amd64-avx512-linux.o amd
 
 ipa_i386_linux_regobj="i386-linux-ipa.o i386-avx-linux-ipa.o i386-avx512-linux-ipa.o i386-mpx-linux-ipa.o i386-mmx-linux-ipa.o"
 ipa_amd64_linux_regobj="amd64-linux-ipa.o amd64-avx-linux-ipa.o amd64-avx512-linux-ipa.o amd64-mpx-linux-ipa.o"
+ipa_ppc_linux_regobj="powerpc-32l-ipa.o powerpc-altivec32l-ipa.o powerpc-cell32l-ipa.o powerpc-vsx32l-ipa.o powerpc-isa205-32l-ipa.o powerpc-isa205-altivec32l-ipa.o powerpc-isa205-vsx32l-ipa.o powerpc-e500l-ipa.o powerpc-64l-ipa.o powerpc-altivec64l-ipa.o powerpc-cell64l-ipa.o powerpc-vsx64l-ipa.o powerpc-isa205-64l-ipa.o powerpc-isa205-altivec64l-ipa.o powerpc-isa205-vsx64l-ipa.o"
 
 srv_i386_32bit_xmlfiles="i386/32bit-core.xml i386/32bit-sse.xml i386/32bit-avx.xml i386/32bit-avx512.xml i386/32bit-mpx.xml"
 srv_i386_64bit_xmlfiles="i386/64bit-core.xml i386/64bit-sse.xml i386/64bit-avx.xml i386/64bit-avx512.xml i386/x32-core.xml i386/64bit-mpx.xml"
@@ -258,6 +259,7 @@ case "${target}" in
 			srv_linux_usrregs=yes
 			srv_linux_regsets=yes
 			srv_linux_thread_db=yes
+			ipa_obj="${ipa_ppc_linux_regobj} 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..2e8afea
--- /dev/null
+++ b/gdb/gdbserver/linux-ppc-ipa.c
@@ -0,0 +1,238 @@
+/* GNU/Linux/PowerPC specific low level interface, for the in-process
+   agent library for GDB.
+
+   Copyright (C) 2016 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 <sys/mman.h>
+#include "tracepoint.h"
+#include "linux-ppc-tdesc.h"
+
+/* 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] * sizeof (long));
+    }
+}
+
+/* Return the value of register REGNUM.  RAW_REGS is collected buffer
+   by jump pad.  This function is called by emit_reg.  */
+
+ULONGEST
+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] * sizeof (long));
+}
+
+/* Allocate buffer for the jump pads.  The branch instruction has a reach
+   of +/- 32MiB, and the executable is loaded at 0x10000000 (256MiB).
+
+   64-bit: To maximize the area of executable that can use tracepoints,
+   try allocating at 0x10000000 - size initially, decreasing until we hit
+   a free area.
+
+   32-bit: ld.so loads dynamic libraries right below the executable, so
+   we cannot depend on that area (dynamic libraries can be quite large).
+   Instead, aim right after the executable - at sbrk(0).  This will
+   cause future brk to fail, and malloc will fallback to mmap.  */
+
+void *
+alloc_jump_pad_buffer (size_t size)
+{
+#ifdef __powerpc64__
+  uintptr_t addr;
+  int pagesize;
+  void *res;
+
+  pagesize = sysconf (_SC_PAGE_SIZE);
+  if (pagesize == -1)
+    perror_with_name ("sysconf");
+
+  addr = 0x10000000 - size;
+
+  /* size should already be page-aligned, but this can't hurt.  */
+  addr &= ~(pagesize - 1);
+
+  /* Search for a free area.  If we hit 0, we're out of luck.  */
+  for (; addr; addr -= pagesize)
+    {
+      /* No MAP_FIXED - we don't want to zap someone's mapping.  */
+      res = mmap ((void *) addr, size,
+		  PROT_READ | PROT_WRITE | PROT_EXEC,
+		  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+      /* If we got what we wanted, return.  */
+      if ((uintptr_t) res == addr)
+	return res;
+
+      /* If we got a mapping, but at a wrong address, undo it.  */
+      if (res != MAP_FAILED)
+	munmap (res, size);
+    }
+
+  return NULL;
+#else
+  void *target = sbrk (0);
+  void *res = mmap (target, size, PROT_READ | PROT_WRITE | PROT_EXEC,
+		    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+  if (res == target)
+    return res;
+
+  if (res != MAP_FAILED)
+    munmap (res, size);
+
+  return NULL;
+#endif
+}
+
+/* Return target_desc to use for IPA, given the tdesc index passed by
+   gdbserver.  */
+
+const struct target_desc *
+get_ipa_tdesc (int idx)
+{
+  switch (idx)
+    {
+#ifdef __powerpc64__
+    case PPC_TDESC_BASE:
+      return tdesc_powerpc_64l;
+    case PPC_TDESC_ALTIVEC:
+      return tdesc_powerpc_altivec64l;
+    case PPC_TDESC_CELL:
+      return tdesc_powerpc_cell64l;
+    case PPC_TDESC_VSX:
+      return tdesc_powerpc_vsx64l;
+    case PPC_TDESC_ISA205:
+      return tdesc_powerpc_isa205_64l;
+    case PPC_TDESC_ISA205_ALTIVEC:
+      return tdesc_powerpc_isa205_altivec64l;
+    case PPC_TDESC_ISA205_VSX:
+      return tdesc_powerpc_isa205_vsx64l;
+#else
+    case PPC_TDESC_BASE:
+      return tdesc_powerpc_32l;
+    case PPC_TDESC_ALTIVEC:
+      return tdesc_powerpc_altivec32l;
+    case PPC_TDESC_CELL:
+      return tdesc_powerpc_cell32l;
+    case PPC_TDESC_VSX:
+      return tdesc_powerpc_vsx32l;
+    case PPC_TDESC_ISA205:
+      return tdesc_powerpc_isa205_32l;
+    case PPC_TDESC_ISA205_ALTIVEC:
+      return tdesc_powerpc_isa205_altivec32l;
+    case PPC_TDESC_ISA205_VSX:
+      return tdesc_powerpc_isa205_vsx32l;
+    case PPC_TDESC_E500:
+      return tdesc_powerpc_e500l;
+#endif
+    default:
+      internal_error (__FILE__, __LINE__,
+                     "unknown ipa tdesc index: %d", idx);
+#ifdef __powerpc64__
+      return tdesc_powerpc_64l;
+#else
+      return tdesc_powerpc_32l;
+#endif
+    }
+}
+
+
+/* Initialize ipa_tdesc and others.  */
+
+void
+initialize_low_tracepoint (void)
+{
+#ifdef __powerpc64__
+  init_registers_powerpc_64l ();
+  init_registers_powerpc_altivec64l ();
+  init_registers_powerpc_cell64l ();
+  init_registers_powerpc_vsx64l ();
+  init_registers_powerpc_isa205_64l ();
+  init_registers_powerpc_isa205_altivec64l ();
+  init_registers_powerpc_isa205_vsx64l ();
+#else
+  init_registers_powerpc_32l ();
+  init_registers_powerpc_altivec32l ();
+  init_registers_powerpc_cell32l ();
+  init_registers_powerpc_vsx32l ();
+  init_registers_powerpc_isa205_32l ();
+  init_registers_powerpc_isa205_altivec32l ();
+  init_registers_powerpc_isa205_vsx32l ();
+  init_registers_powerpc_e500l ();
+#endif
+}
diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c
index 49d27ee..c1a3a8d 100644
--- a/gdb/gdbserver/linux-ppc-low.c
+++ b/gdb/gdbserver/linux-ppc-low.c
@@ -24,70 +24,24 @@
 #include <asm/ptrace.h>
 
 #include "nat/ppc-linux.h"
+#include "linux-ppc-tdesc.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;
 
 
-/* Defined in auto-generated file powerpc-32l.c.  */
-void init_registers_powerpc_32l (void);
-extern const struct target_desc *tdesc_powerpc_32l;
-
-/* Defined in auto-generated file powerpc-altivec32l.c.  */
-void init_registers_powerpc_altivec32l (void);
-extern const struct target_desc *tdesc_powerpc_altivec32l;
-
-/* Defined in auto-generated file powerpc-cell32l.c.  */
-void init_registers_powerpc_cell32l (void);
-extern const struct target_desc *tdesc_powerpc_cell32l;
-
-/* Defined in auto-generated file powerpc-vsx32l.c.  */
-void init_registers_powerpc_vsx32l (void);
-extern const struct target_desc *tdesc_powerpc_vsx32l;
-
-/* Defined in auto-generated file powerpc-isa205-32l.c.  */
-void init_registers_powerpc_isa205_32l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_32l;
-
-/* Defined in auto-generated file powerpc-isa205-altivec32l.c.  */
-void init_registers_powerpc_isa205_altivec32l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_altivec32l;
-
-/* Defined in auto-generated file powerpc-isa205-vsx32l.c.  */
-void init_registers_powerpc_isa205_vsx32l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_vsx32l;
-
-/* Defined in auto-generated file powerpc-e500l.c.  */
-void init_registers_powerpc_e500l (void);
-extern const struct target_desc *tdesc_powerpc_e500l;
-
-/* Defined in auto-generated file powerpc-64l.c.  */
-void init_registers_powerpc_64l (void);
-extern const struct target_desc *tdesc_powerpc_64l;
-
-/* Defined in auto-generated file powerpc-altivec64l.c.  */
-void init_registers_powerpc_altivec64l (void);
-extern const struct target_desc *tdesc_powerpc_altivec64l;
-
-/* Defined in auto-generated file powerpc-cell64l.c.  */
-void init_registers_powerpc_cell64l (void);
-extern const struct target_desc *tdesc_powerpc_cell64l;
-
-/* Defined in auto-generated file powerpc-vsx64l.c.  */
-void init_registers_powerpc_vsx64l (void);
-extern const struct target_desc *tdesc_powerpc_vsx64l;
-
-/* Defined in auto-generated file powerpc-isa205-64l.c.  */
-void init_registers_powerpc_isa205_64l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_64l;
-
-/* Defined in auto-generated file powerpc-isa205-altivec64l.c.  */
-void init_registers_powerpc_isa205_altivec64l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_altivec64l;
-
-/* Defined in auto-generated file powerpc-isa205-vsx64l.c.  */
-void init_registers_powerpc_isa205_vsx64l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_vsx64l;
-
 #define ppc_num_regs 73
 
 #ifdef __powerpc64__
@@ -756,12 +710,784 @@ ppc_arch_setup (void)
   current_process ()->tdesc = tdesc;
 }
 
+/* Implementation of linux_target_ops method "supports_tracepoints".  */
+
 static int
 ppc_supports_tracepoints (void)
 {
   return 1;
 }
 
+/* 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)
+{
+#ifdef __powerpc64__
+  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);
+  int is_64 = register_size (regcache->tdesc, 0) == 8;
+#endif
+  long res;
+
+#ifdef __powerpc64__
+  if (is_64)
+    res = ptrace (PTRACE_PEEKUSER, lwpid, (long) PT_R13 * sizeof (long),
+		  (long) 0);
+  else
+#endif
+    res = ptrace (PTRACE_PEEKUSER, lwpid, (long) PT_R2 * sizeof (long),
+		  (long) 0);
+
+  if (res == -1)
+    return -1;
+
+  *addr = res;
+
+#ifdef __powerpc64__
+  if (!is_64)
+    *addr &= 0xffffffffull;
+#endif
+
+  return 0;
+}
+
+/* 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)
+#define GEN_STWU(buf, rt, ra, si)	gen_d_form (buf, 37, rt, ra, si)
+
+/* Generate a xfx-form instruction in BUF and return the number of bytes
+   written.
+
+   0      6     11         21        31 32
+   | OPCD | RST |    RI    |    XO   |/|  */
+
+static int
+gen_xfx_form (uint32_t *buf, int opcd, int rst, int ri, int xo)
+{
+  uint32_t insn;
+  unsigned int n = ((ri & 0x1f) << 5) | ((ri >> 5) & 0x1f);
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((rst & ~0x1f) == 0);
+  gdb_assert ((xo & ~0x3ff) == 0);
+
+  insn = (rst << 21) | (n << 11) | (xo << 1);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* Followings are frequently used xfx-form instructions.  */
+
+#define GEN_MFSPR(buf, rt, spr)		gen_xfx_form (buf, 31, rt, spr, 339)
+#define GEN_MTSPR(buf, rt, spr)		gen_xfx_form (buf, 31, rt, spr, 467)
+#define GEN_MFCR(buf, rt)		gen_xfx_form (buf, 31, rt, 0, 19)
+#define GEN_MTCR(buf, rt)		gen_xfx_form (buf, 31, rt, 0x3cf, 144)
+#define GEN_SYNC(buf, L, E)             gen_xfx_form (buf, 31, L & 0x3, \
+						      E & 0xf, 598)
+#define GEN_LWSYNC(buf)			GEN_SYNC (buf, 1, 0)
+
+
+/* Generate a x-form instruction in BUF and return the number of bytes written.
+
+   0      6     11   16   21       31 32
+   | OPCD | RST | RA | RB |   XO   |RC|  */
+
+static int
+gen_x_form (uint32_t *buf, int opcd, int rst, int ra, int rb, int xo, int rc)
+{
+  uint32_t insn;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((rst & ~0x1f) == 0);
+  gdb_assert ((ra & ~0x1f) == 0);
+  gdb_assert ((rb & ~0x1f) == 0);
+  gdb_assert ((xo & ~0x3ff) == 0);
+  gdb_assert ((rc & ~1) == 0);
+
+  insn = (rst << 21) | (ra << 16) | (rb << 11) | (xo << 1) | rc;
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* Followings are frequently used x-form instructions.  */
+
+#define GEN_OR(buf, ra, rs, rb)		gen_x_form (buf, 31, rs, ra, rb, 444, 0)
+#define GEN_MR(buf, ra, rs)		GEN_OR (buf, ra, rs, rs)
+#define GEN_LWARX(buf, rt, ra, rb)	gen_x_form (buf, 31, rt, ra, rb, 20, 0)
+#define GEN_STWCX(buf, rs, ra, rb)	gen_x_form (buf, 31, rs, ra, rb, 150, 1)
+/* Assume bf = cr7.  */
+#define GEN_CMPW(buf, ra, rb)		gen_x_form (buf, 31, 28, ra, rb, 0, 0)
+
+
+/* Generate a md-form instruction in BUF and return the number of bytes written.
+
+   0      6    11   16   21   27   30 31 32
+   | OPCD | RS | RA | sh | mb | XO |sh|Rc|  */
+
+static int
+gen_md_form (uint32_t *buf, int opcd, int rs, int ra, int sh, int mb,
+	     int xo, int rc)
+{
+  uint32_t insn;
+  unsigned int n = ((mb & 0x1f) << 1) | ((mb >> 5) & 0x1);
+  unsigned int sh0_4 = sh & 0x1f;
+  unsigned int sh5 = (sh >> 5) & 1;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((rs & ~0x1f) == 0);
+  gdb_assert ((ra & ~0x1f) == 0);
+  gdb_assert ((sh & ~0x3f) == 0);
+  gdb_assert ((mb & ~0x3f) == 0);
+  gdb_assert ((xo & ~0x7) == 0);
+  gdb_assert ((rc & ~0x1) == 0);
+
+  insn = (rs << 21) | (ra << 16) | (sh0_4 << 11) | (n << 5)
+	 | (sh5 << 1) | (xo << 2) | (rc & 1);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* The following are frequently used md-form instructions.  */
+
+#define GEN_RLDICL(buf, ra, rs ,sh, mb) \
+				gen_md_form (buf, 30, rs, ra, sh, mb, 0, 0)
+#define GEN_RLDICR(buf, ra, rs ,sh, mb) \
+				gen_md_form (buf, 30, rs, ra, sh, mb, 1, 0)
+
+/* Generate a i-form instruction in BUF and return the number of bytes written.
+
+   0      6                          30 31 32
+   | OPCD |            LI            |AA|LK|  */
+
+static int
+gen_i_form (uint32_t *buf, int opcd, int li, int aa, int lk)
+{
+  uint32_t insn;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+
+  insn = (li & 0x3fffffc) | (aa & 1) | (lk & 1);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* The following are frequently used i-form instructions.  */
+
+#define GEN_B(buf, li)		gen_i_form (buf, 18, li, 0, 0)
+#define GEN_BL(buf, li)		gen_i_form (buf, 18, li, 0, 1)
+
+/* Generate a b-form instruction in BUF and return the number of bytes written.
+
+   0      6    11   16               30 31 32
+   | OPCD | BO | BI |      BD        |AA|LK|  */
+
+static int
+gen_b_form (uint32_t *buf, int opcd, int bo, int bi, int bd,
+	    int aa, int lk)
+{
+  uint32_t insn;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((bo & ~0x1f) == 0);
+  gdb_assert ((bi & ~0x1f) == 0);
+
+  insn = (bo << 21) | (bi << 16) | (bd & 0xfffc) | (aa & 1) | (lk & 1);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* The following are frequently used b-form instructions.  */
+/* Assume bi = cr7.  */
+#define GEN_BNE(buf, bd)  gen_b_form (buf, 16, 0x4, (7 << 2) | 2, bd, 0 ,0)
+
+/* GEN_LOAD and GEN_STORE generate 64- or 32-bit load/store for ppc64 or ppc32
+   respectively.  They are primary used for save/restore GPRs in jump-pad,
+   not used for bytecode compiling.  */
+
+#if defined __powerpc64__
+#define GEN_LOAD(buf, rt, ra, si)	(is_64 ? GEN_LD (buf, rt, ra, si) : \
+						 GEN_LWZ (buf, rt, ra, si))
+#define GEN_STORE(buf, rt, ra, si)	(is_64 ? GEN_STD (buf, rt, ra, si) : \
+						 GEN_STW (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, int is_64)
+{
+  uint32_t *p = buf;
+
+  if ((imm + 32768) < 65536)
+    {
+      /* li	reg, imm[7:0] */
+      p += GEN_LI (p, reg, imm);
+    }
+  else if ((imm >> 16) == 0)
+    {
+      /* li	reg, 0
+	 ori	reg, reg, imm[15:0] */
+      p += GEN_LI (p, reg, 0);
+      p += GEN_ORI (p, reg, reg, imm);
+    }
+  else if ((imm >> 32) == 0)
+    {
+      /* lis	reg, imm[31:16]
+	 ori	reg, reg, imm[15:0]
+	 rldicr reg, reg, 0, 32 */
+      p += GEN_LIS (p, reg, (imm >> 16) & 0xffff);
+      p += GEN_ORI (p, reg, reg, imm & 0xffff);
+      /* Clear upper 32-bit if sign-bit is set.  */
+      if (imm & (1 << 31) && is_64)
+	p += GEN_RLDICL (p, reg, reg, 0, 32);
+    }
+  else
+    {
+      gdb_assert (is_64);
+      /* 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,
+		 int is_64)
+{
+  const int r_lock = 6;
+  const int r_old = 7;
+  const int r_tmp = 8;
+  uint32_t *p = buf;
+
+  /*
+  1: lwarx   TMP, 0, LOCK
+     cmpwi   TMP, OLD
+     bne     1b
+     stwcx.  NEW, 0, LOCK
+     bne     1b */
+
+  p += gen_limm (p, r_lock, lock, is_64);
+  p += gen_limm (p, r_old, old_value, is_64);
+
+  p += GEN_LWARX (p, r_tmp, 0, r_lock);
+  p += GEN_CMPW (p, r_tmp, r_old);
+  p += GEN_BNE (p, -8);
+  p += GEN_STWCX (p, r_new, 0, r_lock);
+  p += GEN_BNE (p, -16);
+
+  return p - buf;
+}
+
+/* Generate a sequence of instructions for calling a function
+   at address of FN.  Return the number of bytes are written in BUF.  */
+
+static int
+gen_call (uint32_t *buf, CORE_ADDR fn, int is_64, int is_opd)
+{
+  uint32_t *p = buf;
+
+  /* Must be called by r12 for caller to calculate TOC address. */
+  p += gen_limm (p, 12, fn, is_64);
+  if (is_opd)
+    {
+      p += GEN_LOAD (p, 11, 12, 16);
+      p += GEN_LOAD (p, 2, 12, 8);
+      p += GEN_LOAD (p, 12, 12, 0);
+    }
+  p += GEN_MTSPR (p, 12, 9);		/* mtctr  r12 */
+  *p++ = 0x4e800421;			/* bctrl */
+
+  return p - buf;
+}
+
+/* Copy the instruction from OLDLOC to *TO, and update *TO to *TO + size
+   of instruction.  This function is used to adjust pc-relative instructions
+   when copying.  */
+
+static void
+ppc_relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc)
+{
+  uint32_t insn, op6;
+  long rel, newrel;
+
+  read_inferior_memory (oldloc, (unsigned char *) &insn, 4);
+  op6 = PPC_OP6 (insn);
+
+  if (op6 == 18 && (insn & 2) == 0)
+    {
+      /* branch && AA = 0 */
+      rel = PPC_LI (insn);
+      newrel = (oldloc - *to) + rel;
+
+      /* Out of range. Cannot relocate instruction.  */
+      if (newrel >= (1 << 25) || newrel < -(1 << 25))
+	return;
+
+      insn = (insn & ~0x3fffffc) | (newrel & 0x3fffffc);
+    }
+  else if (op6 == 16 && (insn & 2) == 0)
+    {
+      /* conditional branch && AA = 0 */
+
+      /* If the new relocation is too big for even a 26-bit unconditional
+	 branch, there is nothing we can do.  Just abort.
+
+	 Otherwise, if it can be fit in 16-bit conditional branch, just
+	 copy the instruction and relocate the address.
+
+	 If the it's  big for conditional-branch (16-bit), try to invert the
+	 condition and jump with 26-bit branch.  For example,
+
+	 beq  .Lgoto
+	 INSN1
+
+	 =>
+
+	 bne  1f (+8)
+	 b    .Lgoto
+       1:INSN1
+
+	 After this transform, we are actually jump from *TO+4 instead of *TO,
+	 so check the relocation again because it will be 1-insn farther then
+	 before if *TO is after OLDLOC.
+
+
+	 For BDNZT (or so) is transformed from
+
+	 bdnzt  eq, .Lgoto
+	 INSN1
+
+	 =>
+
+	 bdz    1f (+12)
+	 bf     eq, 1f (+8)
+	 b      .Lgoto
+       1:INSN1
+
+	 See also "BO field encodings".  */
+
+      rel = PPC_BD (insn);
+      newrel = (oldloc - *to) + rel;
+
+      if (newrel < (1 << 15) && newrel >= -(1 << 15))
+	insn = (insn & ~0xfffc) | (newrel & 0xfffc);
+      else if ((PPC_BO (insn) & 0x14) == 0x4 || (PPC_BO (insn) & 0x14) == 0x10)
+	{
+	  newrel -= 4;
+
+	  /* Out of range. Cannot relocate instruction.  */
+	  if (newrel >= (1 << 25) || newrel < -(1 << 25))
+	    return;
+
+	  if ((PPC_BO (insn) & 0x14) == 0x4)
+	    insn ^= (1 << 24);
+	  else if ((PPC_BO (insn) & 0x14) == 0x10)
+	    insn ^= (1 << 22);
+
+	  /* Jump over the unconditional branch.  */
+	  insn = (insn & ~0xfffc) | 0x8;
+	  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+	  *to += 4;
+
+	  /* Build a unconditional branch and copy LK bit.  */
+	  insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3);
+	  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+	  *to += 4;
+
+	  return;
+	}
+      else if ((PPC_BO (insn) & 0x14) == 0)
+	{
+	  uint32_t bdnz_insn = (16 << 26) | (0x10 << 21) | 12;
+	  uint32_t bf_insn = (16 << 26) | (0x4 << 21) | 8;
+
+	  newrel -= 8;
+
+	  /* Out of range. Cannot relocate instruction.  */
+	  if (newrel >= (1 << 25) || newrel < -(1 << 25))
+	    return;
+
+	  /* Copy BI field.  */
+	  bf_insn |= (insn & 0x1f0000);
+
+	  /* Invert condition.  */
+	  bdnz_insn |= (insn ^ (1 << 22)) & (1 << 22);
+	  bf_insn |= (insn ^ (1 << 24)) & (1 << 24);
+
+	  write_inferior_memory (*to, (unsigned char *) &bdnz_insn, 4);
+	  *to += 4;
+	  write_inferior_memory (*to, (unsigned char *) &bf_insn, 4);
+	  *to += 4;
+
+	  /* Build a unconditional branch and copy LK bit.  */
+	  insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3);
+	  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+	  *to += 4;
+
+	  return;
+	}
+      else /* (BO & 0x14) == 0x14, branch always.  */
+	{
+	  /* Out of range. Cannot relocate instruction.  */
+	  if (newrel >= (1 << 25) || newrel < -(1 << 25))
+	    return;
+
+	  /* Build a unconditional branch and copy LK bit.  */
+	  insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3);
+	  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+	  *to += 4;
+
+	  return;
+	}
+    }
+
+  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+  *to += 4;
+}
+
+/* Implement install_fast_tracepoint_jump_pad of target_ops.
+   See target.h for details.  */
+
+static int
+ppc_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
+				      CORE_ADDR collector,
+				      CORE_ADDR lockaddr,
+				      ULONGEST orig_size,
+				      CORE_ADDR *jump_entry,
+				      CORE_ADDR *trampoline,
+				      ULONGEST *trampoline_size,
+				      unsigned char *jjump_pad_insn,
+				      ULONGEST *jjump_pad_insn_size,
+				      CORE_ADDR *adjusted_insn_addr,
+				      CORE_ADDR *adjusted_insn_addr_end,
+				      char *err)
+{
+  uint32_t buf[256];
+  uint32_t *p = buf;
+  int j, offset;
+  CORE_ADDR buildaddr = *jump_entry;
+  const CORE_ADDR entryaddr = *jump_entry;
+  int rsz, min_frame, frame_size, tp_reg;
+#ifdef __powerpc64__
+  struct regcache *regcache = get_thread_regcache (current_thread, 0);
+  int is_64 = register_size (regcache->tdesc, 0) == 8;
+#if _CALL_ELF == 2
+  /* XXX is there a way to get this dynamically from the inferior?  */
+  int is_opd = 0;
+#else
+  int is_opd = is_64;
+#endif
+#else
+  int is_64 = 0, is_opd = 0;
+#endif
+
+#ifdef __powerpc64__
+  if (is_64)
+    {
+      /* Minimum frame size is 32 bytes for ELFv2, and 112 bytes for ELFv1.  */
+      rsz = 8;
+      min_frame = 112;
+      frame_size = (40 * rsz) + min_frame;
+      tp_reg = 13;
+    }
+  else
+    {
+#endif
+      rsz = 4;
+      min_frame = 16;
+      frame_size = (40 * rsz) + min_frame;
+      tp_reg = 2;
+#ifdef __powerpc64__
+    }
+#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.  */
+  if (is_64)
+    p += GEN_STDU (p, 1, 1, -frame_size);		/* stdu   r1,-frame_size(r1) */
+  else
+    p += GEN_STWU (p, 1, 1, -frame_size);		/* stwu   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, is_64);
+  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, is_64);
+
+  /* Prepare collecting_t object for lock.  */
+  p += GEN_STORE (p, 3, 1, min_frame + 37 * rsz);
+  p += GEN_STORE (p, tp_reg, 1, min_frame + 38 * rsz);
+  /* Set R5 to collecting object.  */
+  p += GEN_ADDI (p, 5, 1, 37 * rsz);
+
+  p += GEN_LWSYNC (p);
+  p += gen_atomic_xchg (p, lockaddr, 0, 5, is_64);
+  p += GEN_LWSYNC (p);
+
+  /* Call to collector.  */
+  p += gen_call (p, collector, is_64, is_opd);
+
+  /* Simply write 0 to release the lock.  */
+  p += gen_limm (p, 3, lockaddr, is_64);
+  p += gen_limm (p, 4, 0, is_64);
+  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 (void)
+{
+  return 4;
+}
+
+/* Implementation of linux_target_ops method "get_ipa_tdesc_idx".  */
+
+static int
+ppc_get_ipa_tdesc_idx (void)
+{
+  struct regcache *regcache = get_thread_regcache (current_thread, 0);
+  const struct target_desc *tdesc = regcache->tdesc;
+
+#ifdef __powerpc64__
+  if (tdesc == tdesc_powerpc_64l)
+    return PPC_TDESC_BASE;
+  if (tdesc == tdesc_powerpc_altivec64l)
+    return PPC_TDESC_ALTIVEC;
+  if (tdesc == tdesc_powerpc_cell64l)
+    return PPC_TDESC_CELL;
+  if (tdesc == tdesc_powerpc_vsx64l)
+    return PPC_TDESC_VSX;
+  if (tdesc == tdesc_powerpc_isa205_64l)
+    return PPC_TDESC_ISA205;
+  if (tdesc == tdesc_powerpc_isa205_altivec64l)
+    return PPC_TDESC_ISA205_ALTIVEC;
+  if (tdesc == tdesc_powerpc_isa205_vsx64l)
+    return PPC_TDESC_ISA205_VSX;
+#endif
+
+  if (tdesc == tdesc_powerpc_32l)
+    return PPC_TDESC_BASE;
+  if (tdesc == tdesc_powerpc_altivec32l)
+    return PPC_TDESC_ALTIVEC;
+  if (tdesc == tdesc_powerpc_cell32l)
+    return PPC_TDESC_CELL;
+  if (tdesc == tdesc_powerpc_vsx32l)
+    return PPC_TDESC_VSX;
+  if (tdesc == tdesc_powerpc_isa205_32l)
+    return PPC_TDESC_ISA205;
+  if (tdesc == tdesc_powerpc_isa205_altivec32l)
+    return PPC_TDESC_ISA205_ALTIVEC;
+  if (tdesc == tdesc_powerpc_isa205_vsx32l)
+    return PPC_TDESC_ISA205_VSX;
+  if (tdesc == tdesc_powerpc_e500l)
+    return PPC_TDESC_E500;
+
+  return 0;
+}
+
 struct linux_target_ops the_low_target = {
   ppc_arch_setup,
   ppc_regs_info,
@@ -789,13 +1515,15 @@ struct linux_target_ops the_low_target = {
   NULL, /* prepare_to_resume */
   NULL, /* process_qsupported */
   ppc_supports_tracepoints,
-  NULL, /* get_thread_area */
-  NULL, /* install_fast_tracepoint_jump_pad */
+  ppc_get_thread_area,
+  ppc_install_fast_tracepoint_jump_pad,
   NULL, /* emit_ops */
-  NULL, /* get_min_fast_tracepoint_insn_len */
+  ppc_get_min_fast_tracepoint_insn_len,
   NULL, /* supports_range_stepping */
   NULL, /* breakpoint_kind_from_current_state */
   ppc_supports_hardware_single_step,
+  NULL, /* get_syscall_trapinfo */
+  ppc_get_ipa_tdesc_idx,
 };
 
 void
@@ -811,6 +1539,7 @@ initialize_low_arch (void)
   init_registers_powerpc_isa205_altivec32l ();
   init_registers_powerpc_isa205_vsx32l ();
   init_registers_powerpc_e500l ();
+#if __powerpc64__
   init_registers_powerpc_64l ();
   init_registers_powerpc_altivec64l ();
   init_registers_powerpc_cell64l ();
@@ -818,6 +1547,7 @@ initialize_low_arch (void)
   init_registers_powerpc_isa205_64l ();
   init_registers_powerpc_isa205_altivec64l ();
   init_registers_powerpc_isa205_vsx64l ();
+#endif
 
   initialize_regsets_info (&ppc_regsets_info);
 }
diff --git a/gdb/gdbserver/linux-ppc-tdesc.h b/gdb/gdbserver/linux-ppc-tdesc.h
new file mode 100644
index 0000000..d77b127
--- /dev/null
+++ b/gdb/gdbserver/linux-ppc-tdesc.h
@@ -0,0 +1,101 @@
+/* Low level support for ppc, shared between gdbserver and IPA.
+
+   Copyright (C) 2016 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/>.  */
+
+/* Note: since IPA obviously knows what ABI it's running on (32 vs 64),
+   it's sufficient to pass only the register set here.  This, together with
+   the ABI known at IPA compile time, maps to a tdesc.  */
+
+enum ppc_linux_tdesc {
+  PPC_TDESC_BASE,
+  PPC_TDESC_ALTIVEC,
+  PPC_TDESC_CELL,
+  PPC_TDESC_VSX,
+  PPC_TDESC_ISA205,
+  PPC_TDESC_ISA205_ALTIVEC,
+  PPC_TDESC_ISA205_VSX,
+  PPC_TDESC_E500,
+};
+
+#if !defined __powerpc64__ || !defined IN_PROCESS_AGENT
+
+/* Defined in auto-generated file powerpc-32l.c.  */
+void init_registers_powerpc_32l (void);
+extern const struct target_desc *tdesc_powerpc_32l;
+
+/* Defined in auto-generated file powerpc-altivec32l.c.  */
+void init_registers_powerpc_altivec32l (void);
+extern const struct target_desc *tdesc_powerpc_altivec32l;
+
+/* Defined in auto-generated file powerpc-cell32l.c.  */
+void init_registers_powerpc_cell32l (void);
+extern const struct target_desc *tdesc_powerpc_cell32l;
+
+/* Defined in auto-generated file powerpc-vsx32l.c.  */
+void init_registers_powerpc_vsx32l (void);
+extern const struct target_desc *tdesc_powerpc_vsx32l;
+
+/* Defined in auto-generated file powerpc-isa205-32l.c.  */
+void init_registers_powerpc_isa205_32l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_32l;
+
+/* Defined in auto-generated file powerpc-isa205-altivec32l.c.  */
+void init_registers_powerpc_isa205_altivec32l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_altivec32l;
+
+/* Defined in auto-generated file powerpc-isa205-vsx32l.c.  */
+void init_registers_powerpc_isa205_vsx32l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_vsx32l;
+
+/* Defined in auto-generated file powerpc-e500l.c.  */
+void init_registers_powerpc_e500l (void);
+extern const struct target_desc *tdesc_powerpc_e500l;
+
+#endif
+
+#if defined __powerpc64__
+
+/* Defined in auto-generated file powerpc-64l.c.  */
+void init_registers_powerpc_64l (void);
+extern const struct target_desc *tdesc_powerpc_64l;
+
+/* Defined in auto-generated file powerpc-altivec64l.c.  */
+void init_registers_powerpc_altivec64l (void);
+extern const struct target_desc *tdesc_powerpc_altivec64l;
+
+/* Defined in auto-generated file powerpc-cell64l.c.  */
+void init_registers_powerpc_cell64l (void);
+extern const struct target_desc *tdesc_powerpc_cell64l;
+
+/* Defined in auto-generated file powerpc-vsx64l.c.  */
+void init_registers_powerpc_vsx64l (void);
+extern const struct target_desc *tdesc_powerpc_vsx64l;
+
+/* Defined in auto-generated file powerpc-isa205-64l.c.  */
+void init_registers_powerpc_isa205_64l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_64l;
+
+/* Defined in auto-generated file powerpc-isa205-altivec64l.c.  */
+void init_registers_powerpc_isa205_altivec64l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_altivec64l;
+
+/* Defined in auto-generated file powerpc-isa205-vsx64l.c.  */
+void init_registers_powerpc_isa205_vsx64l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_vsx64l;
+
+#endif
-- 
2.7.2

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

* [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers.
  2016-03-13  2:31 [PATCH 0/3] gdbserver: Add powerpc fast tracepoint support Marcin Kościelnicki
  2016-03-13  2:32 ` [PATCH 3/3] " Marcin Kościelnicki
  2016-03-13  2:32 ` [PATCH 2/3] IPA: Add alloc_jump_pad_buffer target hook Marcin Kościelnicki
@ 2016-03-13  2:32 ` Marcin Kościelnicki
  2016-03-14 14:41   ` Ulrich Weigand
  2016-03-14 22:25 ` [PATCH 4/4] gdbserver: Add emit_ops for powerpc Marcin Kościelnicki
  3 siblings, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-13  2:32 UTC (permalink / raw)
  To: gdb-patches; +Cc: Marcin Kościelnicki

On powerpc64, qSymbol for a function returns the function code address,
and not the descriptor address.  Since we emit code calling gdb_collect
and some other functions, we need the descriptor (no way to know the
proper TOC address without it).  To get the descriptor address, make
global function pointer variables in the IPA pointing to the relevant
functions and read them instead of asking for them directly via qSymbol.

gdb/gdbserver/ChangeLog:

	* linux-aarch64-ipa.c: Rename gdb_agent_get_raw_reg to get_raw_reg.
	* linux-amd64-ipa.c: Ditto.
	* linux-i386-ipa.c: Ditto.
	* tracepoint.c: IPA-export gdb_collect_ptr instead of gdb_collect,
	ditto for get_raw_reg_ptr, get_trace_state_variable_value_ptr,
	set_trace_state_variable_value_ptr.
	(struct ipa_sym_addresses): Ditto.
	(symbol_list): Ditto.
	(install_fast_tracepoint): Dereference gdb_collect_ptr instead of
	accessing gdb_collect directly.
	(gdb_collect_ptr_type): New typedef.
	(get_raw_reg_ptr_type): New typedef.
	(get_trace_state_variable_value_ptr_type): New typedef.
	(set_trace_state_variable_value_ptr_type): New typedef.
	(gdb_collect_ptr): New global.
	(get_raw_reg_ptr): New global.
	(get_trace_state_variable_value_ptr): New global.
	(set_trace_state_variable_value_ptr): New global.
	(get_raw_reg_func_addr): Ditto for get_raw_reg_ptr
	(get_get_tsv_func_addr): Ditto for get_trace_state_variable_value_ptr.
	(get_set_tsv_func_addr): Ditto for set_trace_state_variable_value_ptr.
	* tracepoint.h: Rename gdb_agent_get_raw_reg to get_raw_reg.
---
Another approach here could be to add a flag to qSymbol selecting
descriptor vs code address, but I'd rather not mess with changing the
remote protocol.

 gdb/gdbserver/ChangeLog           | 25 ++++++++++++
 gdb/gdbserver/linux-aarch64-ipa.c |  4 +-
 gdb/gdbserver/linux-amd64-ipa.c   |  4 +-
 gdb/gdbserver/linux-i386-ipa.c    |  4 +-
 gdb/gdbserver/tracepoint.c        | 83 ++++++++++++++++++++++++++++++---------
 gdb/gdbserver/tracepoint.h        |  3 +-
 6 files changed, 97 insertions(+), 26 deletions(-)

diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 7ce2690..31120c5 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,5 +1,30 @@
 2016-03-12  Marcin Kościelnicki  <koriakin@0x04.net>
 
+	* linux-aarch64-ipa.c: Rename gdb_agent_get_raw_reg to get_raw_reg.
+	* linux-amd64-ipa.c: Ditto.
+	* linux-i386-ipa.c: Ditto.
+	* tracepoint.c: IPA-export gdb_collect_ptr instead of gdb_collect,
+	ditto for get_raw_reg_ptr, get_trace_state_variable_value_ptr,
+	set_trace_state_variable_value_ptr.
+	(struct ipa_sym_addresses): Ditto.
+	(symbol_list): Ditto.
+	(install_fast_tracepoint): Dereference gdb_collect_ptr instead of
+	accessing gdb_collect directly.
+	(gdb_collect_ptr_type): New typedef.
+	(get_raw_reg_ptr_type): New typedef.
+	(get_trace_state_variable_value_ptr_type): New typedef.
+	(set_trace_state_variable_value_ptr_type): New typedef.
+	(gdb_collect_ptr): New global.
+	(get_raw_reg_ptr): New global.
+	(get_trace_state_variable_value_ptr): New global.
+	(set_trace_state_variable_value_ptr): New global.
+	(get_raw_reg_func_addr): Ditto for get_raw_reg_ptr
+	(get_get_tsv_func_addr): Ditto for get_trace_state_variable_value_ptr.
+	(get_set_tsv_func_addr): Ditto for set_trace_state_variable_value_ptr.
+	* tracepoint.h: Rename gdb_agent_get_raw_reg to get_raw_reg.
+
+2016-03-12  Marcin Kościelnicki  <koriakin@0x04.net>
+
 	* remote-utils.c (look_up_one_symbol): Remove own_buf, handle 'v'
 	packets.
 	(relocate_instruction): Remove own_buf.
diff --git a/gdb/gdbserver/linux-aarch64-ipa.c b/gdb/gdbserver/linux-aarch64-ipa.c
index f1eaa70..00cbf3e 100644
--- a/gdb/gdbserver/linux-aarch64-ipa.c
+++ b/gdb/gdbserver/linux-aarch64-ipa.c
@@ -133,8 +133,8 @@ supply_fast_tracepoint_registers (struct regcache *regcache,
 		     + (aarch64_ft_collect_regmap[i] * FT_CR_SIZE));
 }
 
-IP_AGENT_EXPORT_FUNC ULONGEST
-gdb_agent_get_raw_reg (const unsigned char *raw_regs, int regnum)
+ULONGEST
+get_raw_reg (const unsigned char *raw_regs, int regnum)
 {
   if (regnum >= AARCH64_NUM_FT_COLLECT_GREGS)
     return 0;
diff --git a/gdb/gdbserver/linux-amd64-ipa.c b/gdb/gdbserver/linux-amd64-ipa.c
index 2dca943..70889d2 100644
--- a/gdb/gdbserver/linux-amd64-ipa.c
+++ b/gdb/gdbserver/linux-amd64-ipa.c
@@ -69,8 +69,8 @@ supply_fast_tracepoint_registers (struct regcache *regcache,
 		     ((char *) buf) + x86_64_ft_collect_regmap[i]);
 }
 
-IP_AGENT_EXPORT_FUNC ULONGEST
-gdb_agent_get_raw_reg (const unsigned char *raw_regs, int regnum)
+ULONGEST
+get_raw_reg (const unsigned char *raw_regs, int regnum)
 {
   if (regnum >= X86_64_NUM_FT_COLLECT_GREGS)
     return 0;
diff --git a/gdb/gdbserver/linux-i386-ipa.c b/gdb/gdbserver/linux-i386-ipa.c
index 4860012..7159eee 100644
--- a/gdb/gdbserver/linux-i386-ipa.c
+++ b/gdb/gdbserver/linux-i386-ipa.c
@@ -95,8 +95,8 @@ supply_fast_tracepoint_registers (struct regcache *regcache,
     }
 }
 
-IP_AGENT_EXPORT_FUNC ULONGEST
-gdb_agent_get_raw_reg (const unsigned char *raw_regs, int regnum)
+ULONGEST
+get_raw_reg (const unsigned char *raw_regs, int regnum)
 {
   /* This should maybe be allowed to return an error code, or perhaps
      better, have the emit_reg detect this, and emit a constant zero,
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index 383fb71..061e161 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -108,7 +108,7 @@ trace_vdebug (const char *fmt, ...)
 # define gdb_trampoline_buffer_end IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer_end)
 # define gdb_trampoline_buffer_error IPA_SYM_EXPORTED_NAME (gdb_trampoline_buffer_error)
 # define collecting IPA_SYM_EXPORTED_NAME (collecting)
-# define gdb_collect IPA_SYM_EXPORTED_NAME (gdb_collect)
+# define gdb_collect_ptr IPA_SYM_EXPORTED_NAME (gdb_collect_ptr)
 # define stop_tracing IPA_SYM_EXPORTED_NAME (stop_tracing)
 # define flush_trace_buffer IPA_SYM_EXPORTED_NAME (flush_trace_buffer)
 # define about_to_request_buffer_space IPA_SYM_EXPORTED_NAME (about_to_request_buffer_space)
@@ -126,11 +126,11 @@ trace_vdebug (const char *fmt, ...)
 # define traceframe_write_count IPA_SYM_EXPORTED_NAME (traceframe_write_count)
 # define traceframes_created IPA_SYM_EXPORTED_NAME (traceframes_created)
 # define trace_state_variables IPA_SYM_EXPORTED_NAME (trace_state_variables)
-# define get_raw_reg IPA_SYM_EXPORTED_NAME (get_raw_reg)
-# define get_trace_state_variable_value \
-  IPA_SYM_EXPORTED_NAME (get_trace_state_variable_value)
-# define set_trace_state_variable_value \
-  IPA_SYM_EXPORTED_NAME (set_trace_state_variable_value)
+# define get_raw_reg_ptr IPA_SYM_EXPORTED_NAME (get_raw_reg_ptr)
+# define get_trace_state_variable_value_ptr \
+  IPA_SYM_EXPORTED_NAME (get_trace_state_variable_value_ptr)
+# define set_trace_state_variable_value_ptr \
+  IPA_SYM_EXPORTED_NAME (set_trace_state_variable_value_ptr)
 # define ust_loaded IPA_SYM_EXPORTED_NAME (ust_loaded)
 # define helper_thread_id IPA_SYM_EXPORTED_NAME (helper_thread_id)
 # define cmd_buf IPA_SYM_EXPORTED_NAME (cmd_buf)
@@ -150,7 +150,7 @@ struct ipa_sym_addresses
   CORE_ADDR addr_gdb_trampoline_buffer_end;
   CORE_ADDR addr_gdb_trampoline_buffer_error;
   CORE_ADDR addr_collecting;
-  CORE_ADDR addr_gdb_collect;
+  CORE_ADDR addr_gdb_collect_ptr;
   CORE_ADDR addr_stop_tracing;
   CORE_ADDR addr_flush_trace_buffer;
   CORE_ADDR addr_about_to_request_buffer_space;
@@ -168,9 +168,9 @@ struct ipa_sym_addresses
   CORE_ADDR addr_traceframe_write_count;
   CORE_ADDR addr_traceframes_created;
   CORE_ADDR addr_trace_state_variables;
-  CORE_ADDR addr_get_raw_reg;
-  CORE_ADDR addr_get_trace_state_variable_value;
-  CORE_ADDR addr_set_trace_state_variable_value;
+  CORE_ADDR addr_get_raw_reg_ptr;
+  CORE_ADDR addr_get_trace_state_variable_value_ptr;
+  CORE_ADDR addr_set_trace_state_variable_value_ptr;
   CORE_ADDR addr_ust_loaded;
   CORE_ADDR addr_ipa_tdesc_idx;
 };
@@ -187,7 +187,7 @@ static struct
   IPA_SYM(gdb_trampoline_buffer_end),
   IPA_SYM(gdb_trampoline_buffer_error),
   IPA_SYM(collecting),
-  IPA_SYM(gdb_collect),
+  IPA_SYM(gdb_collect_ptr),
   IPA_SYM(stop_tracing),
   IPA_SYM(flush_trace_buffer),
   IPA_SYM(about_to_request_buffer_space),
@@ -205,9 +205,9 @@ static struct
   IPA_SYM(traceframe_write_count),
   IPA_SYM(traceframes_created),
   IPA_SYM(trace_state_variables),
-  IPA_SYM(get_raw_reg),
-  IPA_SYM(get_trace_state_variable_value),
-  IPA_SYM(set_trace_state_variable_value),
+  IPA_SYM(get_raw_reg_ptr),
+  IPA_SYM(get_trace_state_variable_value_ptr),
+  IPA_SYM(set_trace_state_variable_value_ptr),
   IPA_SYM(ust_loaded),
   IPA_SYM(ipa_tdesc_idx),
 };
@@ -3068,6 +3068,7 @@ install_fast_tracepoint (struct tracepoint *tpoint, char *errbuf)
 {
   CORE_ADDR jentry, jump_entry;
   CORE_ADDR trampoline;
+  CORE_ADDR collect;
   ULONGEST trampoline_size;
   int err = 0;
   /* The jump to the jump pad of the last fast tracepoint
@@ -3082,6 +3083,13 @@ install_fast_tracepoint (struct tracepoint *tpoint, char *errbuf)
       return 0;
     }
 
+  if (read_inferior_data_pointer (ipa_sym_addrs.addr_gdb_collect_ptr,
+				  &collect))
+    {
+      error ("error extracting gdb_collect_ptr");
+      return 1;
+    }
+
   jentry = jump_entry = get_jump_space_head ();
 
   trampoline = 0;
@@ -3090,7 +3098,7 @@ install_fast_tracepoint (struct tracepoint *tpoint, char *errbuf)
   /* Install the jump pad.  */
   err = install_fast_tracepoint_jump_pad (tpoint->obj_addr_on_target,
 					  tpoint->address,
-					  ipa_sym_addrs.addr_gdb_collect,
+					  collect,
 					  ipa_sym_addrs.addr_collecting,
 					  tpoint->orig_size,
 					  &jentry,
@@ -5856,6 +5864,25 @@ gdb_collect (struct tracepoint *tpoint, unsigned char *regs)
     }
 }
 
+/* These global variables points to the corresponding functions.  This is
+   necessary on powerpc64, where asking for function symbol address from gdb
+   results in returning the actual code pointer, instead of the descriptor
+   pointer.  */
+
+typedef void (*gdb_collect_ptr_type) (struct tracepoint *, unsigned char *);
+typedef ULONGEST (*get_raw_reg_ptr_type) (const unsigned char *, int);
+typedef LONGEST (*get_trace_state_variable_value_ptr_type) (int);
+typedef void (*set_trace_state_variable_value_ptr_type) (int, LONGEST);
+
+EXTERN_C_PUSH
+IP_AGENT_EXPORT_VAR const gdb_collect_ptr_type gdb_collect_ptr = gdb_collect;
+IP_AGENT_EXPORT_VAR const get_raw_reg_ptr_type get_raw_reg_ptr = get_raw_reg;
+IP_AGENT_EXPORT_VAR const get_trace_state_variable_value_ptr_type
+  get_trace_state_variable_value_ptr = get_trace_state_variable_value;
+IP_AGENT_EXPORT_VAR const set_trace_state_variable_value_ptr_type
+  set_trace_state_variable_value_ptr = set_trace_state_variable_value;
+EXTERN_C_POP
+
 #endif
 
 #ifndef IN_PROCESS_AGENT
@@ -5863,19 +5890,39 @@ gdb_collect (struct tracepoint *tpoint, unsigned char *regs)
 CORE_ADDR
 get_raw_reg_func_addr (void)
 {
-  return ipa_sym_addrs.addr_get_raw_reg;
+  CORE_ADDR res;
+  if (read_inferior_data_pointer (ipa_sym_addrs.addr_get_raw_reg_ptr, &res))
+    {
+      error ("error extracting get_raw_reg_ptr");
+      return 0;
+    }
+  return res;
 }
 
 CORE_ADDR
 get_get_tsv_func_addr (void)
 {
-  return ipa_sym_addrs.addr_get_trace_state_variable_value;
+  CORE_ADDR res;
+  if (read_inferior_data_pointer (
+	ipa_sym_addrs.addr_get_trace_state_variable_value_ptr, &res))
+    {
+      error ("error extracting get_trace_state_variable_value_ptr");
+      return 0;
+    }
+  return res;
 }
 
 CORE_ADDR
 get_set_tsv_func_addr (void)
 {
-  return ipa_sym_addrs.addr_set_trace_state_variable_value;
+  CORE_ADDR res;
+  if (read_inferior_data_pointer (
+	ipa_sym_addrs.addr_set_trace_state_variable_value_ptr, &res))
+    {
+      error ("error extracting set_trace_state_variable_value_ptr");
+      return 0;
+    }
+  return res;
 }
 
 static void
diff --git a/gdb/gdbserver/tracepoint.h b/gdb/gdbserver/tracepoint.h
index e30f4f7..df815ef 100644
--- a/gdb/gdbserver/tracepoint.h
+++ b/gdb/gdbserver/tracepoint.h
@@ -163,8 +163,7 @@ int agent_mem_read_string (struct eval_agent_expr_context *ctx,
 
 /* The prototype the get_raw_reg function in the IPA.  Each arch's
    bytecode compiler emits calls to this function.  */
-IP_AGENT_EXPORT_FUNC ULONGEST gdb_agent_get_raw_reg
-  (const unsigned char *raw_regs, int regnum);
+ULONGEST get_raw_reg (const unsigned char *raw_regs, int regnum);
 
 /* Returns the address of the get_raw_reg function in the IPA.  */
 CORE_ADDR get_raw_reg_func_addr (void);
-- 
2.7.2

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

* Re: [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers.
  2016-03-13  2:32 ` [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers Marcin Kościelnicki
@ 2016-03-14 14:41   ` Ulrich Weigand
  2016-03-14 14:53     ` Marcin Kościelnicki
  2016-03-14 17:08     ` [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers Simon Marchi
  0 siblings, 2 replies; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-14 14:41 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: gdb-patches, Marcin Kościelnicki

Marcin Kościelnicki wrote:

> On powerpc64, qSymbol for a function returns the function code address,
> and not the descriptor address.  Since we emit code calling gdb_collect
> and some other functions, we need the descriptor (no way to know the
> proper TOC address without it).  To get the descriptor address, make
> global function pointer variables in the IPA pointing to the relevant
> functions and read them instead of asking for them directly via qSymbol.

Huh.  This problem already came up last year with Wei-cheng's patches.
See my reply here:
https://sourceware.org/ml/gdb-patches/2015-02/msg00838.html

At the time, I suggested two possible fixes by changing how qSymbol works.
Your approach is yet another fix, however ...

I'm not sure I really like your approach, it seems odd to make common
code jump through "unnatural" hoops just so that powerpc64 works.
On the other hand, your approach certainly involves the least amount
of changes to the current code base.

I am somewhat confused about one thing, though.  In your other patch
https://sourceware.org/ml/gdb-patches/2016-03/msg00201.html
you seem to imply that qSymbol for function symbols simply does not
work at all on powerpc64 at the moment.

If this is true, how does thread-db support work?  This is the one
pre-existing user of qSymbol for function symbols in gdbserver.
I had been under the assumption that this actually works now.  Is
this not in fact true?

If this is indeed just completely broken at the moment, my
preferred fix would actually be to change qSymbol to just return
the function descriptor address (i.e. work as on any other platform)
and have the function descriptor -> function code address lookup
be done on the gdbserver side when necessary for thread-db support.
(This would have been my preferred fix anyway, except for the fact
that it breaks protocol compatibility.  However, if the current
implementation simply doesn't *work*, there's no reason to worry
about compatibility.)

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers.
  2016-03-14 14:41   ` Ulrich Weigand
@ 2016-03-14 14:53     ` Marcin Kościelnicki
  2016-03-14 17:49       ` Ulrich Weigand
  2016-03-14 17:08     ` [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers Simon Marchi
  1 sibling, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-14 14:53 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches

On 14/03/16 15:41, Ulrich Weigand wrote:
> Marcin Kościelnicki wrote:
>
>> On powerpc64, qSymbol for a function returns the function code address,
>> and not the descriptor address.  Since we emit code calling gdb_collect
>> and some other functions, we need the descriptor (no way to know the
>> proper TOC address without it).  To get the descriptor address, make
>> global function pointer variables in the IPA pointing to the relevant
>> functions and read them instead of asking for them directly via qSymbol.
>
> Huh.  This problem already came up last year with Wei-cheng's patches.
> See my reply here:
> https://sourceware.org/ml/gdb-patches/2015-02/msg00838.html
>
> At the time, I suggested two possible fixes by changing how qSymbol works.
> Your approach is yet another fix, however ...
>
> I'm not sure I really like your approach, it seems odd to make common
> code jump through "unnatural" hoops just so that powerpc64 works.
> On the other hand, your approach certainly involves the least amount
> of changes to the current code base.
>
Yeah, I'm not that happy with it either... but we're going to need to 
jump through some hoops in gdbserver anyway - eg. for gdb_collect, we 
need the descriptor address, while for stop_tracing, we need the code 
address.  So we will need some special handling for one of these sets of 
symbols either way, and uglify the common code with it.

> I am somewhat confused about one thing, though.  In your other patch
> https://sourceware.org/ml/gdb-patches/2016-03/msg00201.html
> you seem to imply that qSymbol for function symbols simply does not
> work at all on powerpc64 at the moment.

It works *sometimes* - I'm not sure what it depends on, as I'm not 
familiar with BFD internals, but it seems gdb could have the necessary 
information cached and not need to read the file during qSymbol 
processing.  I, for one, had one hell of a debugging session, since my 
simple test program linked against the IPA had all the IPA symbols 
properly fetched, while the testsuite programs failed at the same. 
Could be something like library load order...
>
> If this is true, how does thread-db support work?  This is the one
> pre-existing user of qSymbol for function symbols in gdbserver.
> I had been under the assumption that this actually works now.  Is
> this not in fact true?
>
> If this is indeed just completely broken at the moment, my
> preferred fix would actually be to change qSymbol to just return
> the function descriptor address (i.e. work as on any other platform)
> and have the function descriptor -> function code address lookup
> be done on the gdbserver side when necessary for thread-db support.
> (This would have been my preferred fix anyway, except for the fact
> that it breaks protocol compatibility.  However, if the current
> implementation simply doesn't *work*, there's no reason to worry
> about compatibility.)

Yep, I thought about it, but there's the protocol compatibility issue...
>
> Bye,
> Ulrich
>

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

* Re: [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers.
  2016-03-14 14:41   ` Ulrich Weigand
  2016-03-14 14:53     ` Marcin Kościelnicki
@ 2016-03-14 17:08     ` Simon Marchi
  2016-03-14 17:40       ` Ulrich Weigand
  1 sibling, 1 reply; 56+ messages in thread
From: Simon Marchi @ 2016-03-14 17:08 UTC (permalink / raw)
  To: Ulrich Weigand, Marcin Kościelnicki; +Cc: gdb-patches, antoine.tremblay

On 16-03-14 10:41 AM, Ulrich Weigand wrote:
> Marcin KoÅ>cielnicki wrote:
> 
>> On powerpc64, qSymbol for a function returns the function code address,
>> and not the descriptor address.  Since we emit code calling gdb_collect
>> and some other functions, we need the descriptor (no way to know the
>> proper TOC address without it).  To get the descriptor address, make
>> global function pointer variables in the IPA pointing to the relevant
>> functions and read them instead of asking for them directly via qSymbol.
> 
> Huh.  This problem already came up last year with Wei-cheng's patches.
> See my reply here:
> https://sourceware.org/ml/gdb-patches/2015-02/msg00838.html
> 
> At the time, I suggested two possible fixes by changing how qSymbol works.
> Your approach is yet another fix, however ...
> 
> I'm not sure I really like your approach, it seems odd to make common
> code jump through "unnatural" hoops just so that powerpc64 works.
> On the other hand, your approach certainly involves the least amount
> of changes to the current code base.
> 
> I am somewhat confused about one thing, though.  In your other patch
> https://sourceware.org/ml/gdb-patches/2016-03/msg00201.html
> you seem to imply that qSymbol for function symbols simply does not
> work at all on powerpc64 at the moment.
> 
> If this is true, how does thread-db support work?  This is the one
> pre-existing user of qSymbol for function symbols in gdbserver.
> I had been under the assumption that this actually works now.  Is
> this not in fact true?
> 
> If this is indeed just completely broken at the moment, my
> preferred fix would actually be to change qSymbol to just return
> the function descriptor address (i.e. work as on any other platform)
> and have the function descriptor -> function code address lookup
> be done on the gdbserver side when necessary for thread-db support.
> (This would have been my preferred fix anyway, except for the fact
> that it breaks protocol compatibility.  However, if the current
> implementation simply doesn't *work*, there's no reason to worry
> about compatibility.)
> 
> Bye,
> Ulrich

Since we are working on fast tracepoints for ARM, I can provide an
additional data point to the discussion.  We have a similar problem,
that is when generating the branch to gdb_collect, we need to know
whether gdb_collect is an ARM or Thumb symbol.  If the symbol is an
ARM one, the branch instruction must jump to an even address
(e.g. 0xd3c8), whereas if the symbol is Thumb, the destination address
must have its bit 0 set (e.g. 0xd3c9).

To achieve this, we extended qSymbol to allow sending the symbol target
flags (coming from MSYMBOL_TARGET_FLAG_{1,2}).  Those flags are target/arch
specific.  In the case of ARM, one of them indicates that the symbol is
a Thumb one.  This solution works well, but we also have to think about
backwards compatibility of the protocol.  It shouldn't be too complicated
however, since we are adding an optional field.

On the other hand, Marcin's solution would work as well for the ARM
architecture.  The compiler would place the right value in gdb_collect_ptr,
regardless of whether gdb_collect is an ARM (bit 0 cleared) or a Thumb
(bit 0 set) symbol.

Simon

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

* Re: [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers.
  2016-03-14 17:08     ` [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers Simon Marchi
@ 2016-03-14 17:40       ` Ulrich Weigand
  0 siblings, 0 replies; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-14 17:40 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Marcin Kościelnicki, gdb-patches, antoine.tremblay

Simon Marchi wrote:

> Since we are working on fast tracepoints for ARM, I can provide an
> additional data point to the discussion.  We have a similar problem,
> that is when generating the branch to gdb_collect, we need to know
> whether gdb_collect is an ARM or Thumb symbol.  If the symbol is an
> ARM one, the branch instruction must jump to an even address
> (e.g. 0xd3c8), whereas if the symbol is Thumb, the destination address
> must have its bit 0 set (e.g. 0xd3c9).

Thanks for the additional info, that's quite interesting as well!
 
> To achieve this, we extended qSymbol to allow sending the symbol target
> flags (coming from MSYMBOL_TARGET_FLAG_{1,2}).  Those flags are target/arch
> specific.  In the case of ARM, one of them indicates that the symbol is
> a Thumb one.  This solution works well, but we also have to think about
> backwards compatibility of the protocol.  It shouldn't be too complicated
> however, since we are adding an optional field.
> 
> On the other hand, Marcin's solution would work as well for the ARM
> architecture.  The compiler would place the right value in gdb_collect_ptr,
> regardless of whether gdb_collect is an ARM (bit 0 cleared) or a Thumb
> (bit 0 set) symbol.

This is similar to the second option I suggested last year, which was
to add an extra field to qSymbol so it could return both a code address
*and* a function pointer value for function symbols.

This it seems would work for your case too, since you could determine
ARM vs. Thumb from the function pointer value.

On the other hand, I'm now wondering if it makes sense to add extra
protocol support to provide function pointer values, when we can just
as well use Marcin's trick to simply read a function pointer ...

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers.
  2016-03-14 14:53     ` Marcin Kościelnicki
@ 2016-03-14 17:49       ` Ulrich Weigand
  2016-03-22  9:19         ` Marcin Kościelnicki
  0 siblings, 1 reply; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-14 17:49 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: gdb-patches

Marcin Kościelnicki wrote:
> On 14/03/16 15:41, Ulrich Weigand wrote:
> > I'm not sure I really like your approach, it seems odd to make common
> > code jump through "unnatural" hoops just so that powerpc64 works.
> > On the other hand, your approach certainly involves the least amount
> > of changes to the current code base.
> >
> Yeah, I'm not that happy with it either... but we're going to need to 
> jump through some hoops in gdbserver anyway - eg. for gdb_collect, we 
> need the descriptor address, while for stop_tracing, we need the code 
> address.  So we will need some special handling for one of these sets of 
> symbols either way, and uglify the common code with it.

That's certainly true as well.  Also, implementing the descriptor to
code address lookup in exactly the same way as GDB does might be
difficult for gdbserver to do, since it is currently reading the BFD,
which gdbserver doesn't have available.

> > I am somewhat confused about one thing, though.  In your other patch
> > https://sourceware.org/ml/gdb-patches/2016-03/msg00201.html
> > you seem to imply that qSymbol for function symbols simply does not
> > work at all on powerpc64 at the moment.
> 
> It works *sometimes* - I'm not sure what it depends on, as I'm not 
> familiar with BFD internals, but it seems gdb could have the necessary 
> information cached and not need to read the file during qSymbol 
> processing.  I, for one, had one hell of a debugging session, since my 
> simple test program linked against the IPA had all the IPA symbols 
> properly fetched, while the testsuite programs failed at the same. 
> Could be something like library load order...

Hmm.  I just checked, and it turns out that as of Dec 2015 gdbserver
actually no longer even uses the td_ta_set_event libthread_db
callback at all.  Instead, it now always relies on PTRACE_EVENT_CLONE
to detect new inferior threads.  This means that thread support
shouldn't actually require qSymbol on a function symbol any more.

In addition, it probably used to work in the past because GDB only
uses the vFile packet when it is reading the target libraries from
the target itself.  In past, GDB usually required copies of the
target libraries to be present on the host system as well, and
used them from there.  While there was support for loading target
libraries remotely for a while, it was only made default about
a year ago.


> Yep, I thought about it, but there's the protocol compatibility issue...

The more I think about it, the more I tend to agree that your
proposal is actually the best solution.  I'd still like to give
it a couple of days to give others a chance to comment as well ...

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* [PATCH 3/4 v2] gdbserver: Add powerpc fast tracepoint support.
  2016-03-13  2:32 ` [PATCH 3/3] " Marcin Kościelnicki
@ 2016-03-14 22:10   ` Marcin Kościelnicki
  2016-03-16 16:58     ` Ulrich Weigand
  0 siblings, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-14 22:10 UTC (permalink / raw)
  To: gdb-patches; +Cc: Marcin Kościelnicki

gdb/gdbserver/ChangeLog:

2016-03-13  Wei-cheng Wang  <cole945@gmail.com>
	    Marcin Kościelnicki  <koriakin@0x04.net>

	* Makefile.in: Add powerpc-*-ipa.o
	* configure.srv: Add ipa_obj for powerpc*-linux.
	* linux-ppc-ipa.c: New file.
	* linux-ppc-low.c: Added linux-ppc-tdesc.h, ax.h,
	tracepoint.h includes.
	(PPC_FIELD): New macro.
	(PPC_SEXT): New macro.
	(PPC_OP6): New macro.
	(PPC_BO): New macro.
	(PPC_LI): New macro.
	(PPC_BD): New macro.
	(init_registers_*): Move prototype to linux-ppc-tdesc.h.
	(tdesc_*): Move declaration to linux-ppc-tdesc.h.
	(ppc_get_thread_area): New function.
	(gen_ds_form): New function.
	(GEN_STD): New macro.
	(GEN_STDU): New macro.
	(GEN_LD): New macro.
	(GEN_LDU): New macro.
	(gen_d_form): New function.
	(GEN_ADDI): New macro.
	(GEN_ADDIS): New macro.
	(GEN_LI): New macro.
	(GEN_LIS): New macro.
	(GEN_ORI): New macro.
	(GEN_ORIS): New macro.
	(GEN_LWZ): New macro.
	(GEN_STW): New macro.
	(GEN_STWU): New macro.
	(gen_xfx_form): New function.
	(GEN_MFSPR): New macro.
	(GEN_MTSPR): New macro.
	(GEN_MFCR): New macro.
	(GEN_MTCR): New macro.
	(GEN_SYNC): New macro.
	(GEN_LWSYNC): New macro.
	(gen_x_form): New function.
	(GEN_OR): New macro.
	(GEN_MR): New macro.
	(GEN_LWARX): New macro.
	(GEN_STWCX): New macro.
	(GEN_CMPW): New macro.
	(gen_md_form): New function.
	(GEN_RLDICL): New macro.
	(GEN_RLDICR): New macro.
	(gen_i_form): New function.
	(GEN_B): New macro.
	(GEN_BL): New macro.
	(gen_b_form): New function.
	(GEN_BNE): New macro.
	(GEN_LOAD): New macro.
	(GEN_STORE): New macro.
	(gen_limm): New function.
	(gen_atomic_xchg): New function.
	(gen_call): New function.
	(ppc_relocate_instruction): New function.
	(ppc_install_fast_tracepoint_jump_pad): New function.
	(ppc_get_min_fast_tracepoint_insn_len): New function.
	(ppc_get_ipa_tdesc_idx): New function.
	(the_low_target): Wire in the new functions.
	(initialize_low_arch) [!__powerpc64__]: Don'it initialize 64-bit
	tdescs.
	* linux-ppc-tdesc.h: New file.
---
This fixes get_raw_reg for 32-bit (ULONGEST was used to read the
registers dumped by jump pad instead of unsigned long).  Also slightly
optimizes gen_limm and fixes a few comments.

 gdb/gdbserver/ChangeLog         |  67 ++++
 gdb/gdbserver/Makefile.in       |  48 +++
 gdb/gdbserver/configure.srv     |   2 +
 gdb/gdbserver/linux-ppc-ipa.c   | 238 +++++++++++
 gdb/gdbserver/linux-ppc-low.c   | 853 +++++++++++++++++++++++++++++++++++++---
 gdb/gdbserver/linux-ppc-tdesc.h | 101 +++++
 6 files changed, 1246 insertions(+), 63 deletions(-)
 create mode 100644 gdb/gdbserver/linux-ppc-ipa.c
 create mode 100644 gdb/gdbserver/linux-ppc-tdesc.h

diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 4a4a9bf..a6bba77 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,70 @@
+2016-03-13  Wei-cheng Wang  <cole945@gmail.com>
+	    Marcin Kościelnicki  <koriakin@0x04.net>
+
+	* Makefile.in: Add powerpc-*-ipa.o
+	* configure.srv: Add ipa_obj for powerpc*-linux.
+	* linux-ppc-ipa.c: New file.
+	* linux-ppc-low.c: Added linux-ppc-tdesc.h, ax.h,
+	tracepoint.h includes.
+	(PPC_FIELD): New macro.
+	(PPC_SEXT): New macro.
+	(PPC_OP6): New macro.
+	(PPC_BO): New macro.
+	(PPC_LI): New macro.
+	(PPC_BD): New macro.
+	(init_registers_*): Move prototype to linux-ppc-tdesc.h.
+	(tdesc_*): Move declaration to linux-ppc-tdesc.h.
+	(ppc_get_thread_area): New function.
+	(gen_ds_form): New function.
+	(GEN_STD): New macro.
+	(GEN_STDU): New macro.
+	(GEN_LD): New macro.
+	(GEN_LDU): New macro.
+	(gen_d_form): New function.
+	(GEN_ADDI): New macro.
+	(GEN_ADDIS): New macro.
+	(GEN_LI): New macro.
+	(GEN_LIS): New macro.
+	(GEN_ORI): New macro.
+	(GEN_ORIS): New macro.
+	(GEN_LWZ): New macro.
+	(GEN_STW): New macro.
+	(GEN_STWU): New macro.
+	(gen_xfx_form): New function.
+	(GEN_MFSPR): New macro.
+	(GEN_MTSPR): New macro.
+	(GEN_MFCR): New macro.
+	(GEN_MTCR): New macro.
+	(GEN_SYNC): New macro.
+	(GEN_LWSYNC): New macro.
+	(gen_x_form): New function.
+	(GEN_OR): New macro.
+	(GEN_MR): New macro.
+	(GEN_LWARX): New macro.
+	(GEN_STWCX): New macro.
+	(GEN_CMPW): New macro.
+	(gen_md_form): New function.
+	(GEN_RLDICL): New macro.
+	(GEN_RLDICR): New macro.
+	(gen_i_form): New function.
+	(GEN_B): New macro.
+	(GEN_BL): New macro.
+	(gen_b_form): New function.
+	(GEN_BNE): New macro.
+	(GEN_LOAD): New macro.
+	(GEN_STORE): New macro.
+	(gen_limm): New function.
+	(gen_atomic_xchg): New function.
+	(gen_call): New function.
+	(ppc_relocate_instruction): New function.
+	(ppc_install_fast_tracepoint_jump_pad): New function.
+	(ppc_get_min_fast_tracepoint_insn_len): New function.
+	(ppc_get_ipa_tdesc_idx): New function.
+	(the_low_target): Wire in the new functions.
+	(initialize_low_arch) [!__powerpc64__]: Don'it initialize 64-bit
+	tdescs.
+	* linux-ppc-tdesc.h: New file.
+
 2016-03-13  Marcin Kościelnicki  <koriakin@0x04.net>
 
 	* linux-aarch64-ipa.c: Add <sys/mman.h> include.
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 257e9bf..11908d2 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -531,6 +531,54 @@ linux-aarch64-ipa.o: linux-aarch64-ipa.c
 aarch64-ipa.o: aarch64.c
 	$(IPAGENT_COMPILE) $<
 	$(POSTCOMPILE)
+linux-ppc-ipa.o: linux-ppc-ipa.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-32l-ipa.o: powerpc-32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-altivec32l-ipa.o: powerpc-altivec32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-cell32l-ipa.o: powerpc-cell32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-vsx32l-ipa.o: powerpc-vsx32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-32l-ipa.o: powerpc-isa205-32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-altivec32l-ipa.o: powerpc-isa205-altivec32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-vsx32l-ipa.o: powerpc-isa205-vsx32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-e500l-ipa.o: powerpc-e500l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-64l-ipa.o: powerpc-64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-altivec64l-ipa.o: powerpc-altivec64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-cell64l-ipa.o: powerpc-cell64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-vsx64l-ipa.o: powerpc-vsx64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-64l-ipa.o: powerpc-isa205-64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-altivec64l-ipa.o: powerpc-isa205-altivec64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-vsx64l-ipa.o: powerpc-isa205-vsx64l.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 a89b1d1..177e0a3 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -31,6 +31,7 @@ srv_amd64_linux_regobj="amd64-linux.o amd64-avx-linux.o amd64-avx512-linux.o amd
 
 ipa_i386_linux_regobj="i386-linux-ipa.o i386-avx-linux-ipa.o i386-avx512-linux-ipa.o i386-mpx-linux-ipa.o i386-mmx-linux-ipa.o"
 ipa_amd64_linux_regobj="amd64-linux-ipa.o amd64-avx-linux-ipa.o amd64-avx512-linux-ipa.o amd64-mpx-linux-ipa.o"
+ipa_ppc_linux_regobj="powerpc-32l-ipa.o powerpc-altivec32l-ipa.o powerpc-cell32l-ipa.o powerpc-vsx32l-ipa.o powerpc-isa205-32l-ipa.o powerpc-isa205-altivec32l-ipa.o powerpc-isa205-vsx32l-ipa.o powerpc-e500l-ipa.o powerpc-64l-ipa.o powerpc-altivec64l-ipa.o powerpc-cell64l-ipa.o powerpc-vsx64l-ipa.o powerpc-isa205-64l-ipa.o powerpc-isa205-altivec64l-ipa.o powerpc-isa205-vsx64l-ipa.o"
 
 srv_i386_32bit_xmlfiles="i386/32bit-core.xml i386/32bit-sse.xml i386/32bit-avx.xml i386/32bit-avx512.xml i386/32bit-mpx.xml"
 srv_i386_64bit_xmlfiles="i386/64bit-core.xml i386/64bit-sse.xml i386/64bit-avx.xml i386/64bit-avx512.xml i386/x32-core.xml i386/64bit-mpx.xml"
@@ -258,6 +259,7 @@ case "${target}" in
 			srv_linux_usrregs=yes
 			srv_linux_regsets=yes
 			srv_linux_thread_db=yes
+			ipa_obj="${ipa_ppc_linux_regobj} 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..ab2de82
--- /dev/null
+++ b/gdb/gdbserver/linux-ppc-ipa.c
@@ -0,0 +1,238 @@
+/* GNU/Linux/PowerPC specific low level interface, for the in-process
+   agent library for GDB.
+
+   Copyright (C) 2016 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 <sys/mman.h>
+#include "tracepoint.h"
+#include "linux-ppc-tdesc.h"
+
+/* 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] * sizeof (long));
+    }
+}
+
+/* Return the value of register REGNUM.  RAW_REGS is collected buffer
+   by jump pad.  This function is called by emit_reg.  */
+
+ULONGEST
+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 *(unsigned long *) (raw_regs
+			     + ppc_ft_collect_regmap[regnum] * sizeof (long));
+}
+
+/* Allocate buffer for the jump pads.  The branch instruction has a reach
+   of +/- 32MiB, and the executable is loaded at 0x10000000 (256MiB).
+
+   64-bit: To maximize the area of executable that can use tracepoints,
+   try allocating at 0x10000000 - size initially, decreasing until we hit
+   a free area.
+
+   32-bit: ld.so loads dynamic libraries right below the executable, so
+   we cannot depend on that area (dynamic libraries can be quite large).
+   Instead, aim right after the executable - at sbrk(0).  This will
+   cause future brk to fail, and malloc will fallback to mmap.  */
+
+void *
+alloc_jump_pad_buffer (size_t size)
+{
+#ifdef __powerpc64__
+  uintptr_t addr;
+  int pagesize;
+  void *res;
+
+  pagesize = sysconf (_SC_PAGE_SIZE);
+  if (pagesize == -1)
+    perror_with_name ("sysconf");
+
+  addr = 0x10000000 - size;
+
+  /* size should already be page-aligned, but this can't hurt.  */
+  addr &= ~(pagesize - 1);
+
+  /* Search for a free area.  If we hit 0, we're out of luck.  */
+  for (; addr; addr -= pagesize)
+    {
+      /* No MAP_FIXED - we don't want to zap someone's mapping.  */
+      res = mmap ((void *) addr, size,
+		  PROT_READ | PROT_WRITE | PROT_EXEC,
+		  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+      /* If we got what we wanted, return.  */
+      if ((uintptr_t) res == addr)
+	return res;
+
+      /* If we got a mapping, but at a wrong address, undo it.  */
+      if (res != MAP_FAILED)
+	munmap (res, size);
+    }
+
+  return NULL;
+#else
+  void *target = sbrk (0);
+  void *res = mmap (target, size, PROT_READ | PROT_WRITE | PROT_EXEC,
+		    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+  if (res == target)
+    return res;
+
+  if (res != MAP_FAILED)
+    munmap (res, size);
+
+  return NULL;
+#endif
+}
+
+/* Return target_desc to use for IPA, given the tdesc index passed by
+   gdbserver.  */
+
+const struct target_desc *
+get_ipa_tdesc (int idx)
+{
+  switch (idx)
+    {
+#ifdef __powerpc64__
+    case PPC_TDESC_BASE:
+      return tdesc_powerpc_64l;
+    case PPC_TDESC_ALTIVEC:
+      return tdesc_powerpc_altivec64l;
+    case PPC_TDESC_CELL:
+      return tdesc_powerpc_cell64l;
+    case PPC_TDESC_VSX:
+      return tdesc_powerpc_vsx64l;
+    case PPC_TDESC_ISA205:
+      return tdesc_powerpc_isa205_64l;
+    case PPC_TDESC_ISA205_ALTIVEC:
+      return tdesc_powerpc_isa205_altivec64l;
+    case PPC_TDESC_ISA205_VSX:
+      return tdesc_powerpc_isa205_vsx64l;
+#else
+    case PPC_TDESC_BASE:
+      return tdesc_powerpc_32l;
+    case PPC_TDESC_ALTIVEC:
+      return tdesc_powerpc_altivec32l;
+    case PPC_TDESC_CELL:
+      return tdesc_powerpc_cell32l;
+    case PPC_TDESC_VSX:
+      return tdesc_powerpc_vsx32l;
+    case PPC_TDESC_ISA205:
+      return tdesc_powerpc_isa205_32l;
+    case PPC_TDESC_ISA205_ALTIVEC:
+      return tdesc_powerpc_isa205_altivec32l;
+    case PPC_TDESC_ISA205_VSX:
+      return tdesc_powerpc_isa205_vsx32l;
+    case PPC_TDESC_E500:
+      return tdesc_powerpc_e500l;
+#endif
+    default:
+      internal_error (__FILE__, __LINE__,
+                     "unknown ipa tdesc index: %d", idx);
+#ifdef __powerpc64__
+      return tdesc_powerpc_64l;
+#else
+      return tdesc_powerpc_32l;
+#endif
+    }
+}
+
+
+/* Initialize ipa_tdesc and others.  */
+
+void
+initialize_low_tracepoint (void)
+{
+#ifdef __powerpc64__
+  init_registers_powerpc_64l ();
+  init_registers_powerpc_altivec64l ();
+  init_registers_powerpc_cell64l ();
+  init_registers_powerpc_vsx64l ();
+  init_registers_powerpc_isa205_64l ();
+  init_registers_powerpc_isa205_altivec64l ();
+  init_registers_powerpc_isa205_vsx64l ();
+#else
+  init_registers_powerpc_32l ();
+  init_registers_powerpc_altivec32l ();
+  init_registers_powerpc_cell32l ();
+  init_registers_powerpc_vsx32l ();
+  init_registers_powerpc_isa205_32l ();
+  init_registers_powerpc_isa205_altivec32l ();
+  init_registers_powerpc_isa205_vsx32l ();
+  init_registers_powerpc_e500l ();
+#endif
+}
diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c
index 49d27ee..2b3630f 100644
--- a/gdb/gdbserver/linux-ppc-low.c
+++ b/gdb/gdbserver/linux-ppc-low.c
@@ -24,70 +24,24 @@
 #include <asm/ptrace.h>
 
 #include "nat/ppc-linux.h"
+#include "linux-ppc-tdesc.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;
 
 
-/* Defined in auto-generated file powerpc-32l.c.  */
-void init_registers_powerpc_32l (void);
-extern const struct target_desc *tdesc_powerpc_32l;
-
-/* Defined in auto-generated file powerpc-altivec32l.c.  */
-void init_registers_powerpc_altivec32l (void);
-extern const struct target_desc *tdesc_powerpc_altivec32l;
-
-/* Defined in auto-generated file powerpc-cell32l.c.  */
-void init_registers_powerpc_cell32l (void);
-extern const struct target_desc *tdesc_powerpc_cell32l;
-
-/* Defined in auto-generated file powerpc-vsx32l.c.  */
-void init_registers_powerpc_vsx32l (void);
-extern const struct target_desc *tdesc_powerpc_vsx32l;
-
-/* Defined in auto-generated file powerpc-isa205-32l.c.  */
-void init_registers_powerpc_isa205_32l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_32l;
-
-/* Defined in auto-generated file powerpc-isa205-altivec32l.c.  */
-void init_registers_powerpc_isa205_altivec32l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_altivec32l;
-
-/* Defined in auto-generated file powerpc-isa205-vsx32l.c.  */
-void init_registers_powerpc_isa205_vsx32l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_vsx32l;
-
-/* Defined in auto-generated file powerpc-e500l.c.  */
-void init_registers_powerpc_e500l (void);
-extern const struct target_desc *tdesc_powerpc_e500l;
-
-/* Defined in auto-generated file powerpc-64l.c.  */
-void init_registers_powerpc_64l (void);
-extern const struct target_desc *tdesc_powerpc_64l;
-
-/* Defined in auto-generated file powerpc-altivec64l.c.  */
-void init_registers_powerpc_altivec64l (void);
-extern const struct target_desc *tdesc_powerpc_altivec64l;
-
-/* Defined in auto-generated file powerpc-cell64l.c.  */
-void init_registers_powerpc_cell64l (void);
-extern const struct target_desc *tdesc_powerpc_cell64l;
-
-/* Defined in auto-generated file powerpc-vsx64l.c.  */
-void init_registers_powerpc_vsx64l (void);
-extern const struct target_desc *tdesc_powerpc_vsx64l;
-
-/* Defined in auto-generated file powerpc-isa205-64l.c.  */
-void init_registers_powerpc_isa205_64l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_64l;
-
-/* Defined in auto-generated file powerpc-isa205-altivec64l.c.  */
-void init_registers_powerpc_isa205_altivec64l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_altivec64l;
-
-/* Defined in auto-generated file powerpc-isa205-vsx64l.c.  */
-void init_registers_powerpc_isa205_vsx64l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_vsx64l;
-
 #define ppc_num_regs 73
 
 #ifdef __powerpc64__
@@ -756,12 +710,781 @@ ppc_arch_setup (void)
   current_process ()->tdesc = tdesc;
 }
 
+/* Implementation of linux_target_ops method "supports_tracepoints".  */
+
 static int
 ppc_supports_tracepoints (void)
 {
   return 1;
 }
 
+/* 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)
+{
+#ifdef __powerpc64__
+  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);
+  int is_64 = register_size (regcache->tdesc, 0) == 8;
+#endif
+  long res;
+
+#ifdef __powerpc64__
+  if (is_64)
+    res = ptrace (PTRACE_PEEKUSER, lwpid, (long) PT_R13 * sizeof (long),
+		  (long) 0);
+  else
+#endif
+    res = ptrace (PTRACE_PEEKUSER, lwpid, (long) PT_R2 * sizeof (long),
+		  (long) 0);
+
+  if (res == -1)
+    return -1;
+
+  *addr = res;
+
+#ifdef __powerpc64__
+  if (!is_64)
+    *addr &= 0xffffffffull;
+#endif
+
+  return 0;
+}
+
+/* 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)
+#define GEN_STWU(buf, rt, ra, si)	gen_d_form (buf, 37, rt, ra, si)
+
+/* Generate a xfx-form instruction in BUF and return the number of bytes
+   written.
+
+   0      6     11         21        31 32
+   | OPCD | RST |    RI    |    XO   |/|  */
+
+static int
+gen_xfx_form (uint32_t *buf, int opcd, int rst, int ri, int xo)
+{
+  uint32_t insn;
+  unsigned int n = ((ri & 0x1f) << 5) | ((ri >> 5) & 0x1f);
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((rst & ~0x1f) == 0);
+  gdb_assert ((xo & ~0x3ff) == 0);
+
+  insn = (rst << 21) | (n << 11) | (xo << 1);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* Followings are frequently used xfx-form instructions.  */
+
+#define GEN_MFSPR(buf, rt, spr)		gen_xfx_form (buf, 31, rt, spr, 339)
+#define GEN_MTSPR(buf, rt, spr)		gen_xfx_form (buf, 31, rt, spr, 467)
+#define GEN_MFCR(buf, rt)		gen_xfx_form (buf, 31, rt, 0, 19)
+#define GEN_MTCR(buf, rt)		gen_xfx_form (buf, 31, rt, 0x3cf, 144)
+#define GEN_SYNC(buf, L, E)             gen_xfx_form (buf, 31, L & 0x3, \
+						      E & 0xf, 598)
+#define GEN_LWSYNC(buf)			GEN_SYNC (buf, 1, 0)
+
+
+/* Generate a x-form instruction in BUF and return the number of bytes written.
+
+   0      6     11   16   21       31 32
+   | OPCD | RST | RA | RB |   XO   |RC|  */
+
+static int
+gen_x_form (uint32_t *buf, int opcd, int rst, int ra, int rb, int xo, int rc)
+{
+  uint32_t insn;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((rst & ~0x1f) == 0);
+  gdb_assert ((ra & ~0x1f) == 0);
+  gdb_assert ((rb & ~0x1f) == 0);
+  gdb_assert ((xo & ~0x3ff) == 0);
+  gdb_assert ((rc & ~1) == 0);
+
+  insn = (rst << 21) | (ra << 16) | (rb << 11) | (xo << 1) | rc;
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* Followings are frequently used x-form instructions.  */
+
+#define GEN_OR(buf, ra, rs, rb)		gen_x_form (buf, 31, rs, ra, rb, 444, 0)
+#define GEN_MR(buf, ra, rs)		GEN_OR (buf, ra, rs, rs)
+#define GEN_LWARX(buf, rt, ra, rb)	gen_x_form (buf, 31, rt, ra, rb, 20, 0)
+#define GEN_STWCX(buf, rs, ra, rb)	gen_x_form (buf, 31, rs, ra, rb, 150, 1)
+/* Assume bf = cr7.  */
+#define GEN_CMPW(buf, ra, rb)		gen_x_form (buf, 31, 28, ra, rb, 0, 0)
+
+
+/* Generate a md-form instruction in BUF and return the number of bytes written.
+
+   0      6    11   16   21   27   30 31 32
+   | OPCD | RS | RA | sh | mb | XO |sh|Rc|  */
+
+static int
+gen_md_form (uint32_t *buf, int opcd, int rs, int ra, int sh, int mb,
+	     int xo, int rc)
+{
+  uint32_t insn;
+  unsigned int n = ((mb & 0x1f) << 1) | ((mb >> 5) & 0x1);
+  unsigned int sh0_4 = sh & 0x1f;
+  unsigned int sh5 = (sh >> 5) & 1;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((rs & ~0x1f) == 0);
+  gdb_assert ((ra & ~0x1f) == 0);
+  gdb_assert ((sh & ~0x3f) == 0);
+  gdb_assert ((mb & ~0x3f) == 0);
+  gdb_assert ((xo & ~0x7) == 0);
+  gdb_assert ((rc & ~0x1) == 0);
+
+  insn = (rs << 21) | (ra << 16) | (sh0_4 << 11) | (n << 5)
+	 | (sh5 << 1) | (xo << 2) | (rc & 1);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* The following are frequently used md-form instructions.  */
+
+#define GEN_RLDICL(buf, ra, rs ,sh, mb) \
+				gen_md_form (buf, 30, rs, ra, sh, mb, 0, 0)
+#define GEN_RLDICR(buf, ra, rs ,sh, mb) \
+				gen_md_form (buf, 30, rs, ra, sh, mb, 1, 0)
+
+/* Generate a i-form instruction in BUF and return the number of bytes written.
+
+   0      6                          30 31 32
+   | OPCD |            LI            |AA|LK|  */
+
+static int
+gen_i_form (uint32_t *buf, int opcd, int li, int aa, int lk)
+{
+  uint32_t insn;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+
+  insn = (li & 0x3fffffc) | (aa & 1) | (lk & 1);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* The following are frequently used i-form instructions.  */
+
+#define GEN_B(buf, li)		gen_i_form (buf, 18, li, 0, 0)
+#define GEN_BL(buf, li)		gen_i_form (buf, 18, li, 0, 1)
+
+/* Generate a b-form instruction in BUF and return the number of bytes written.
+
+   0      6    11   16               30 31 32
+   | OPCD | BO | BI |      BD        |AA|LK|  */
+
+static int
+gen_b_form (uint32_t *buf, int opcd, int bo, int bi, int bd,
+	    int aa, int lk)
+{
+  uint32_t insn;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((bo & ~0x1f) == 0);
+  gdb_assert ((bi & ~0x1f) == 0);
+
+  insn = (bo << 21) | (bi << 16) | (bd & 0xfffc) | (aa & 1) | (lk & 1);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* The following are frequently used b-form instructions.  */
+/* Assume bi = cr7.  */
+#define GEN_BNE(buf, bd)  gen_b_form (buf, 16, 0x4, (7 << 2) | 2, bd, 0 ,0)
+
+/* GEN_LOAD and GEN_STORE generate 64- or 32-bit load/store for ppc64 or ppc32
+   respectively.  They are primary used for save/restore GPRs in jump-pad,
+   not used for bytecode compiling.  */
+
+#if defined __powerpc64__
+#define GEN_LOAD(buf, rt, ra, si)	(is_64 ? GEN_LD (buf, rt, ra, si) : \
+						 GEN_LWZ (buf, rt, ra, si))
+#define GEN_STORE(buf, rt, ra, si)	(is_64 ? GEN_STD (buf, rt, ra, si) : \
+						 GEN_STW (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, int is_64)
+{
+  uint32_t *p = buf;
+
+  if ((imm + 32768) < 65536)
+    {
+      /* li	reg, imm[15:0] */
+      p += GEN_LI (p, reg, imm);
+    }
+  else if ((imm >> 32) == 0)
+    {
+      /* lis	reg, imm[31:16]
+	 ori	reg, reg, imm[15:0]
+	 rldicl reg, reg, 0, 32 */
+      p += GEN_LIS (p, reg, (imm >> 16) & 0xffff);
+      if ((imm & 0xffff) != 0)
+	p += GEN_ORI (p, reg, reg, imm & 0xffff);
+      /* Clear upper 32-bit if sign-bit is set.  */
+      if (imm & (1u << 31) && is_64)
+	p += GEN_RLDICL (p, reg, reg, 0, 32);
+    }
+  else
+    {
+      gdb_assert (is_64);
+      /* 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));
+      if (((imm >> 32) & 0xffff) != 0)
+        p += GEN_ORI (p, reg, reg, ((imm >> 32) & 0xffff));
+      p += GEN_RLDICR (p, reg, reg, 32, 31);
+      if (((imm >> 16) & 0xffff) != 0)
+        p += GEN_ORIS (p, reg, reg, ((imm >> 16) & 0xffff));
+      if ((imm & 0xffff) != 0)
+        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,
+		 int is_64)
+{
+  const int r_lock = 6;
+  const int r_old = 7;
+  const int r_tmp = 8;
+  uint32_t *p = buf;
+
+  /*
+  1: lwarx   TMP, 0, LOCK
+     cmpwi   TMP, OLD
+     bne     1b
+     stwcx.  NEW, 0, LOCK
+     bne     1b */
+
+  p += gen_limm (p, r_lock, lock, is_64);
+  p += gen_limm (p, r_old, old_value, is_64);
+
+  p += GEN_LWARX (p, r_tmp, 0, r_lock);
+  p += GEN_CMPW (p, r_tmp, r_old);
+  p += GEN_BNE (p, -8);
+  p += GEN_STWCX (p, r_new, 0, r_lock);
+  p += GEN_BNE (p, -16);
+
+  return p - buf;
+}
+
+/* Generate a sequence of instructions for calling a function
+   at address of FN.  Return the number of bytes are written in BUF.  */
+
+static int
+gen_call (uint32_t *buf, CORE_ADDR fn, int is_64, int is_opd)
+{
+  uint32_t *p = buf;
+
+  /* Must be called by r12 for caller to calculate TOC address. */
+  p += gen_limm (p, 12, fn, is_64);
+  if (is_opd)
+    {
+      p += GEN_LOAD (p, 11, 12, 16);
+      p += GEN_LOAD (p, 2, 12, 8);
+      p += GEN_LOAD (p, 12, 12, 0);
+    }
+  p += GEN_MTSPR (p, 12, 9);		/* mtctr  r12 */
+  *p++ = 0x4e800421;			/* bctrl */
+
+  return p - buf;
+}
+
+/* Copy the instruction from OLDLOC to *TO, and update *TO to *TO + size
+   of instruction.  This function is used to adjust pc-relative instructions
+   when copying.  */
+
+static void
+ppc_relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc)
+{
+  uint32_t insn, op6;
+  long rel, newrel;
+
+  read_inferior_memory (oldloc, (unsigned char *) &insn, 4);
+  op6 = PPC_OP6 (insn);
+
+  if (op6 == 18 && (insn & 2) == 0)
+    {
+      /* branch && AA = 0 */
+      rel = PPC_LI (insn);
+      newrel = (oldloc - *to) + rel;
+
+      /* Out of range. Cannot relocate instruction.  */
+      if (newrel >= (1 << 25) || newrel < -(1 << 25))
+	return;
+
+      insn = (insn & ~0x3fffffc) | (newrel & 0x3fffffc);
+    }
+  else if (op6 == 16 && (insn & 2) == 0)
+    {
+      /* conditional branch && AA = 0 */
+
+      /* If the new relocation is too big for even a 26-bit unconditional
+	 branch, there is nothing we can do.  Just abort.
+
+	 Otherwise, if it can be fit in 16-bit conditional branch, just
+	 copy the instruction and relocate the address.
+
+	 If the it's  big for conditional-branch (16-bit), try to invert the
+	 condition and jump with 26-bit branch.  For example,
+
+	 beq  .Lgoto
+	 INSN1
+
+	 =>
+
+	 bne  1f (+8)
+	 b    .Lgoto
+       1:INSN1
+
+	 After this transform, we are actually jump from *TO+4 instead of *TO,
+	 so check the relocation again because it will be 1-insn farther then
+	 before if *TO is after OLDLOC.
+
+
+	 For BDNZT (or so) is transformed from
+
+	 bdnzt  eq, .Lgoto
+	 INSN1
+
+	 =>
+
+	 bdz    1f (+12)
+	 bf     eq, 1f (+8)
+	 b      .Lgoto
+       1:INSN1
+
+	 See also "BO field encodings".  */
+
+      rel = PPC_BD (insn);
+      newrel = (oldloc - *to) + rel;
+
+      if (newrel < (1 << 15) && newrel >= -(1 << 15))
+	insn = (insn & ~0xfffc) | (newrel & 0xfffc);
+      else if ((PPC_BO (insn) & 0x14) == 0x4 || (PPC_BO (insn) & 0x14) == 0x10)
+	{
+	  newrel -= 4;
+
+	  /* Out of range. Cannot relocate instruction.  */
+	  if (newrel >= (1 << 25) || newrel < -(1 << 25))
+	    return;
+
+	  if ((PPC_BO (insn) & 0x14) == 0x4)
+	    insn ^= (1 << 24);
+	  else if ((PPC_BO (insn) & 0x14) == 0x10)
+	    insn ^= (1 << 22);
+
+	  /* Jump over the unconditional branch.  */
+	  insn = (insn & ~0xfffc) | 0x8;
+	  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+	  *to += 4;
+
+	  /* Build a unconditional branch and copy LK bit.  */
+	  insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3);
+	  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+	  *to += 4;
+
+	  return;
+	}
+      else if ((PPC_BO (insn) & 0x14) == 0)
+	{
+	  uint32_t bdnz_insn = (16 << 26) | (0x10 << 21) | 12;
+	  uint32_t bf_insn = (16 << 26) | (0x4 << 21) | 8;
+
+	  newrel -= 8;
+
+	  /* Out of range. Cannot relocate instruction.  */
+	  if (newrel >= (1 << 25) || newrel < -(1 << 25))
+	    return;
+
+	  /* Copy BI field.  */
+	  bf_insn |= (insn & 0x1f0000);
+
+	  /* Invert condition.  */
+	  bdnz_insn |= (insn ^ (1 << 22)) & (1 << 22);
+	  bf_insn |= (insn ^ (1 << 24)) & (1 << 24);
+
+	  write_inferior_memory (*to, (unsigned char *) &bdnz_insn, 4);
+	  *to += 4;
+	  write_inferior_memory (*to, (unsigned char *) &bf_insn, 4);
+	  *to += 4;
+
+	  /* Build a unconditional branch and copy LK bit.  */
+	  insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3);
+	  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+	  *to += 4;
+
+	  return;
+	}
+      else /* (BO & 0x14) == 0x14, branch always.  */
+	{
+	  /* Out of range. Cannot relocate instruction.  */
+	  if (newrel >= (1 << 25) || newrel < -(1 << 25))
+	    return;
+
+	  /* Build a unconditional branch and copy LK bit.  */
+	  insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3);
+	  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+	  *to += 4;
+
+	  return;
+	}
+    }
+
+  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+  *to += 4;
+}
+
+/* Implement install_fast_tracepoint_jump_pad of target_ops.
+   See target.h for details.  */
+
+static int
+ppc_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
+				      CORE_ADDR collector,
+				      CORE_ADDR lockaddr,
+				      ULONGEST orig_size,
+				      CORE_ADDR *jump_entry,
+				      CORE_ADDR *trampoline,
+				      ULONGEST *trampoline_size,
+				      unsigned char *jjump_pad_insn,
+				      ULONGEST *jjump_pad_insn_size,
+				      CORE_ADDR *adjusted_insn_addr,
+				      CORE_ADDR *adjusted_insn_addr_end,
+				      char *err)
+{
+  uint32_t buf[256];
+  uint32_t *p = buf;
+  int j, offset;
+  CORE_ADDR buildaddr = *jump_entry;
+  const CORE_ADDR entryaddr = *jump_entry;
+  int rsz, min_frame, frame_size, tp_reg;
+#ifdef __powerpc64__
+  struct regcache *regcache = get_thread_regcache (current_thread, 0);
+  int is_64 = register_size (regcache->tdesc, 0) == 8;
+#if _CALL_ELF == 2
+  /* XXX is there a way to get this dynamically from the inferior?  */
+  int is_opd = 0;
+#else
+  int is_opd = is_64;
+#endif
+#else
+  int is_64 = 0, is_opd = 0;
+#endif
+
+#ifdef __powerpc64__
+  if (is_64)
+    {
+      /* Minimum frame size is 32 bytes for ELFv2, and 112 bytes for ELFv1.  */
+      rsz = 8;
+      min_frame = 112;
+      frame_size = (40 * rsz) + min_frame;
+      tp_reg = 13;
+    }
+  else
+    {
+#endif
+      rsz = 4;
+      min_frame = 16;
+      frame_size = (40 * rsz) + min_frame;
+      tp_reg = 2;
+#ifdef __powerpc64__
+    }
+#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.  */
+  if (is_64)
+    p += GEN_STDU (p, 1, 1, -frame_size);		/* stdu   r1,-frame_size(r1) */
+  else
+    p += GEN_STWU (p, 1, 1, -frame_size);		/* stwu   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, is_64);
+  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, is_64);
+
+  /* Prepare collecting_t object for lock.  */
+  p += GEN_STORE (p, 3, 1, min_frame + 37 * rsz);
+  p += GEN_STORE (p, tp_reg, 1, min_frame + 38 * rsz);
+  /* Set R5 to collecting object.  */
+  p += GEN_ADDI (p, 5, 1, 37 * rsz);
+
+  p += GEN_LWSYNC (p);
+  p += gen_atomic_xchg (p, lockaddr, 0, 5, is_64);
+  p += GEN_LWSYNC (p);
+
+  /* Call to collector.  */
+  p += gen_call (p, collector, is_64, is_opd);
+
+  /* Simply write 0 to release the lock.  */
+  p += gen_limm (p, 3, lockaddr, is_64);
+  p += gen_limm (p, 4, 0, is_64);
+  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 (void)
+{
+  return 4;
+}
+
+/* Implementation of linux_target_ops method "get_ipa_tdesc_idx".  */
+
+static int
+ppc_get_ipa_tdesc_idx (void)
+{
+  struct regcache *regcache = get_thread_regcache (current_thread, 0);
+  const struct target_desc *tdesc = regcache->tdesc;
+
+#ifdef __powerpc64__
+  if (tdesc == tdesc_powerpc_64l)
+    return PPC_TDESC_BASE;
+  if (tdesc == tdesc_powerpc_altivec64l)
+    return PPC_TDESC_ALTIVEC;
+  if (tdesc == tdesc_powerpc_cell64l)
+    return PPC_TDESC_CELL;
+  if (tdesc == tdesc_powerpc_vsx64l)
+    return PPC_TDESC_VSX;
+  if (tdesc == tdesc_powerpc_isa205_64l)
+    return PPC_TDESC_ISA205;
+  if (tdesc == tdesc_powerpc_isa205_altivec64l)
+    return PPC_TDESC_ISA205_ALTIVEC;
+  if (tdesc == tdesc_powerpc_isa205_vsx64l)
+    return PPC_TDESC_ISA205_VSX;
+#endif
+
+  if (tdesc == tdesc_powerpc_32l)
+    return PPC_TDESC_BASE;
+  if (tdesc == tdesc_powerpc_altivec32l)
+    return PPC_TDESC_ALTIVEC;
+  if (tdesc == tdesc_powerpc_cell32l)
+    return PPC_TDESC_CELL;
+  if (tdesc == tdesc_powerpc_vsx32l)
+    return PPC_TDESC_VSX;
+  if (tdesc == tdesc_powerpc_isa205_32l)
+    return PPC_TDESC_ISA205;
+  if (tdesc == tdesc_powerpc_isa205_altivec32l)
+    return PPC_TDESC_ISA205_ALTIVEC;
+  if (tdesc == tdesc_powerpc_isa205_vsx32l)
+    return PPC_TDESC_ISA205_VSX;
+  if (tdesc == tdesc_powerpc_e500l)
+    return PPC_TDESC_E500;
+
+  return 0;
+}
+
 struct linux_target_ops the_low_target = {
   ppc_arch_setup,
   ppc_regs_info,
@@ -789,13 +1512,15 @@ struct linux_target_ops the_low_target = {
   NULL, /* prepare_to_resume */
   NULL, /* process_qsupported */
   ppc_supports_tracepoints,
-  NULL, /* get_thread_area */
-  NULL, /* install_fast_tracepoint_jump_pad */
+  ppc_get_thread_area,
+  ppc_install_fast_tracepoint_jump_pad,
   NULL, /* emit_ops */
-  NULL, /* get_min_fast_tracepoint_insn_len */
+  ppc_get_min_fast_tracepoint_insn_len,
   NULL, /* supports_range_stepping */
   NULL, /* breakpoint_kind_from_current_state */
   ppc_supports_hardware_single_step,
+  NULL, /* get_syscall_trapinfo */
+  ppc_get_ipa_tdesc_idx,
 };
 
 void
@@ -811,6 +1536,7 @@ initialize_low_arch (void)
   init_registers_powerpc_isa205_altivec32l ();
   init_registers_powerpc_isa205_vsx32l ();
   init_registers_powerpc_e500l ();
+#if __powerpc64__
   init_registers_powerpc_64l ();
   init_registers_powerpc_altivec64l ();
   init_registers_powerpc_cell64l ();
@@ -818,6 +1544,7 @@ initialize_low_arch (void)
   init_registers_powerpc_isa205_64l ();
   init_registers_powerpc_isa205_altivec64l ();
   init_registers_powerpc_isa205_vsx64l ();
+#endif
 
   initialize_regsets_info (&ppc_regsets_info);
 }
diff --git a/gdb/gdbserver/linux-ppc-tdesc.h b/gdb/gdbserver/linux-ppc-tdesc.h
new file mode 100644
index 0000000..d77b127
--- /dev/null
+++ b/gdb/gdbserver/linux-ppc-tdesc.h
@@ -0,0 +1,101 @@
+/* Low level support for ppc, shared between gdbserver and IPA.
+
+   Copyright (C) 2016 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/>.  */
+
+/* Note: since IPA obviously knows what ABI it's running on (32 vs 64),
+   it's sufficient to pass only the register set here.  This, together with
+   the ABI known at IPA compile time, maps to a tdesc.  */
+
+enum ppc_linux_tdesc {
+  PPC_TDESC_BASE,
+  PPC_TDESC_ALTIVEC,
+  PPC_TDESC_CELL,
+  PPC_TDESC_VSX,
+  PPC_TDESC_ISA205,
+  PPC_TDESC_ISA205_ALTIVEC,
+  PPC_TDESC_ISA205_VSX,
+  PPC_TDESC_E500,
+};
+
+#if !defined __powerpc64__ || !defined IN_PROCESS_AGENT
+
+/* Defined in auto-generated file powerpc-32l.c.  */
+void init_registers_powerpc_32l (void);
+extern const struct target_desc *tdesc_powerpc_32l;
+
+/* Defined in auto-generated file powerpc-altivec32l.c.  */
+void init_registers_powerpc_altivec32l (void);
+extern const struct target_desc *tdesc_powerpc_altivec32l;
+
+/* Defined in auto-generated file powerpc-cell32l.c.  */
+void init_registers_powerpc_cell32l (void);
+extern const struct target_desc *tdesc_powerpc_cell32l;
+
+/* Defined in auto-generated file powerpc-vsx32l.c.  */
+void init_registers_powerpc_vsx32l (void);
+extern const struct target_desc *tdesc_powerpc_vsx32l;
+
+/* Defined in auto-generated file powerpc-isa205-32l.c.  */
+void init_registers_powerpc_isa205_32l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_32l;
+
+/* Defined in auto-generated file powerpc-isa205-altivec32l.c.  */
+void init_registers_powerpc_isa205_altivec32l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_altivec32l;
+
+/* Defined in auto-generated file powerpc-isa205-vsx32l.c.  */
+void init_registers_powerpc_isa205_vsx32l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_vsx32l;
+
+/* Defined in auto-generated file powerpc-e500l.c.  */
+void init_registers_powerpc_e500l (void);
+extern const struct target_desc *tdesc_powerpc_e500l;
+
+#endif
+
+#if defined __powerpc64__
+
+/* Defined in auto-generated file powerpc-64l.c.  */
+void init_registers_powerpc_64l (void);
+extern const struct target_desc *tdesc_powerpc_64l;
+
+/* Defined in auto-generated file powerpc-altivec64l.c.  */
+void init_registers_powerpc_altivec64l (void);
+extern const struct target_desc *tdesc_powerpc_altivec64l;
+
+/* Defined in auto-generated file powerpc-cell64l.c.  */
+void init_registers_powerpc_cell64l (void);
+extern const struct target_desc *tdesc_powerpc_cell64l;
+
+/* Defined in auto-generated file powerpc-vsx64l.c.  */
+void init_registers_powerpc_vsx64l (void);
+extern const struct target_desc *tdesc_powerpc_vsx64l;
+
+/* Defined in auto-generated file powerpc-isa205-64l.c.  */
+void init_registers_powerpc_isa205_64l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_64l;
+
+/* Defined in auto-generated file powerpc-isa205-altivec64l.c.  */
+void init_registers_powerpc_isa205_altivec64l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_altivec64l;
+
+/* Defined in auto-generated file powerpc-isa205-vsx64l.c.  */
+void init_registers_powerpc_isa205_vsx64l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_vsx64l;
+
+#endif
-- 
2.7.2

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

* [PATCH 4/4] gdbserver: Add emit_ops for powerpc.
  2016-03-13  2:31 [PATCH 0/3] gdbserver: Add powerpc fast tracepoint support Marcin Kościelnicki
                   ` (2 preceding siblings ...)
  2016-03-13  2:32 ` [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers Marcin Kościelnicki
@ 2016-03-14 22:25 ` Marcin Kościelnicki
  2016-03-16 17:16   ` Ulrich Weigand
  3 siblings, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-14 22:25 UTC (permalink / raw)
  To: gdb-patches; +Cc: Marcin Kościelnicki

gdb/gdbserver/ChangeLog:

2016-03-14  Wei-cheng Wang  <cole945@gmail.com>
	    Marcin Kościelnicki  <koriakin@0x04.net>

	* linux-ppc-low.c (emit_insns): New function.
	(__EMIT_ASM, _EMIT_ASM, EMIT_ASM): New macros.
	(ppc_emit_prologue): New function.
	(ppc_emit_epilogue): New function.
	(ppc_emit_add): New function.
	(ppc_emit_sub): New function.
	(ppc_emit_mul): New function.
	(ppc_emit_lsh): New function.
	(ppc_emit_rsh_signed): New function.
	(ppc_emit_rsh_unsigned): New function.
	(ppc_emit_ext): New function.
	(ppc_emit_zero_ext): New function.
	(ppc_emit_log_not): New function.
	(ppc_emit_bit_and): New function.
	(ppc_emit_bit_or): New function.
	(ppc_emit_bit_xor): New function.
	(ppc_emit_bit_not): New function.
	(ppc_emit_equal): New function.
	(ppc_emit_less_signed): New function.
	(ppc_emit_less_unsigned): New function.
	(ppc_emit_ref): New function.
	(ppc_emit_const): New function.
	(ppc_emit_reg): New function.
	(ppc_emit_pop): New function.
	(ppc_emit_stack_flush): New function.
	(ppc_emit_swap): New function.
	(ppc_emit_stack_adjust): New function.
	(ppc_emit_call): New function.
	(ppc_emit_int_call_1): New function.
	(ppc_emit_void_call_2): New function.
	(ppc_emit_if_goto): New function.
	(ppc_emit_goto): New function.
	(ppc_emit_eq_goto): New function.
	(ppc_emit_ne_goto): New function.
	(ppc_emit_lt_goto): New function.
	(ppc_emit_le_goto): New function.
	(ppc_emit_gt_goto): New function.
	(ppc_emit_ge_goto): New function.
	(ppc_write_goto_address): New function.
	(ppc_emit_ops_impl): New static variable.
	(ppc64v1_emit_prologue): New function.
	(ppc64v2_emit_prologue): New function.
	(ppc64_emit_epilogue): New function.
	(ppc64_emit_add): New function.
	(ppc64_emit_sub): New function.
	(ppc64_emit_mul): New function.
	(ppc64_emit_lsh): New function.
	(ppc64_emit_rsh_signed): New function.
	(ppc64_emit_rsh_unsigned): New function.
	(ppc64_emit_ext): New function.
	(ppc64_emit_zero_ext): New function.
	(ppc64_emit_log_not): New function.
	(ppc64_emit_bit_and): New function.
	(ppc64_emit_bit_or): New function.
	(ppc64_emit_bit_xor): New function.
	(ppc64_emit_bit_not): New function.
	(ppc64_emit_equal): New function.
	(ppc64_emit_less_signed): New function.
	(ppc64_emit_less_unsigned): New function.
	(ppc64_emit_ref): New function.
	(ppc64_emit_const): New function.
	(ppc64v1_emit_reg): New function.
	(ppc64v2_emit_reg): New function.
	(ppc64_emit_pop): New function.
	(ppc64_emit_stack_flush): New function.
	(ppc64_emit_swap): New function.
	(ppc64v1_emit_call): New function.
	(ppc64v2_emit_call): New function.
	(ppc64v1_emit_int_call_1): New function.
	(ppc64v2_emit_int_call_1): New function.
	(ppc64v1_emit_void_call_2): New function.
	(ppc64v2_emit_void_call_2): New function.
	(ppc64_emit_if_goto): New function.
	(ppc64_emit_eq_goto): New function.
	(ppc64_emit_ne_goto): New function.
	(ppc64_emit_lt_goto): New function.
	(ppc64_emit_le_goto): New function.
	(ppc64_emit_gt_goto): New function.
	(ppc64_emit_ge_goto): New function.
	(ppc64v1_emit_ops_impl): New static variable.
	(ppc64v2_emit_ops_impl): New static variable.
	(ppc_emit_ops): New function.
	(linux_low_target): Wire in ppc_emit_ops.
--- 
Compiled agent expressions support for powerpc and powerpc64, finishing
the fast tracepoint patchset.  Tested on powerpc, powerpc64, powerpc64le.

Based on https://sourceware.org/ml/gdb-patches/2015-07/msg00353.html ,
with some fixes and support for 32-bit and ELFv1.

 gdb/gdbserver/ChangeLog       |   87 +++
 gdb/gdbserver/linux-ppc-low.c | 1598 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 1684 insertions(+), 1 deletion(-)

diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index a6bba77..354ca2f 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,90 @@
+2016-03-14  Wei-cheng Wang  <cole945@gmail.com>
+	    Marcin Kościelnicki  <koriakin@0x04.net>
+
+	* linux-ppc-low.c (emit_insns): New function.
+	(__EMIT_ASM, _EMIT_ASM, EMIT_ASM): New macros.
+	(ppc_emit_prologue): New function.
+	(ppc_emit_epilogue): New function.
+	(ppc_emit_add): New function.
+	(ppc_emit_sub): New function.
+	(ppc_emit_mul): New function.
+	(ppc_emit_lsh): New function.
+	(ppc_emit_rsh_signed): New function.
+	(ppc_emit_rsh_unsigned): New function.
+	(ppc_emit_ext): New function.
+	(ppc_emit_zero_ext): New function.
+	(ppc_emit_log_not): New function.
+	(ppc_emit_bit_and): New function.
+	(ppc_emit_bit_or): New function.
+	(ppc_emit_bit_xor): New function.
+	(ppc_emit_bit_not): New function.
+	(ppc_emit_equal): New function.
+	(ppc_emit_less_signed): New function.
+	(ppc_emit_less_unsigned): New function.
+	(ppc_emit_ref): New function.
+	(ppc_emit_const): New function.
+	(ppc_emit_reg): New function.
+	(ppc_emit_pop): New function.
+	(ppc_emit_stack_flush): New function.
+	(ppc_emit_swap): New function.
+	(ppc_emit_stack_adjust): New function.
+	(ppc_emit_call): New function.
+	(ppc_emit_int_call_1): New function.
+	(ppc_emit_void_call_2): New function.
+	(ppc_emit_if_goto): New function.
+	(ppc_emit_goto): New function.
+	(ppc_emit_eq_goto): New function.
+	(ppc_emit_ne_goto): New function.
+	(ppc_emit_lt_goto): New function.
+	(ppc_emit_le_goto): New function.
+	(ppc_emit_gt_goto): New function.
+	(ppc_emit_ge_goto): New function.
+	(ppc_write_goto_address): New function.
+	(ppc_emit_ops_impl): New static variable.
+	(ppc64v1_emit_prologue): New function.
+	(ppc64v2_emit_prologue): New function.
+	(ppc64_emit_epilogue): New function.
+	(ppc64_emit_add): New function.
+	(ppc64_emit_sub): New function.
+	(ppc64_emit_mul): New function.
+	(ppc64_emit_lsh): New function.
+	(ppc64_emit_rsh_signed): New function.
+	(ppc64_emit_rsh_unsigned): New function.
+	(ppc64_emit_ext): New function.
+	(ppc64_emit_zero_ext): New function.
+	(ppc64_emit_log_not): New function.
+	(ppc64_emit_bit_and): New function.
+	(ppc64_emit_bit_or): New function.
+	(ppc64_emit_bit_xor): New function.
+	(ppc64_emit_bit_not): New function.
+	(ppc64_emit_equal): New function.
+	(ppc64_emit_less_signed): New function.
+	(ppc64_emit_less_unsigned): New function.
+	(ppc64_emit_ref): New function.
+	(ppc64_emit_const): New function.
+	(ppc64v1_emit_reg): New function.
+	(ppc64v2_emit_reg): New function.
+	(ppc64_emit_pop): New function.
+	(ppc64_emit_stack_flush): New function.
+	(ppc64_emit_swap): New function.
+	(ppc64v1_emit_call): New function.
+	(ppc64v2_emit_call): New function.
+	(ppc64v1_emit_int_call_1): New function.
+	(ppc64v2_emit_int_call_1): New function.
+	(ppc64v1_emit_void_call_2): New function.
+	(ppc64v2_emit_void_call_2): New function.
+	(ppc64_emit_if_goto): New function.
+	(ppc64_emit_eq_goto): New function.
+	(ppc64_emit_ne_goto): New function.
+	(ppc64_emit_lt_goto): New function.
+	(ppc64_emit_le_goto): New function.
+	(ppc64_emit_gt_goto): New function.
+	(ppc64_emit_ge_goto): New function.
+	(ppc64v1_emit_ops_impl): New static variable.
+	(ppc64v2_emit_ops_impl): New static variable.
+	(ppc_emit_ops): New function.
+	(linux_low_target): Wire in ppc_emit_ops.
+
 2016-03-13  Wei-cheng Wang  <cole945@gmail.com>
 	    Marcin Kościelnicki  <koriakin@0x04.net>
 
diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c
index 2b3630f..df4e838 100644
--- a/gdb/gdbserver/linux-ppc-low.c
+++ b/gdb/gdbserver/linux-ppc-low.c
@@ -1440,6 +1440,1602 @@ ppc_get_min_fast_tracepoint_insn_len (void)
   return 4;
 }
 
+/* Emits a given buffer into the target at current_insn_ptr.  Length
+   is in units of 32-bit words.  */
+
+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 - 32-bit
+
+	|  LR save area           (SP + 4)
+ 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 and 16-byte alignment.
+        |  16 bytes.
+ SP     +- Back-chain (SP')
+
+  initial frame size
+  = 16 + (4 * 4) + 64
+  = 96
+
+   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 the high part of TOP value.
+       It was the first argument, pointer to regs.
+   r4  is used for cache of the low part of TOP value.
+       It was the second argument, pointer to the result.
+       We should set *result = TOP after leaving this function.
+
+ Note:
+ * To restore stack at epilogue
+   => sp = r31
+ * To check stack is big enough for bytecode execution.
+   => r30 - 8 > SP + 8
+ * To return execution result.
+   => 0(r4) = TOP
+
+ */
+
+/* Regardless of endian, register 3 is always high part, 4 is low part.
+   These defines are used when the register pair is stored/loaded.
+   Likewise, to simplify code, have a similiar define for 5:6. */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define TOP_FIRST	"4"
+#define TOP_SECOND	"3"
+#define TMP_FIRST	"6"
+#define TMP_SECOND	"5"
+#else
+#define TOP_FIRST	"3"
+#define TOP_SECOND	"4"
+#define TMP_FIRST	"5"
+#define TMP_SECOND	"6"
+#endif
+
+/* Emit prologue in inferior memory.  See above comments.  */
+
+static void
+ppc_emit_prologue (void)
+{
+  EMIT_ASM (/* Save return address.  */
+	    "mflr  0		\n"
+	    "stw   0, 4(1)	\n"
+	    /* Adjust SP.  96 is the initial frame size.  */
+	    "stwu  1, -96(1)	\n"
+	    /* Save r30 and incoming arguments.  */
+	    "stw   31, 96-4(1)	\n"
+	    "stw   30, 96-8(1)	\n"
+	    "stw   4, 96-12(1)	\n"
+	    "stw   3, 96-16(1)	\n"
+	    /* Point r31 to original r1 for access arguments.  */
+	    "addi  31, 1, 96	\n"
+	    /* Set r30 to pointing stack-top.  */
+	    "addi  30, 1, 64	\n"
+	    /* Initial r3/TOP to 0.  */
+	    "li    3, 0		\n"
+	    "li    4, 0		\n");
+}
+
+/* Emit epilogue in inferior memory.  See above comments.  */
+
+static void
+ppc_emit_epilogue (void)
+{
+  EMIT_ASM (/* *result = TOP */
+	    "lwz   5, -12(31)	\n"
+	    "stw   " TOP_FIRST ", 0(5)	\n"
+	    "stw   " TOP_SECOND ", 4(5)	\n"
+	    /* Restore registers.  */
+	    "lwz   31, -4(31)	\n"
+	    "lwz   30, -8(31)	\n"
+	    /* Restore SP.  */
+	    "lwz   1, 0(1)      \n"
+	    /* Restore LR.  */
+	    "lwz   0, 4(1)	\n"
+	    /* Return 0 for no-error.  */
+	    "li    3, 0		\n"
+	    "mtlr  0		\n"
+	    "blr		\n");
+}
+
+/* TOP = stack[--sp] + TOP  */
+
+static void
+ppc_emit_add (void)
+{
+  EMIT_ASM ("lwzu  " TMP_FIRST ", 8(30)	\n"
+	    "lwz   " TMP_SECOND ", 4(30)\n"
+	    "addc  4, 6, 4	\n"
+	    "adde  3, 5, 3	\n");
+}
+
+/* TOP = stack[--sp] - TOP  */
+
+static void
+ppc_emit_sub (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "subfc  4, 4, 6	\n"
+	    "subfe  3, 3, 5	\n");
+}
+
+/* TOP = stack[--sp] * TOP  */
+
+static void
+ppc_emit_mul (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "mulhwu 7, 6, 4	\n"
+	    "mullw  3, 6, 3	\n"
+	    "mullw  5, 4, 5	\n"
+	    "mullw  4, 6, 4	\n"
+	    "add    3, 5, 3	\n"
+	    "add    3, 7, 3	\n");
+}
+
+/* TOP = stack[--sp] << TOP  */
+
+static void
+ppc_emit_lsh (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "subfic 3, 4, 32\n"		/* r3 = 32 - TOP */
+	    "addi   7, 4, -32\n"	/* r7 = TOP - 32 */
+	    "slw    5, 5, 4\n"		/* Shift high part left */
+	    "slw    4, 6, 4\n"		/* Shift low part left */
+	    "srw    3, 6, 3\n"		/* Shift low to high if shift < 32 */
+	    "slw    7, 6, 7\n"		/* Shift low to high if shift >= 32 */
+	    "or     3, 5, 3\n"
+	    "or     3, 7, 3\n");	/* Assemble high part */
+}
+
+/* Top = stack[--sp] >> TOP
+   (Arithmetic shift right)  */
+
+static void
+ppc_emit_rsh_signed (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "addi   7, 4, -32\n"	/* r7 = TOP - 32 */
+	    "sraw   3, 5, 4\n"		/* Shift high part right */
+	    "cmpwi  7, 1\n"
+	    "blt    0, 1f\n"		/* If shift <= 32, goto 1: */
+	    "sraw   4, 5, 7\n"		/* Shift high to low */
+	    "b      2f\n"
+	    "1:\n"
+	    "subfic 7, 4, 32\n"		/* r7 = 32 - TOP */
+	    "srw    4, 6, 4\n"		/* Shift low part right */
+	    "slw    5, 5, 7\n"		/* Shift high to low */
+	    "or     4, 4, 5\n"		/* Assemble low part */
+	    "2:\n");
+}
+
+/* Top = stack[--sp] >> TOP
+   (Logical shift right)  */
+
+static void
+ppc_emit_rsh_unsigned (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "subfic 3, 4, 32\n"		/* r3 = 32 - TOP */
+	    "addi   7, 4, -32\n"	/* r7 = TOP - 32 */
+	    "srw    6, 6, 4\n"		/* Shift low part right */
+	    "slw    3, 5, 3\n"		/* Shift high to low if shift < 32 */
+	    "srw    7, 5, 7\n"		/* Shift high to low if shift >= 32 */
+	    "or     6, 6, 3\n"
+	    "srw    3, 5, 4\n"		/* Shift high part right */
+	    "or     4, 6, 7\n");	/* Assemble low part */
+}
+
+/* Emit code for signed-extension specified by ARG.  */
+
+static void
+ppc_emit_ext (int arg)
+{
+  switch (arg)
+    {
+    case 8:
+      EMIT_ASM ("extsb  4, 4\n"
+		"srawi 3, 4, 31");
+      break;
+    case 16:
+      EMIT_ASM ("extsh  4, 4\n"
+		"srawi 3, 4, 31");
+      break;
+    case 32:
+      EMIT_ASM ("srawi 3, 4, 31");
+      break;
+    default:
+      emit_error = 1;
+    }
+}
+
+/* Emit code for zero-extension specified by ARG.  */
+
+static void
+ppc_emit_zero_ext (int arg)
+{
+  switch (arg)
+    {
+    case 8:
+      EMIT_ASM ("clrlwi 4,4,24\n"
+		"li 3, 0\n");
+      break;
+    case 16:
+      EMIT_ASM ("clrlwi 4,4,16\n"
+		"li 3, 0\n");
+      break;
+    case 32:
+      EMIT_ASM ("li 3, 0");
+      break;
+    default:
+      emit_error = 1;
+    }
+}
+
+/* TOP = !TOP
+   i.e., TOP = (TOP == 0) ? 1 : 0;  */
+
+static void
+ppc_emit_log_not (void)
+{
+  EMIT_ASM ("or      4, 3, 4	\n"
+	    "cntlzw  4, 4	\n"
+	    "srwi    4, 4, 5	\n"
+	    "li      3, 0	\n");
+}
+
+/* TOP = stack[--sp] & TOP  */
+
+static void
+ppc_emit_bit_and (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "and  4, 6, 4	\n"
+	    "and  3, 5, 3	\n");
+}
+
+/* TOP = stack[--sp] | TOP  */
+
+static void
+ppc_emit_bit_or (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "or  4, 6, 4	\n"
+	    "or  3, 5, 3	\n");
+}
+
+/* TOP = stack[--sp] ^ TOP  */
+
+static void
+ppc_emit_bit_xor (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "xor  4, 6, 4	\n"
+	    "xor  3, 5, 3	\n");
+}
+
+/* TOP = ~TOP
+   i.e., TOP = ~(TOP | TOP)  */
+
+static void
+ppc_emit_bit_not (void)
+{
+  EMIT_ASM ("nor  3, 3, 3	\n"
+	    "nor  4, 4, 4	\n");
+}
+
+/* TOP = stack[--sp] == TOP  */
+
+static void
+ppc_emit_equal (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "xor     4, 6, 4	\n"
+	    "xor     3, 5, 3	\n"
+	    "or      4, 3, 4	\n"
+	    "cntlzw  4, 4	\n"
+	    "srwi    4, 4, 5	\n"
+	    "li      3, 0	\n");
+}
+
+/* TOP = stack[--sp] < TOP
+   (Signed comparison)  */
+
+static void
+ppc_emit_less_signed (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "cmplw   6, 6, 4		\n"
+	    "cmpw    7, 5, 3		\n"
+	    /* CR6 bit 0 = low less and high equal */
+	    "crand   6*4+0, 6*4+0, 7*4+2\n"
+	    /* CR7 bit 0 = (low less and high equal) or high less */
+	    "cror    7*4+0, 7*4+0, 6*4+0\n"
+	    "mfcr    4			\n"
+	    "rlwinm  4, 4, 29, 31, 31	\n"
+	    "li      3, 0		\n");
+}
+
+/* TOP = stack[--sp] < TOP
+   (Unsigned comparison)  */
+
+static void
+ppc_emit_less_unsigned (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "cmplw   6, 6, 4		\n"
+	    "cmplw   7, 5, 3		\n"
+	    /* CR6 bit 0 = low less and high equal */
+	    "crand   6*4+0, 6*4+0, 7*4+2\n"
+	    /* CR7 bit 0 = (low less and high equal) or high less */
+	    "cror    7*4+0, 7*4+0, 6*4+0\n"
+	    "mfcr    4			\n"
+	    "rlwinm  4, 4, 29, 31, 31	\n"
+	    "li      3, 0		\n");
+}
+
+/* Access the memory address in TOP in size of SIZE.
+   Zero-extend the read value.  */
+
+static void
+ppc_emit_ref (int size)
+{
+  switch (size)
+    {
+    case 1:
+      EMIT_ASM ("lbz   4, 0(4)\n"
+		"li    3, 0");
+      break;
+    case 2:
+      EMIT_ASM ("lhz   4, 0(4)\n"
+		"li    3, 0");
+      break;
+    case 4:
+      EMIT_ASM ("lwz   4, 0(4)\n"
+		"li    3, 0");
+      break;
+    case 8:
+      if (__BYTE_ORDER == __LITTLE_ENDIAN)
+	EMIT_ASM ("lwz   3, 4(4)\n"
+		  "lwz   4, 0(4)");
+      else
+	EMIT_ASM ("lwz   3, 0(4)\n"
+		  "lwz   4, 4(4)");
+      break;
+    }
+}
+
+/* TOP = NUM  */
+
+static void
+ppc_emit_const (LONGEST num)
+{
+  uint32_t buf[10];
+  uint32_t *p = buf;
+
+  p += gen_limm (p, 3, num >> 32 & 0xffffffff, 0);
+  p += gen_limm (p, 4, num & 0xffffffff, 0);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (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
+ppc_emit_reg (int reg)
+{
+  uint32_t buf[13];
+  uint32_t *p = buf;
+
+  /* fctx->regs is passed in r3 and then saved in -16(31).  */
+  p += GEN_LWZ (p, 3, 31, -16);
+  p += GEN_LI (p, 4, reg);	/* li	r4, reg */
+  p += gen_call (p, get_raw_reg_func_addr (), 0, 0);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+
+  if (__BYTE_ORDER == __LITTLE_ENDIAN)
+    {
+      EMIT_ASM ("mr 5, 4\n"
+		"mr 4, 3\n"
+		"mr 3, 5\n");
+    }
+}
+
+/* TOP = stack[--sp] */
+
+static void
+ppc_emit_pop (void)
+{
+  EMIT_ASM ("lwzu " TOP_FIRST ", 8(30)	\n"
+	    "lwz " TOP_SECOND ", 4(30)	\n");
+}
+
+/* stack[sp++] = TOP
+
+   Because we may use up bytecode stack, expand 8 doublewords more
+   if needed.  */
+
+static void
+ppc_emit_stack_flush (void)
+{
+  /* Make sure bytecode stack is big enough before push.
+     Otherwise, expand 64-byte more.  */
+
+  EMIT_ASM ("  stw   " TOP_FIRST ", 0(30)	\n"
+	    "  stw   " TOP_SECOND ", 4(30)\n"
+	    "  addi  5, 30, -(8 + 8)	\n"
+	    "  cmpw  7, 5, 1		\n"
+	    "  bgt   7, 1f		\n"
+	    "  stwu  31, -64(1)		\n"
+	    "1:addi  30, 30, -8		\n");
+}
+
+/* Swap TOP and stack[sp-1]  */
+
+static void
+ppc_emit_swap (void)
+{
+  EMIT_ASM ("lwz  " TMP_FIRST ", 8(30)	\n"
+	    "lwz  " TMP_SECOND ", 12(30)	\n"
+	    "stw  " TOP_FIRST ", 8(30)	\n"
+	    "stw  " TOP_SECOND ", 12(30)	\n"
+	    "mr   3, 5		\n"
+	    "mr   4, 6		\n");
+}
+
+/* Discard N elements in the stack.  Also used for ppc64.  */
+
+static void
+ppc_emit_stack_adjust (int n)
+{
+  uint32_t buf[6];
+  uint32_t *p = buf;
+
+  n = n << 3;
+  if ((n >> 15) != 0)
+    {
+      emit_error = 1;
+      return;
+    }
+
+  p += GEN_ADDI (p, 30, 30, n);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+}
+
+/* Call function FN.  */
+
+static void
+ppc_emit_call (CORE_ADDR fn)
+{
+  uint32_t buf[11];
+  uint32_t *p = buf;
+
+  p += gen_call (p, fn, 0, 0);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+}
+
+/* FN's prototype is `LONGEST(*fn)(int)'.
+   TOP = fn (arg1)
+  */
+
+static void
+ppc_emit_int_call_1 (CORE_ADDR fn, int arg1)
+{
+  uint32_t buf[15];
+  uint32_t *p = buf;
+
+  /* Setup argument.  arg1 is a 16-bit value.  */
+  p += gen_limm (p, 3, (uint32_t) arg1, 0);
+  p += gen_call (p, fn, 0, 0);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+
+  if (__BYTE_ORDER == __LITTLE_ENDIAN)
+    {
+      EMIT_ASM ("mr 5, 4\n"
+		"mr 4, 3\n"
+		"mr 3, 5\n");
+    }
+}
+
+/* FN's prototype is `void(*fn)(int,LONGEST)'.
+   fn (arg1, TOP)
+
+   TOP should be preserved/restored before/after the call.  */
+
+static void
+ppc_emit_void_call_2 (CORE_ADDR fn, int arg1)
+{
+  uint32_t buf[21];
+  uint32_t *p = buf;
+
+  /* Save TOP.  0(30) is next-empty.  */
+  p += GEN_STW (p, 3, 30, 0);
+  p += GEN_STW (p, 4, 30, 4);
+
+  /* Setup argument.  arg1 is a 16-bit value.  */
+  if (__BYTE_ORDER == __LITTLE_ENDIAN)
+    {
+       p += GEN_MR (p, 5, 4);
+       p += GEN_MR (p, 6, 3);
+    }
+  else
+    {
+       p += GEN_MR (p, 5, 3);
+       p += GEN_MR (p, 6, 4);
+    }
+  p += gen_limm (p, 3, (uint32_t) arg1, 0);
+  p += gen_call (p, fn, 0, 0);
+
+  /* Restore TOP */
+  p += GEN_LWZ (p, 3, 30, 0);
+  p += GEN_LWZ (p, 4, 30, 4);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (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
+ppc_emit_if_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("or.    3, 3, 4	\n"
+	    "lwzu " TOP_FIRST ", 8(30)	\n"
+	    "lwz " TOP_SECOND ", 4(30)	\n"
+	    "1:bne  0, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 12;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Unconditional goto.  Also used for ppc64.  */
+
+static void
+ppc_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
+ppc_emit_eq_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("lwzu  " TMP_FIRST ", 8(30)	\n"
+	    "lwz   " TMP_SECOND ", 4(30)	\n"
+	    "xor   4, 6, 4	\n"
+	    "xor   3, 5, 3	\n"
+	    "or.   3, 3, 4	\n"
+	    "lwzu  " TOP_FIRST ", 8(30)	\n"
+	    "lwz   " TOP_SECOND ", 4(30)	\n"
+	    "1:beq 0, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 28;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Goto if stack[--sp] != TOP  */
+
+static void
+ppc_emit_ne_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("lwzu  " TMP_FIRST ", 8(30)	\n"
+	    "lwz   " TMP_SECOND ", 4(30)	\n"
+	    "xor   4, 6, 4	\n"
+	    "xor   3, 5, 3	\n"
+	    "or.   3, 3, 4	\n"
+	    "lwzu  " TOP_FIRST ", 8(30)	\n"
+	    "lwz   " TOP_SECOND ", 4(30)	\n"
+	    "1:bne 0, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 28;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Goto if stack[--sp] < TOP  */
+
+static void
+ppc_emit_lt_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "cmplw   6, 6, 4		\n"
+	    "cmpw    7, 5, 3		\n"
+	    /* CR6 bit 0 = low less and high equal */
+	    "crand   6*4+0, 6*4+0, 7*4+2\n"
+	    /* CR7 bit 0 = (low less and high equal) or high less */
+	    "cror    7*4+0, 7*4+0, 6*4+0\n"
+	    "lwzu    " TOP_FIRST ", 8(30)	\n"
+	    "lwz     " TOP_SECOND ", 4(30)\n"
+	    "1:blt   7, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 32;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Goto if stack[--sp] <= TOP  */
+
+static void
+ppc_emit_le_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "cmplw   6, 6, 4		\n"
+	    "cmpw    7, 5, 3		\n"
+	    /* CR6 bit 0 = low less/equal and high equal */
+	    "crandc   6*4+0, 7*4+2, 6*4+1\n"
+	    /* CR7 bit 0 = (low less/eq and high equal) or high less */
+	    "cror    7*4+0, 7*4+0, 6*4+0\n"
+	    "lwzu    " TOP_FIRST ", 8(30)	\n"
+	    "lwz     " TOP_SECOND ", 4(30)\n"
+	    "1:blt   7, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 32;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Goto if stack[--sp] > TOP  */
+
+static void
+ppc_emit_gt_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "cmplw   6, 6, 4		\n"
+	    "cmpw    7, 5, 3		\n"
+	    /* CR6 bit 0 = low greater and high equal */
+	    "crand   6*4+0, 6*4+1, 7*4+2\n"
+	    /* CR7 bit 0 = (low greater and high equal) or high greater */
+	    "cror    7*4+0, 7*4+1, 6*4+0\n"
+	    "lwzu    " TOP_FIRST ", 8(30)	\n"
+	    "lwz     " TOP_SECOND ", 4(30)\n"
+	    "1:blt   7, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 32;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Goto if stack[--sp] >= TOP  */
+
+static void
+ppc_emit_ge_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "cmplw   6, 6, 4		\n"
+	    "cmpw    7, 5, 3		\n"
+	    /* CR6 bit 0 = low ge and high equal */
+	    "crandc  6*4+0, 7*4+2, 6*4+0\n"
+	    /* CR7 bit 0 = (low ge and high equal) or high greater */
+	    "cror    7*4+0, 7*4+1, 6*4+0\n"
+	    "lwzu    " TOP_FIRST ", 8(30)\n"
+	    "lwz     " TOP_SECOND ", 4(30)\n"
+	    "1:blt   7, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 32;
+  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.
+   Also used for ppc64.  */
+
+static void
+ppc_write_goto_address (CORE_ADDR from, CORE_ADDR to, int size)
+{
+  long 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);
+}
+
+/* Table of emit ops for 32-bit.  */
+
+static struct emit_ops ppc_emit_ops_impl =
+{
+  ppc_emit_prologue,
+  ppc_emit_epilogue,
+  ppc_emit_add,
+  ppc_emit_sub,
+  ppc_emit_mul,
+  ppc_emit_lsh,
+  ppc_emit_rsh_signed,
+  ppc_emit_rsh_unsigned,
+  ppc_emit_ext,
+  ppc_emit_log_not,
+  ppc_emit_bit_and,
+  ppc_emit_bit_or,
+  ppc_emit_bit_xor,
+  ppc_emit_bit_not,
+  ppc_emit_equal,
+  ppc_emit_less_signed,
+  ppc_emit_less_unsigned,
+  ppc_emit_ref,
+  ppc_emit_if_goto,
+  ppc_emit_goto,
+  ppc_write_goto_address,
+  ppc_emit_const,
+  ppc_emit_call,
+  ppc_emit_reg,
+  ppc_emit_pop,
+  ppc_emit_stack_flush,
+  ppc_emit_zero_ext,
+  ppc_emit_swap,
+  ppc_emit_stack_adjust,
+  ppc_emit_int_call_1,
+  ppc_emit_void_call_2,
+  ppc_emit_eq_goto,
+  ppc_emit_ne_goto,
+  ppc_emit_lt_goto,
+  ppc_emit_le_goto,
+  ppc_emit_gt_goto,
+  ppc_emit_ge_goto
+};
+
+#ifdef __powerpc64__
+
+/*
+
+  Bytecode execution stack frame - 64-bit
+
+	|  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
+ * 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
+ppc64v1_emit_prologue (void)
+{
+  /* On ELFv1, function pointers really point to function descriptor,
+     so emit one here.  We don't care about contents of words 1 and 2,
+     so let them just overlap out code.  */
+  uint64_t opd = current_insn_ptr + 8;
+  uint32_t buf[2];
+
+  /* Mind the strict aliasing rules.  */
+  memcpy (buf, &opd, sizeof buf);
+  emit_insns(buf, 2);
+  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 prologue in inferior memory.  See above comments.  */
+
+static void
+ppc64v2_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"
+	    "mfcr    3			\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"
+	    "mfcr    3			\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, 1);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (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
+ppc64v1_emit_reg (int reg)
+{
+  uint32_t buf[15];
+  uint32_t *p = buf;
+
+  /* fctx->regs is passed in r3 and then saved in 176(1).  */
+  p += GEN_LD (p, 3, 31, -32);
+  p += GEN_LI (p, 4, reg);
+  p += GEN_STD (p, 2, 1, 40);	/* Save TOC.  */
+  p += gen_call (p, get_raw_reg_func_addr (), 1, 1);
+  p += GEN_LD (p, 2, 1, 40);	/* Restore TOC.  */
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+}
+
+/* Likewise, for ELFv2.  */
+
+static void
+ppc64v2_emit_reg (int reg)
+{
+  uint32_t buf[12];
+  uint32_t *p = buf;
+
+  /* fctx->regs is passed in r3 and then saved in 176(1).  */
+  p += GEN_LD (p, 3, 31, -32);
+  p += GEN_LI (p, 4, reg);
+  p += GEN_STD (p, 2, 1, 24);	/* Save TOC.  */
+  p += gen_call (p, get_raw_reg_func_addr (), 1, 0);
+  p += GEN_LD (p, 2, 1, 24);	/* Restore TOC.  */
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (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"
+	    "  stdu  31, -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");
+}
+
+/* Call function FN - ELFv1.  */
+
+static void
+ppc64v1_emit_call (CORE_ADDR fn)
+{
+  uint32_t buf[13];
+  uint32_t *p = buf;
+
+  p += GEN_STD (p, 2, 1, 40);	/* Save TOC.  */
+  p += gen_call (p, fn, 1, 1);
+  p += GEN_LD (p, 2, 1, 40);	/* Restore TOC.  */
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+}
+
+/* Call function FN - ELFv2.  */
+
+static void
+ppc64v2_emit_call (CORE_ADDR fn)
+{
+  uint32_t buf[10];
+  uint32_t *p = buf;
+
+  p += GEN_STD (p, 2, 1, 24);	/* Save TOC.  */
+  p += gen_call (p, fn, 1, 0);
+  p += GEN_LD (p, 2, 1, 24);	/* Restore TOC.  */
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+}
+
+/* FN's prototype is `LONGEST(*fn)(int)'.
+   TOP = fn (arg1)
+  */
+
+static void
+ppc64v1_emit_int_call_1 (CORE_ADDR fn, int arg1)
+{
+  uint32_t buf[13];
+  uint32_t *p = buf;
+
+  /* Setup argument.  arg1 is a 16-bit value.  */
+  p += gen_limm (p, 3, arg1, 1);
+  p += GEN_STD (p, 2, 1, 40);	/* Save TOC.  */
+  p += gen_call (p, fn, 1, 1);
+  p += GEN_LD (p, 2, 1, 40);	/* Restore TOC.  */
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+}
+
+/* Likewise for ELFv2.  */
+
+static void
+ppc64v2_emit_int_call_1 (CORE_ADDR fn, int arg1)
+{
+  uint32_t buf[10];
+  uint32_t *p = buf;
+
+  /* Setup argument.  arg1 is a 16-bit value.  */
+  p += gen_limm (p, 3, arg1, 1);
+  p += GEN_STD (p, 2, 1, 24);	/* Save TOC.  */
+  p += gen_call (p, fn, 1, 0);
+  p += GEN_LD (p, 2, 1, 24);	/* Restore TOC.  */
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (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
+ppc64v1_emit_void_call_2 (CORE_ADDR fn, int arg1)
+{
+  uint32_t buf[17];
+  uint32_t *p = buf;
+
+  /* Save TOP.  0(30) is next-empty.  */
+  p += GEN_STD (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, 1);
+  p += GEN_STD (p, 2, 1, 40);	/* Save TOC.  */
+  p += gen_call (p, fn, 1, 1);
+  p += GEN_LD (p, 2, 1, 40);	/* Restore TOC.  */
+
+  /* Restore TOP */
+  p += GEN_LD (p, 3, 30, 0);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+}
+
+/* Likewise for ELFv2.  */
+
+static void
+ppc64v2_emit_void_call_2 (CORE_ADDR fn, int arg1)
+{
+  uint32_t buf[14];
+  uint32_t *p = buf;
+
+  /* Save TOP.  0(30) is next-empty.  */
+  p += GEN_STD (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, 1);
+  p += GEN_STD (p, 2, 1, 24);	/* Save TOC.  */
+  p += gen_call (p, fn, 1, 0);
+  p += GEN_LD (p, 2, 1, 24);	/* Restore TOC.  */
+
+  /* Restore TOP */
+  p += GEN_LD (p, 3, 30, 0);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+}
+
+/* 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 = 8;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* 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;
+}
+
+/* Table of emit ops for 64-bit ELFv1.  */
+
+static struct emit_ops ppc64v1_emit_ops_impl =
+{
+  ppc64v1_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,
+  ppc_emit_goto,
+  ppc_write_goto_address,
+  ppc64_emit_const,
+  ppc64v1_emit_call,
+  ppc64v1_emit_reg,
+  ppc64_emit_pop,
+  ppc64_emit_stack_flush,
+  ppc64_emit_zero_ext,
+  ppc64_emit_swap,
+  ppc_emit_stack_adjust,
+  ppc64v1_emit_int_call_1,
+  ppc64v1_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
+};
+
+/* Table of emit ops for 64-bit ELFv2.  */
+
+static struct emit_ops ppc64v2_emit_ops_impl =
+{
+  ppc64v2_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,
+  ppc_emit_goto,
+  ppc_write_goto_address,
+  ppc64_emit_const,
+  ppc64v2_emit_call,
+  ppc64v2_emit_reg,
+  ppc64_emit_pop,
+  ppc64_emit_stack_flush,
+  ppc64_emit_zero_ext,
+  ppc64_emit_swap,
+  ppc_emit_stack_adjust,
+  ppc64v2_emit_int_call_1,
+  ppc64v2_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
+};
+
+#endif
+
+/* Implementation of linux_target_ops method "emit_ops".  */
+
+static struct emit_ops *
+ppc_emit_ops (void)
+{
+#ifdef __powerpc64__
+  struct regcache *regcache = get_thread_regcache (current_thread, 0);
+
+  if (register_size (regcache->tdesc, 0) == 8)
+    {
+#if _CALL_ELF == 2
+      /* XXX determine this at run-time based on the actual target? */
+      return &ppc64v2_emit_ops_impl;
+#else
+      return &ppc64v1_emit_ops_impl;
+#endif
+    }
+#endif
+  return &ppc_emit_ops_impl;
+}
+
 /* Implementation of linux_target_ops method "get_ipa_tdesc_idx".  */
 
 static int
@@ -1514,7 +3110,7 @@ struct linux_target_ops the_low_target = {
   ppc_supports_tracepoints,
   ppc_get_thread_area,
   ppc_install_fast_tracepoint_jump_pad,
-  NULL, /* emit_ops */
+  ppc_emit_ops,
   ppc_get_min_fast_tracepoint_insn_len,
   NULL, /* supports_range_stepping */
   NULL, /* breakpoint_kind_from_current_state */
-- 
2.7.2

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

* Re: [PATCH 3/4 v2] gdbserver: Add powerpc fast tracepoint support.
  2016-03-14 22:10   ` [PATCH 3/4 v2] " Marcin Kościelnicki
@ 2016-03-16 16:58     ` Ulrich Weigand
  2016-03-16 17:55       ` Marcin Kościelnicki
  0 siblings, 1 reply; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-16 16:58 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: gdb-patches, Marcin Kościelnicki

Marcin Kościelnicki wrote:

> I'm not sure how to properly determine whether ELFv1 or ELFv2 is in use
> by the target, so I assume it's the same ABI as in gdbserver itself.

That's a generally sensible assumption.  In principle, you can check
which ABI the target is using by checking the e_flags field in the
ELF header.  The problem for gdbserver is that it usually doesn't
access the ELF file.  However, the ELF header is mapped into target
memory, so could be checked there.  Yet again, the *address* of the
ELF header is not very easily detectable without making assumptions
on how memory is layed out.

The best bet would probably be to determine the AT_PHDR auxillary vector,
which gives you the address of the *program headers* for the main
executable in the target, and then round that address down to the page
size boundary.  This should give you the address of the ELF header,
when making the assumption that the linker places program headers
in the fist page, following the ELF header.  This is not necessarily
guaranteed by the ELF format, but is what all linkers happen to do.

> Allocating the jump pad buffer needs a mention.  On powerpc64, IPA simply
> scans from 0x10000000 (the executable load address) downwards until it
> find a free address.  However, on 32-bit, ld.so loads dynamic libraries
> there, and they can easily cause us to exceed the 32MiB branch range -
> so, instead I aim right after the executable, at sbrk(0).  This will
> of course cause further memory allocation via brk to fail, but glibc
> transparently falls back to mmap in this case, so that's not a problem.
> Of course, given a program with large data/bss section, this might
> exceed the branch range as well, so perhaps some better heuristic is
> in order here.

These heuristics seem reasonable to me.

> This fixes get_raw_reg for 32-bit (ULONGEST was used to read the
> registers dumped by jump pad instead of unsigned long).  Also slightly
> optimizes gen_limm and fixes a few comments.

> +alloc_jump_pad_buffer (size_t size)
> +{
> +#ifdef __powerpc64__
> +  uintptr_t addr;
> +  int pagesize;
> +  void *res;
> +
> +  pagesize = sysconf (_SC_PAGE_SIZE);
> +  if (pagesize == -1)
> +    perror_with_name ("sysconf");
> +
> +  addr = 0x10000000 - size;

It also would be preferable to dynamically determine the actual
load address, since 0x10000000 is just the default, which can
be changed e.g. via linker script or due to PIE address randomization.

You might again use the AT_PHDR auxillary vector (which is what
Wei-cheng's patches did).

> +/* 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)
> +{
> +#ifdef __powerpc64__
> +  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);
> +  int is_64 = register_size (regcache->tdesc, 0) == 8;
> +#endif
> +  long res;
> +
> +#ifdef __powerpc64__
> +  if (is_64)
> +    res = ptrace (PTRACE_PEEKUSER, lwpid, (long) PT_R13 * sizeof (long),
> +		  (long) 0);
> +  else
> +#endif
> +    res = ptrace (PTRACE_PEEKUSER, lwpid, (long) PT_R2 * sizeof (long),
> +		  (long) 0);

Was there a particular reason why you changed to using direct ptrace
calls instead of collecting the value from the regcache as in the
original patch?

> +/* GEN_LOAD and GEN_STORE generate 64- or 32-bit load/store for ppc64 or ppc32
> +   respectively.  They are primary used for save/restore GPRs in jump-pad,
> +   not used for bytecode compiling.  */
> +
> +#if defined __powerpc64__
> +#define GEN_LOAD(buf, rt, ra, si)	(is_64 ? GEN_LD (buf, rt, ra, si) : \
> +						 GEN_LWZ (buf, rt, ra, si))
> +#define GEN_STORE(buf, rt, ra, si)	(is_64 ? GEN_STD (buf, rt, ra, si) : \
> +						 GEN_STW (buf, rt, ra, si))

Huh, using the is_64 variable from the surrounding routine without
passing it in as macro argument is probably not the best idea :-)

> +#if _CALL_ELF == 2
> +  /* XXX is there a way to get this dynamically from the inferior?  */
> +  int is_opd = 0;

See above.


Otherwise, this looks good to me.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH 4/4] gdbserver: Add emit_ops for powerpc.
  2016-03-14 22:25 ` [PATCH 4/4] gdbserver: Add emit_ops for powerpc Marcin Kościelnicki
@ 2016-03-16 17:16   ` Ulrich Weigand
  2016-03-18 15:10     ` [PATCH v2 " Marcin Kościelnicki
  0 siblings, 1 reply; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-16 17:16 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: gdb-patches, Marcin Kościelnicki

Marcin Kościelnicki wrote:

> gdb/gdbserver/ChangeLog:
> 
> 2016-03-14  Wei-cheng Wang  <cole945@gmail.com>
> 	    Marcin Kościelnicki  <koriakin@0x04.net>
> 
> 	* linux-ppc-low.c (emit_insns): New function.
> 	(__EMIT_ASM, _EMIT_ASM, EMIT_ASM): New macros.
> 	(ppc_emit_prologue): New function.
> 	(ppc_emit_epilogue): New function.
> 	(ppc_emit_add): New function.
> 	(ppc_emit_sub): New function.
> 	(ppc_emit_mul): New function.
> 	(ppc_emit_lsh): New function.
> 	(ppc_emit_rsh_signed): New function.
> 	(ppc_emit_rsh_unsigned): New function.
> 	(ppc_emit_ext): New function.
> 	(ppc_emit_zero_ext): New function.
> 	(ppc_emit_log_not): New function.
> 	(ppc_emit_bit_and): New function.
> 	(ppc_emit_bit_or): New function.
> 	(ppc_emit_bit_xor): New function.
> 	(ppc_emit_bit_not): New function.
> 	(ppc_emit_equal): New function.
> 	(ppc_emit_less_signed): New function.
> 	(ppc_emit_less_unsigned): New function.
> 	(ppc_emit_ref): New function.
> 	(ppc_emit_const): New function.
> 	(ppc_emit_reg): New function.
> 	(ppc_emit_pop): New function.
> 	(ppc_emit_stack_flush): New function.
> 	(ppc_emit_swap): New function.
> 	(ppc_emit_stack_adjust): New function.
> 	(ppc_emit_call): New function.
> 	(ppc_emit_int_call_1): New function.
> 	(ppc_emit_void_call_2): New function.
> 	(ppc_emit_if_goto): New function.
> 	(ppc_emit_goto): New function.
> 	(ppc_emit_eq_goto): New function.
> 	(ppc_emit_ne_goto): New function.
> 	(ppc_emit_lt_goto): New function.
> 	(ppc_emit_le_goto): New function.
> 	(ppc_emit_gt_goto): New function.
> 	(ppc_emit_ge_goto): New function.
> 	(ppc_write_goto_address): New function.
> 	(ppc_emit_ops_impl): New static variable.
> 	(ppc64v1_emit_prologue): New function.
> 	(ppc64v2_emit_prologue): New function.
> 	(ppc64_emit_epilogue): New function.
> 	(ppc64_emit_add): New function.
> 	(ppc64_emit_sub): New function.
> 	(ppc64_emit_mul): New function.
> 	(ppc64_emit_lsh): New function.
> 	(ppc64_emit_rsh_signed): New function.
> 	(ppc64_emit_rsh_unsigned): New function.
> 	(ppc64_emit_ext): New function.
> 	(ppc64_emit_zero_ext): New function.
> 	(ppc64_emit_log_not): New function.
> 	(ppc64_emit_bit_and): New function.
> 	(ppc64_emit_bit_or): New function.
> 	(ppc64_emit_bit_xor): New function.
> 	(ppc64_emit_bit_not): New function.
> 	(ppc64_emit_equal): New function.
> 	(ppc64_emit_less_signed): New function.
> 	(ppc64_emit_less_unsigned): New function.
> 	(ppc64_emit_ref): New function.
> 	(ppc64_emit_const): New function.
> 	(ppc64v1_emit_reg): New function.
> 	(ppc64v2_emit_reg): New function.
> 	(ppc64_emit_pop): New function.
> 	(ppc64_emit_stack_flush): New function.
> 	(ppc64_emit_swap): New function.
> 	(ppc64v1_emit_call): New function.
> 	(ppc64v2_emit_call): New function.
> 	(ppc64v1_emit_int_call_1): New function.
> 	(ppc64v2_emit_int_call_1): New function.
> 	(ppc64v1_emit_void_call_2): New function.
> 	(ppc64v2_emit_void_call_2): New function.
> 	(ppc64_emit_if_goto): New function.
> 	(ppc64_emit_eq_goto): New function.
> 	(ppc64_emit_ne_goto): New function.
> 	(ppc64_emit_lt_goto): New function.
> 	(ppc64_emit_le_goto): New function.
> 	(ppc64_emit_gt_goto): New function.
> 	(ppc64_emit_ge_goto): New function.
> 	(ppc64v1_emit_ops_impl): New static variable.
> 	(ppc64v2_emit_ops_impl): New static variable.
> 	(ppc_emit_ops): New function.
> 	(linux_low_target): Wire in ppc_emit_ops.

This is OK once the rest is in.

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH 3/4 v2] gdbserver: Add powerpc fast tracepoint support.
  2016-03-16 16:58     ` Ulrich Weigand
@ 2016-03-16 17:55       ` Marcin Kościelnicki
  2016-03-17  6:30         ` Ulrich Weigand
  0 siblings, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-16 17:55 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches

On 16/03/16 17:58, Ulrich Weigand wrote:
> Marcin Kościelnicki wrote:
>
>> I'm not sure how to properly determine whether ELFv1 or ELFv2 is in use
>> by the target, so I assume it's the same ABI as in gdbserver itself.
>
> That's a generally sensible assumption.  In principle, you can check
> which ABI the target is using by checking the e_flags field in the
> ELF header.  The problem for gdbserver is that it usually doesn't
> access the ELF file.  However, the ELF header is mapped into target
> memory, so could be checked there.  Yet again, the *address* of the
> ELF header is not very easily detectable without making assumptions
> on how memory is layed out.
>
> The best bet would probably be to determine the AT_PHDR auxillary vector,
> which gives you the address of the *program headers* for the main
> executable in the target, and then round that address down to the page
> size boundary.  This should give you the address of the ELF header,
> when making the assumption that the linker places program headers
> in the fist page, following the ELF header.  This is not necessarily
> guaranteed by the ELF format, but is what all linkers happen to do.

I'll try to do that.  Seems like a bit of work, but it's only called 
once per installed pad / emitted expression, so should be OK.
>
>> Allocating the jump pad buffer needs a mention.  On powerpc64, IPA simply
>> scans from 0x10000000 (the executable load address) downwards until it
>> find a free address.  However, on 32-bit, ld.so loads dynamic libraries
>> there, and they can easily cause us to exceed the 32MiB branch range -
>> so, instead I aim right after the executable, at sbrk(0).  This will
>> of course cause further memory allocation via brk to fail, but glibc
>> transparently falls back to mmap in this case, so that's not a problem.
>> Of course, given a program with large data/bss section, this might
>> exceed the branch range as well, so perhaps some better heuristic is
>> in order here.
>
> These heuristics seem reasonable to me.
>
>> This fixes get_raw_reg for 32-bit (ULONGEST was used to read the
>> registers dumped by jump pad instead of unsigned long).  Also slightly
>> optimizes gen_limm and fixes a few comments.
>
>> +alloc_jump_pad_buffer (size_t size)
>> +{
>> +#ifdef __powerpc64__
>> +  uintptr_t addr;
>> +  int pagesize;
>> +  void *res;
>> +
>> +  pagesize = sysconf (_SC_PAGE_SIZE);
>> +  if (pagesize == -1)
>> +    perror_with_name ("sysconf");
>> +
>> +  addr = 0x10000000 - size;
>
> It also would be preferable to dynamically determine the actual
> load address, since 0x10000000 is just the default, which can
> be changed e.g. via linker script or due to PIE address randomization.
>
> You might again use the AT_PHDR auxillary vector (which is what
> Wei-cheng's patches did).

Alright, I'll do that (and throw it in for aarch64 as well, code should 
be near-identical).
>
>> +/* 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)
>> +{
>> +#ifdef __powerpc64__
>> +  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);
>> +  int is_64 = register_size (regcache->tdesc, 0) == 8;
>> +#endif
>> +  long res;
>> +
>> +#ifdef __powerpc64__
>> +  if (is_64)
>> +    res = ptrace (PTRACE_PEEKUSER, lwpid, (long) PT_R13 * sizeof (long),
>> +		  (long) 0);
>> +  else
>> +#endif
>> +    res = ptrace (PTRACE_PEEKUSER, lwpid, (long) PT_R2 * sizeof (long),
>> +		  (long) 0);
>
> Was there a particular reason why you changed to using direct ptrace
> calls instead of collecting the value from the regcache as in the
> original patch?

Not really, I just happened to had this bit written before I learned of 
Wei-cheng's patches.  What are your preferences here?

>
>> +/* GEN_LOAD and GEN_STORE generate 64- or 32-bit load/store for ppc64 or ppc32
>> +   respectively.  They are primary used for save/restore GPRs in jump-pad,
>> +   not used for bytecode compiling.  */
>> +
>> +#if defined __powerpc64__
>> +#define GEN_LOAD(buf, rt, ra, si)	(is_64 ? GEN_LD (buf, rt, ra, si) : \
>> +						 GEN_LWZ (buf, rt, ra, si))
>> +#define GEN_STORE(buf, rt, ra, si)	(is_64 ? GEN_STD (buf, rt, ra, si) : \
>> +						 GEN_STW (buf, rt, ra, si))
>
> Huh, using the is_64 variable from the surrounding routine without
> passing it in as macro argument is probably not the best idea :-)

I'll change that.

>
>> +#if _CALL_ELF == 2
>> +  /* XXX is there a way to get this dynamically from the inferior?  */
>> +  int is_opd = 0;
>
> See above.
>
>
> Otherwise, this looks good to me.
>
> Thanks,
> Ulrich
>

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

* Re: [PATCH 3/4 v2] gdbserver: Add powerpc fast tracepoint support.
  2016-03-16 17:55       ` Marcin Kościelnicki
@ 2016-03-17  6:30         ` Ulrich Weigand
  2016-03-18 15:09           ` [PATCH v2 3/4] " Marcin Kościelnicki
  0 siblings, 1 reply; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-17  6:30 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: gdb-patches

Marcin Kościelnicki wrote:
> On 16/03/16 17:58, Ulrich Weigand wrote:
> > Was there a particular reason why you changed to using direct ptrace
> > calls instead of collecting the value from the regcache as in the
> > original patch?
> 
> Not really, I just happened to had this bit written before I learned of 
> Wei-cheng's patches.  What are your preferences here?

I think using collect_register_by_name is probably better.  Then you
also shouldn't need to do this:

+#ifdef __powerpc64__
+  if (!is_64)
+    *addr &= 0xffffffffull;
+#endif

because that should be handled automatically by the regcache logic.

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* [PATCH 2/4 v2] IPA: Add alloc_jump_pad_buffer target hook.
  2016-03-13  2:32 ` [PATCH 2/3] IPA: Add alloc_jump_pad_buffer target hook Marcin Kościelnicki
@ 2016-03-18 15:08   ` Marcin Kościelnicki
  2016-03-29 18:18     ` Ulrich Weigand
  0 siblings, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-18 15:08 UTC (permalink / raw)
  To: gdb-patches; +Cc: Marcin Kościelnicki

Targets may have various requirements on the required location of the jump
pad area.  Currently IPA allocates it at the lowest possible address,
so that it is reachable by branches from the executable.  However, this
fails on powerpc, which has executable link address (0x10000000) much
larger than branch reach (+/- 32MiB).

This makes jump pad buffer allocation a target hook instead.  The current
implementations are as follows:

- i386: Branches can reach anywhere, so just mmap it.  This avoids
  the linear search dance.
- x86_64: Branches have +/-2GiB of reach, and executable is loaded low,
  so just call mmap with MAP_32BIT.  Likewise avoids the linear search.
- aarch64: Branches have +-128MiB of reach, executable loaded at 4MiB.
  Do a linear search from 4MiB-size downwards to page_size.

gdb/gdbserver/ChangeLog:

	* linux-aarch64-ipa.c: Add <sys/mman.h> include.
	(alloc_jump_pad_buffer): New function.
	* linux-amd64-ipa.c: Add <sys/mman.h> include.
	(alloc_jump_pad_buffer): New function.
	* linux-i386-ipa.c (alloc_jump_pad_buffer): New function.
	* tracepoint.c (getauxval) [!HAVE_GETAUXVAL]: New function.
	(initialize_tracepoint): Delegate to alloc_jump_pad_buffer.
	* tracepoint.h (alloc_jump_pad_buffer): New prototype.
	(getauxval) [!HAVE_GETAUXVAL]: New prototype.
---
This version changes aarch64 to use getauxval(AT_PHDR) instead of
hardcoded default load address.

Note: this patch will need testing on aarch64, I don't have a machine
for that.  The code works for powerpc64 though.

 gdb/gdbserver/ChangeLog           | 12 +++++++++
 gdb/gdbserver/linux-aarch64-ipa.c | 50 ++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/linux-amd64-ipa.c   | 18 +++++++++++++
 gdb/gdbserver/linux-i386-ipa.c    | 15 +++++++++++
 gdb/gdbserver/tracepoint.c        | 53 +++++++++++++++++++++++++--------------
 gdb/gdbserver/tracepoint.h        |  4 +++
 6 files changed, 133 insertions(+), 19 deletions(-)

diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 31120c5..46e9ac2 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,15 @@
+2016-03-13  Marcin Kościelnicki  <koriakin@0x04.net>
+
+	* linux-aarch64-ipa.c: Add <sys/mman.h> include.
+	(alloc_jump_pad_buffer): New function.
+	* linux-amd64-ipa.c: Add <sys/mman.h> include.
+	(alloc_jump_pad_buffer): New function.
+	* linux-i386-ipa.c (alloc_jump_pad_buffer): New function.
+	* tracepoint.c (getauxval) [!HAVE_GETAUXVAL]: New function.
+	(initialize_tracepoint): Delegate to alloc_jump_pad_buffer.
+	* tracepoint.h (alloc_jump_pad_buffer): New prototype.
+	(getauxval) [!HAVE_GETAUXVAL]: New prototype.
+
 2016-03-12  Marcin Kościelnicki  <koriakin@0x04.net>
 
 	* linux-aarch64-ipa.c: Rename gdb_agent_get_raw_reg to get_raw_reg.
diff --git a/gdb/gdbserver/linux-aarch64-ipa.c b/gdb/gdbserver/linux-aarch64-ipa.c
index 00cbf3e..50caeae 100644
--- a/gdb/gdbserver/linux-aarch64-ipa.c
+++ b/gdb/gdbserver/linux-aarch64-ipa.c
@@ -19,7 +19,11 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
+#include <sys/mman.h>
 #include "tracepoint.h"
+#ifdef HAVE_GETAUXVAL
+#include <sys/auxv.h>
+#endif
 
 /* Defined in auto-generated file aarch64.c.  */
 void init_registers_aarch64 (void);
@@ -153,6 +157,52 @@ get_ipa_tdesc (int idx)
   return tdesc_aarch64;
 }
 
+/* Allocate buffer for the jump pads.  The branch instruction has a reach
+   of +/- 128MiB, and the executable is loaded at 0x400000 (4MiB).
+   To maximize the area of executable that can use tracepoints, try
+   allocating at 0x400000 - size initially, decreasing until we hit
+   a free area.  */
+
+void *
+alloc_jump_pad_buffer (size_t size)
+{
+  uintptr_t addr;
+  uintptr_t exec_base = getauxval (AT_PHDR);
+  int pagesize;
+  void *res;
+
+  if (exec_base == 0)
+    exec_base = 0x400000;
+
+  pagesize = sysconf (_SC_PAGE_SIZE);
+  if (pagesize == -1)
+    perror_with_name ("sysconf");
+
+  addr = exec_base - size;
+
+  /* size should already be page-aligned, but this can't hurt.  */
+  addr &= ~(pagesize - 1);
+
+  /* Search for a free area.  If we hit 0, we're out of luck.  */
+  for (; addr; addr -= pagesize)
+    {
+      /* No MAP_FIXED - we don't want to zap someone's mapping.  */
+      res = mmap ((void *) addr, size,
+		  PROT_READ | PROT_WRITE | PROT_EXEC,
+		  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+      /* If we got what we wanted, return.  */
+      if ((uintptr_t) res == addr)
+	return res;
+
+      /* If we got a mapping, but at a wrong address, undo it.  */
+      if (res != MAP_FAILED)
+	munmap (res, size);
+    }
+
+  return NULL;
+}
+
 void
 initialize_low_tracepoint (void)
 {
diff --git a/gdb/gdbserver/linux-amd64-ipa.c b/gdb/gdbserver/linux-amd64-ipa.c
index 70889d2..9ee0fe8 100644
--- a/gdb/gdbserver/linux-amd64-ipa.c
+++ b/gdb/gdbserver/linux-amd64-ipa.c
@@ -19,6 +19,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
+#include <sys/mman.h>
 #include "tracepoint.h"
 #include "linux-x86-tdesc.h"
 
@@ -190,6 +191,23 @@ get_ipa_tdesc (int idx)
     }
 }
 
+/* Allocate buffer for the jump pads.  Since we're using 32-bit jumps
+   to reach them, and the executable is at low addresses, MAP_32BIT
+   works just fine.  Shared libraries, being allocated at the top,
+   are unfortunately out of luck.  */
+
+void *
+alloc_jump_pad_buffer (size_t size)
+{
+  void *res = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC,
+		    MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, 1, 0);
+
+  if (res == MAP_FAILED)
+    return NULL;
+
+  return res;
+}
+
 void
 initialize_low_tracepoint (void)
 {
diff --git a/gdb/gdbserver/linux-i386-ipa.c b/gdb/gdbserver/linux-i386-ipa.c
index 7159eee..52c0581 100644
--- a/gdb/gdbserver/linux-i386-ipa.c
+++ b/gdb/gdbserver/linux-i386-ipa.c
@@ -269,6 +269,21 @@ get_ipa_tdesc (int idx)
     }
 }
 
+/* Allocate buffer for the jump pads.  On i386, we can reach an arbitrary
+   address with a jump instruction, so just allocate normally.  */
+
+void *
+alloc_jump_pad_buffer (size_t size)
+{
+  void *res = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC,
+		    MAP_PRIVATE | MAP_ANONYMOUS, 1, 0);
+
+  if (res == MAP_FAILED)
+    return NULL;
+
+  return res;
+}
+
 void
 initialize_low_tracepoint (void)
 {
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index 061e161..f90f19e 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -216,6 +216,34 @@ static struct ipa_sym_addresses ipa_sym_addrs;
 
 static int read_inferior_integer (CORE_ADDR symaddr, int *val);
 
+#if !defined HAVE_GETAUXVAL && defined IN_PROCESS_AGENT
+/* Retrieve the value of TYPE from the auxiliary vector.  If TYPE is not
+   found, 0 is returned.  This function is provided if glibc is too old.  */
+
+unsigned long
+getauxval (unsigned long type)
+{
+  unsigned long data[2];
+  FILE *f = fopen ("/proc/self/auxv", "r");
+  unsigned long value = 0;
+
+  if (f == NULL)
+    return 0;
+
+  while (fread (data, sizeof (data), 1, f) > 0)
+    {
+      if (data[0] == type)
+	{
+	  value = data[1];
+	  break;
+	}
+    }
+
+  fclose (f);
+  return value;
+}
+#endif
+
 /* Returns true if both the in-process agent library and the static
    tracepoints libraries are loaded in the inferior, and agent has
    capability on static tracepoints.  */
@@ -7400,35 +7428,22 @@ initialize_tracepoint (void)
 
 #ifdef IN_PROCESS_AGENT
   {
-    uintptr_t addr;
     int pagesize;
+    size_t jump_pad_size;
 
     pagesize = sysconf (_SC_PAGE_SIZE);
     if (pagesize == -1)
       perror_with_name ("sysconf");
 
-    gdb_tp_heap_buffer = (char *) xmalloc (5 * 1024 * 1024);
-
 #define SCRATCH_BUFFER_NPAGES 20
 
-    /* Allocate scratch buffer aligned on a page boundary, at a low
-       address (close to the main executable's code).  */
-    for (addr = pagesize; addr != 0; addr += pagesize)
-      {
-	gdb_jump_pad_buffer
-	  = (char *) mmap ((void *) addr,
-			   pagesize * SCRATCH_BUFFER_NPAGES,
-			   PROT_READ | PROT_WRITE | PROT_EXEC,
-			   MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
-			   -1, 0);
-	if (gdb_jump_pad_buffer != MAP_FAILED)
-	  break;
-      }
+    jump_pad_size = pagesize * SCRATCH_BUFFER_NPAGES;
 
-    if (addr == 0)
+    gdb_tp_heap_buffer = (char *) xmalloc (5 * 1024 * 1024);
+    gdb_jump_pad_buffer = alloc_jump_pad_buffer (jump_pad_size);
+    if (gdb_jump_pad_buffer == NULL)
       perror_with_name ("mmap");
-
-    gdb_jump_pad_buffer_end = gdb_jump_pad_buffer + pagesize * SCRATCH_BUFFER_NPAGES;
+    gdb_jump_pad_buffer_end = gdb_jump_pad_buffer + jump_pad_size;
   }
 
   gdb_trampoline_buffer = gdb_trampoline_buffer_end = 0;
diff --git a/gdb/gdbserver/tracepoint.h b/gdb/gdbserver/tracepoint.h
index df815ef..3712881 100644
--- a/gdb/gdbserver/tracepoint.h
+++ b/gdb/gdbserver/tracepoint.h
@@ -132,6 +132,10 @@ void supply_static_tracepoint_registers (struct regcache *regcache,
 					 CORE_ADDR pc);
 void set_trampoline_buffer_space (CORE_ADDR begin, CORE_ADDR end,
 				  char *errmsg);
+void *alloc_jump_pad_buffer (size_t size);
+#ifdef HAVE_GETAUXVAL
+unsigned long getauxval (unsigned long type);
+#endif
 #else
 void stop_tracing (void);
 
-- 
2.7.3

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

* [PATCH v2 3/4] gdbserver: Add powerpc fast tracepoint support.
  2016-03-17  6:30         ` Ulrich Weigand
@ 2016-03-18 15:09           ` Marcin Kościelnicki
  2016-03-29 18:23             ` Ulrich Weigand
  2016-03-30 14:52             ` Simon Marchi
  0 siblings, 2 replies; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-18 15:09 UTC (permalink / raw)
  To: uweigand; +Cc: gdb-patches, Marcin Kościelnicki

gdb/gdbserver/ChangeLog:

2016-03-13  Wei-cheng Wang  <cole945@gmail.com>
	    Marcin Kościelnicki  <koriakin@0x04.net>

	* Makefile.in: Add powerpc-*-ipa.o
	* configure.srv: Add ipa_obj for powerpc*-linux.
	* linux-ppc-ipa.c: New file.
	* linux-ppc-low.c: Added linux-ppc-tdesc.h, ax.h,
	tracepoint.h includes.
	(PPC_FIELD): New macro.
	(PPC_SEXT): New macro.
	(PPC_OP6): New macro.
	(PPC_BO): New macro.
	(PPC_LI): New macro.
	(PPC_BD): New macro.
	(init_registers_*): Move prototype to linux-ppc-tdesc.h.
	(tdesc_*): Move declaration to linux-ppc-tdesc.h.
	(ppc_get_hwcap): Rename to ppc_get_auxv and add type parameter.
	(ppc_get_thread_area): New function.
	(is_elfv2_inferior): New function.
	(gen_ds_form): New function.
	(GEN_STD): New macro.
	(GEN_STDU): New macro.
	(GEN_LD): New macro.
	(GEN_LDU): New macro.
	(gen_d_form): New function.
	(GEN_ADDI): New macro.
	(GEN_ADDIS): New macro.
	(GEN_LI): New macro.
	(GEN_LIS): New macro.
	(GEN_ORI): New macro.
	(GEN_ORIS): New macro.
	(GEN_LWZ): New macro.
	(GEN_STW): New macro.
	(GEN_STWU): New macro.
	(gen_xfx_form): New function.
	(GEN_MFSPR): New macro.
	(GEN_MTSPR): New macro.
	(GEN_MFCR): New macro.
	(GEN_MTCR): New macro.
	(GEN_SYNC): New macro.
	(GEN_LWSYNC): New macro.
	(gen_x_form): New function.
	(GEN_OR): New macro.
	(GEN_MR): New macro.
	(GEN_LWARX): New macro.
	(GEN_STWCX): New macro.
	(GEN_CMPW): New macro.
	(gen_md_form): New function.
	(GEN_RLDICL): New macro.
	(GEN_RLDICR): New macro.
	(gen_i_form): New function.
	(GEN_B): New macro.
	(GEN_BL): New macro.
	(gen_b_form): New function.
	(GEN_BNE): New macro.
	(GEN_LOAD): New macro.
	(GEN_STORE): New macro.
	(gen_limm): New function.
	(gen_atomic_xchg): New function.
	(gen_call): New function.
	(ppc_relocate_instruction): New function.
	(ppc_install_fast_tracepoint_jump_pad): New function.
	(ppc_get_min_fast_tracepoint_insn_len): New function.
	(ppc_get_ipa_tdesc_idx): New function.
	(the_low_target): Wire in the new functions.
	(initialize_low_arch) [!__powerpc64__]: Don'it initialize 64-bit
	tdescs.
	* linux-ppc-tdesc.h: New file.
---
 gdb/gdbserver/ChangeLog         |  69 ++++
 gdb/gdbserver/Makefile.in       |  48 +++
 gdb/gdbserver/configure.srv     |   2 +
 gdb/gdbserver/linux-ppc-ipa.c   | 245 +++++++++++
 gdb/gdbserver/linux-ppc-low.c   | 880 ++++++++++++++++++++++++++++++++++++----
 gdb/gdbserver/linux-ppc-tdesc.h | 101 +++++
 6 files changed, 1277 insertions(+), 68 deletions(-)
 create mode 100644 gdb/gdbserver/linux-ppc-ipa.c
 create mode 100644 gdb/gdbserver/linux-ppc-tdesc.h

diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 46e9ac2..60b5f21 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,72 @@
+2016-03-13  Wei-cheng Wang  <cole945@gmail.com>
+	    Marcin Kościelnicki  <koriakin@0x04.net>
+
+	* Makefile.in: Add powerpc-*-ipa.o
+	* configure.srv: Add ipa_obj for powerpc*-linux.
+	* linux-ppc-ipa.c: New file.
+	* linux-ppc-low.c: Added linux-ppc-tdesc.h, ax.h,
+	tracepoint.h includes.
+	(PPC_FIELD): New macro.
+	(PPC_SEXT): New macro.
+	(PPC_OP6): New macro.
+	(PPC_BO): New macro.
+	(PPC_LI): New macro.
+	(PPC_BD): New macro.
+	(init_registers_*): Move prototype to linux-ppc-tdesc.h.
+	(tdesc_*): Move declaration to linux-ppc-tdesc.h.
+	(ppc_get_hwcap): Rename to ppc_get_auxv and add type parameter.
+	(ppc_get_thread_area): New function.
+	(is_elfv2_inferior): New function.
+	(gen_ds_form): New function.
+	(GEN_STD): New macro.
+	(GEN_STDU): New macro.
+	(GEN_LD): New macro.
+	(GEN_LDU): New macro.
+	(gen_d_form): New function.
+	(GEN_ADDI): New macro.
+	(GEN_ADDIS): New macro.
+	(GEN_LI): New macro.
+	(GEN_LIS): New macro.
+	(GEN_ORI): New macro.
+	(GEN_ORIS): New macro.
+	(GEN_LWZ): New macro.
+	(GEN_STW): New macro.
+	(GEN_STWU): New macro.
+	(gen_xfx_form): New function.
+	(GEN_MFSPR): New macro.
+	(GEN_MTSPR): New macro.
+	(GEN_MFCR): New macro.
+	(GEN_MTCR): New macro.
+	(GEN_SYNC): New macro.
+	(GEN_LWSYNC): New macro.
+	(gen_x_form): New function.
+	(GEN_OR): New macro.
+	(GEN_MR): New macro.
+	(GEN_LWARX): New macro.
+	(GEN_STWCX): New macro.
+	(GEN_CMPW): New macro.
+	(gen_md_form): New function.
+	(GEN_RLDICL): New macro.
+	(GEN_RLDICR): New macro.
+	(gen_i_form): New function.
+	(GEN_B): New macro.
+	(GEN_BL): New macro.
+	(gen_b_form): New function.
+	(GEN_BNE): New macro.
+	(GEN_LOAD): New macro.
+	(GEN_STORE): New macro.
+	(gen_limm): New function.
+	(gen_atomic_xchg): New function.
+	(gen_call): New function.
+	(ppc_relocate_instruction): New function.
+	(ppc_install_fast_tracepoint_jump_pad): New function.
+	(ppc_get_min_fast_tracepoint_insn_len): New function.
+	(ppc_get_ipa_tdesc_idx): New function.
+	(the_low_target): Wire in the new functions.
+	(initialize_low_arch) [!__powerpc64__]: Don'it initialize 64-bit
+	tdescs.
+	* linux-ppc-tdesc.h: New file.
+
 2016-03-13  Marcin Kościelnicki  <koriakin@0x04.net>
 
 	* linux-aarch64-ipa.c: Add <sys/mman.h> include.
diff --git a/gdb/gdbserver/Makefile.in b/gdb/gdbserver/Makefile.in
index 257e9bf..11908d2 100644
--- a/gdb/gdbserver/Makefile.in
+++ b/gdb/gdbserver/Makefile.in
@@ -531,6 +531,54 @@ linux-aarch64-ipa.o: linux-aarch64-ipa.c
 aarch64-ipa.o: aarch64.c
 	$(IPAGENT_COMPILE) $<
 	$(POSTCOMPILE)
+linux-ppc-ipa.o: linux-ppc-ipa.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-32l-ipa.o: powerpc-32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-altivec32l-ipa.o: powerpc-altivec32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-cell32l-ipa.o: powerpc-cell32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-vsx32l-ipa.o: powerpc-vsx32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-32l-ipa.o: powerpc-isa205-32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-altivec32l-ipa.o: powerpc-isa205-altivec32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-vsx32l-ipa.o: powerpc-isa205-vsx32l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-e500l-ipa.o: powerpc-e500l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-64l-ipa.o: powerpc-64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-altivec64l-ipa.o: powerpc-altivec64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-cell64l-ipa.o: powerpc-cell64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-vsx64l-ipa.o: powerpc-vsx64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-64l-ipa.o: powerpc-isa205-64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-altivec64l-ipa.o: powerpc-isa205-altivec64l.c
+	$(IPAGENT_COMPILE) $<
+	$(POSTCOMPILE)
+powerpc-isa205-vsx64l-ipa.o: powerpc-isa205-vsx64l.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 a89b1d1..177e0a3 100644
--- a/gdb/gdbserver/configure.srv
+++ b/gdb/gdbserver/configure.srv
@@ -31,6 +31,7 @@ srv_amd64_linux_regobj="amd64-linux.o amd64-avx-linux.o amd64-avx512-linux.o amd
 
 ipa_i386_linux_regobj="i386-linux-ipa.o i386-avx-linux-ipa.o i386-avx512-linux-ipa.o i386-mpx-linux-ipa.o i386-mmx-linux-ipa.o"
 ipa_amd64_linux_regobj="amd64-linux-ipa.o amd64-avx-linux-ipa.o amd64-avx512-linux-ipa.o amd64-mpx-linux-ipa.o"
+ipa_ppc_linux_regobj="powerpc-32l-ipa.o powerpc-altivec32l-ipa.o powerpc-cell32l-ipa.o powerpc-vsx32l-ipa.o powerpc-isa205-32l-ipa.o powerpc-isa205-altivec32l-ipa.o powerpc-isa205-vsx32l-ipa.o powerpc-e500l-ipa.o powerpc-64l-ipa.o powerpc-altivec64l-ipa.o powerpc-cell64l-ipa.o powerpc-vsx64l-ipa.o powerpc-isa205-64l-ipa.o powerpc-isa205-altivec64l-ipa.o powerpc-isa205-vsx64l-ipa.o"
 
 srv_i386_32bit_xmlfiles="i386/32bit-core.xml i386/32bit-sse.xml i386/32bit-avx.xml i386/32bit-avx512.xml i386/32bit-mpx.xml"
 srv_i386_64bit_xmlfiles="i386/64bit-core.xml i386/64bit-sse.xml i386/64bit-avx.xml i386/64bit-avx512.xml i386/x32-core.xml i386/64bit-mpx.xml"
@@ -258,6 +259,7 @@ case "${target}" in
 			srv_linux_usrregs=yes
 			srv_linux_regsets=yes
 			srv_linux_thread_db=yes
+			ipa_obj="${ipa_ppc_linux_regobj} 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..8489c6e
--- /dev/null
+++ b/gdb/gdbserver/linux-ppc-ipa.c
@@ -0,0 +1,245 @@
+/* GNU/Linux/PowerPC specific low level interface, for the in-process
+   agent library for GDB.
+
+   Copyright (C) 2016 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 <sys/mman.h>
+#include "tracepoint.h"
+#include "linux-ppc-tdesc.h"
+#ifdef HAVE_GETAUXVAL
+#include <sys/auxv.h>
+#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] * sizeof (long));
+    }
+}
+
+/* Return the value of register REGNUM.  RAW_REGS is collected buffer
+   by jump pad.  This function is called by emit_reg.  */
+
+ULONGEST
+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 *(unsigned long *) (raw_regs
+			     + ppc_ft_collect_regmap[regnum] * sizeof (long));
+}
+
+/* Allocate buffer for the jump pads.  The branch instruction has a reach
+   of +/- 32MiB, and the executable is loaded at 0x10000000 (256MiB).
+
+   64-bit: To maximize the area of executable that can use tracepoints,
+   try allocating at 0x10000000 - size initially, decreasing until we hit
+   a free area.
+
+   32-bit: ld.so loads dynamic libraries right below the executable, so
+   we cannot depend on that area (dynamic libraries can be quite large).
+   Instead, aim right after the executable - at sbrk(0).  This will
+   cause future brk to fail, and malloc will fallback to mmap.  */
+
+void *
+alloc_jump_pad_buffer (size_t size)
+{
+#ifdef __powerpc64__
+  uintptr_t addr;
+  uintptr_t exec_base = getauxval (AT_PHDR);
+  int pagesize;
+  void *res;
+
+  if (exec_base == 0)
+    exec_base = 0x10000000;
+
+  pagesize = sysconf (_SC_PAGE_SIZE);
+  if (pagesize == -1)
+    perror_with_name ("sysconf");
+
+  addr = exec_base - size;
+
+  /* size should already be page-aligned, but this can't hurt.  */
+  addr &= ~(pagesize - 1);
+
+  /* Search for a free area.  If we hit 0, we're out of luck.  */
+  for (; addr; addr -= pagesize)
+    {
+      /* No MAP_FIXED - we don't want to zap someone's mapping.  */
+      res = mmap ((void *) addr, size,
+		  PROT_READ | PROT_WRITE | PROT_EXEC,
+		  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+      /* If we got what we wanted, return.  */
+      if ((uintptr_t) res == addr)
+	return res;
+
+      /* If we got a mapping, but at a wrong address, undo it.  */
+      if (res != MAP_FAILED)
+	munmap (res, size);
+    }
+
+  return NULL;
+#else
+  void *target = sbrk (0);
+  void *res = mmap (target, size, PROT_READ | PROT_WRITE | PROT_EXEC,
+		    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+  if (res == target)
+    return res;
+
+  if (res != MAP_FAILED)
+    munmap (res, size);
+
+  return NULL;
+#endif
+}
+
+/* Return target_desc to use for IPA, given the tdesc index passed by
+   gdbserver.  */
+
+const struct target_desc *
+get_ipa_tdesc (int idx)
+{
+  switch (idx)
+    {
+#ifdef __powerpc64__
+    case PPC_TDESC_BASE:
+      return tdesc_powerpc_64l;
+    case PPC_TDESC_ALTIVEC:
+      return tdesc_powerpc_altivec64l;
+    case PPC_TDESC_CELL:
+      return tdesc_powerpc_cell64l;
+    case PPC_TDESC_VSX:
+      return tdesc_powerpc_vsx64l;
+    case PPC_TDESC_ISA205:
+      return tdesc_powerpc_isa205_64l;
+    case PPC_TDESC_ISA205_ALTIVEC:
+      return tdesc_powerpc_isa205_altivec64l;
+    case PPC_TDESC_ISA205_VSX:
+      return tdesc_powerpc_isa205_vsx64l;
+#else
+    case PPC_TDESC_BASE:
+      return tdesc_powerpc_32l;
+    case PPC_TDESC_ALTIVEC:
+      return tdesc_powerpc_altivec32l;
+    case PPC_TDESC_CELL:
+      return tdesc_powerpc_cell32l;
+    case PPC_TDESC_VSX:
+      return tdesc_powerpc_vsx32l;
+    case PPC_TDESC_ISA205:
+      return tdesc_powerpc_isa205_32l;
+    case PPC_TDESC_ISA205_ALTIVEC:
+      return tdesc_powerpc_isa205_altivec32l;
+    case PPC_TDESC_ISA205_VSX:
+      return tdesc_powerpc_isa205_vsx32l;
+    case PPC_TDESC_E500:
+      return tdesc_powerpc_e500l;
+#endif
+    default:
+      internal_error (__FILE__, __LINE__,
+                     "unknown ipa tdesc index: %d", idx);
+#ifdef __powerpc64__
+      return tdesc_powerpc_64l;
+#else
+      return tdesc_powerpc_32l;
+#endif
+    }
+}
+
+
+/* Initialize ipa_tdesc and others.  */
+
+void
+initialize_low_tracepoint (void)
+{
+#ifdef __powerpc64__
+  init_registers_powerpc_64l ();
+  init_registers_powerpc_altivec64l ();
+  init_registers_powerpc_cell64l ();
+  init_registers_powerpc_vsx64l ();
+  init_registers_powerpc_isa205_64l ();
+  init_registers_powerpc_isa205_altivec64l ();
+  init_registers_powerpc_isa205_vsx64l ();
+#else
+  init_registers_powerpc_32l ();
+  init_registers_powerpc_altivec32l ();
+  init_registers_powerpc_cell32l ();
+  init_registers_powerpc_vsx32l ();
+  init_registers_powerpc_isa205_32l ();
+  init_registers_powerpc_isa205_altivec32l ();
+  init_registers_powerpc_isa205_vsx32l ();
+  init_registers_powerpc_e500l ();
+#endif
+}
diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c
index 49d27ee..be64401 100644
--- a/gdb/gdbserver/linux-ppc-low.c
+++ b/gdb/gdbserver/linux-ppc-low.c
@@ -24,70 +24,24 @@
 #include <asm/ptrace.h>
 
 #include "nat/ppc-linux.h"
+#include "linux-ppc-tdesc.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;
 
 
-/* Defined in auto-generated file powerpc-32l.c.  */
-void init_registers_powerpc_32l (void);
-extern const struct target_desc *tdesc_powerpc_32l;
-
-/* Defined in auto-generated file powerpc-altivec32l.c.  */
-void init_registers_powerpc_altivec32l (void);
-extern const struct target_desc *tdesc_powerpc_altivec32l;
-
-/* Defined in auto-generated file powerpc-cell32l.c.  */
-void init_registers_powerpc_cell32l (void);
-extern const struct target_desc *tdesc_powerpc_cell32l;
-
-/* Defined in auto-generated file powerpc-vsx32l.c.  */
-void init_registers_powerpc_vsx32l (void);
-extern const struct target_desc *tdesc_powerpc_vsx32l;
-
-/* Defined in auto-generated file powerpc-isa205-32l.c.  */
-void init_registers_powerpc_isa205_32l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_32l;
-
-/* Defined in auto-generated file powerpc-isa205-altivec32l.c.  */
-void init_registers_powerpc_isa205_altivec32l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_altivec32l;
-
-/* Defined in auto-generated file powerpc-isa205-vsx32l.c.  */
-void init_registers_powerpc_isa205_vsx32l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_vsx32l;
-
-/* Defined in auto-generated file powerpc-e500l.c.  */
-void init_registers_powerpc_e500l (void);
-extern const struct target_desc *tdesc_powerpc_e500l;
-
-/* Defined in auto-generated file powerpc-64l.c.  */
-void init_registers_powerpc_64l (void);
-extern const struct target_desc *tdesc_powerpc_64l;
-
-/* Defined in auto-generated file powerpc-altivec64l.c.  */
-void init_registers_powerpc_altivec64l (void);
-extern const struct target_desc *tdesc_powerpc_altivec64l;
-
-/* Defined in auto-generated file powerpc-cell64l.c.  */
-void init_registers_powerpc_cell64l (void);
-extern const struct target_desc *tdesc_powerpc_cell64l;
-
-/* Defined in auto-generated file powerpc-vsx64l.c.  */
-void init_registers_powerpc_vsx64l (void);
-extern const struct target_desc *tdesc_powerpc_vsx64l;
-
-/* Defined in auto-generated file powerpc-isa205-64l.c.  */
-void init_registers_powerpc_isa205_64l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_64l;
-
-/* Defined in auto-generated file powerpc-isa205-altivec64l.c.  */
-void init_registers_powerpc_isa205_altivec64l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_altivec64l;
-
-/* Defined in auto-generated file powerpc-isa205-vsx64l.c.  */
-void init_registers_powerpc_isa205_vsx64l (void);
-extern const struct target_desc *tdesc_powerpc_isa205_vsx64l;
-
 #define ppc_num_regs 73
 
 #ifdef __powerpc64__
@@ -342,7 +296,7 @@ ppc_set_pc (struct regcache *regcache, CORE_ADDR pc)
 
 
 static int
-ppc_get_hwcap (unsigned long *valp)
+ppc_get_auxv (unsigned long type, unsigned long *valp)
 {
   const struct target_desc *tdesc = current_process ()->tdesc;
   int wordsize = register_size (tdesc, 0);
@@ -354,7 +308,7 @@ ppc_get_hwcap (unsigned long *valp)
       if (wordsize == 4)
 	{
 	  unsigned int *data_p = (unsigned int *)data;
-	  if (data_p[0] == AT_HWCAP)
+	  if (data_p[0] == type)
 	    {
 	      *valp = data_p[1];
 	      return 1;
@@ -363,7 +317,7 @@ ppc_get_hwcap (unsigned long *valp)
       else
 	{
 	  unsigned long *data_p = (unsigned long *)data;
-	  if (data_p[0] == AT_HWCAP)
+	  if (data_p[0] == type)
 	    {
 	      *valp = data_p[1];
 	      return 1;
@@ -680,7 +634,7 @@ ppc_arch_setup (void)
   free_register_cache (regcache);
   if (ppc64_64bit_inferior_p (msr))
     {
-      ppc_get_hwcap (&ppc_hwcap);
+      ppc_get_auxv (AT_HWCAP, &ppc_hwcap);
       if (ppc_hwcap & PPC_FEATURE_CELL)
 	tdesc = tdesc_powerpc_cell64l;
       else if (ppc_hwcap & PPC_FEATURE_HAS_VSX)
@@ -714,7 +668,7 @@ ppc_arch_setup (void)
   tdesc = tdesc_powerpc_32l;
   current_process ()->tdesc = tdesc;
 
-  ppc_get_hwcap (&ppc_hwcap);
+  ppc_get_auxv (AT_HWCAP, &ppc_hwcap);
   if (ppc_hwcap & PPC_FEATURE_CELL)
     tdesc = tdesc_powerpc_cell32l;
   else if (ppc_hwcap & PPC_FEATURE_HAS_VSX)
@@ -756,12 +710,798 @@ ppc_arch_setup (void)
   current_process ()->tdesc = tdesc;
 }
 
+/* Implementation of linux_target_ops method "supports_tracepoints".  */
+
 static int
 ppc_supports_tracepoints (void)
 {
   return 1;
 }
 
+/* Get the thread area address.  This is used to recognize which
+   thread is which when tracing with the in-process agent library.  We
+   don't read anything from the address, and treat it as opaque; it's
+   the address itself that we assume is unique per-thread.  */
+
+static int
+ppc_get_thread_area (int lwpid, CORE_ADDR *addr)
+{
+  struct lwp_info *lwp = find_lwp_pid (pid_to_ptid (lwpid));
+  struct thread_info *thr = get_lwp_thread (lwp);
+  struct regcache *regcache = get_thread_regcache (thr, 1);
+  ULONGEST tp = 0;
+
+#ifdef __powerpc64__
+  if (register_size (regcache->tdesc, 0) == 8)
+    collect_register_by_name (regcache, "r13", &tp);
+  else
+#endif
+    collect_register_by_name (regcache, "r2", &tp);
+
+  *addr = tp;
+
+  return 0;
+}
+
+#ifdef __powerpc64__
+
+/* Returns 1 if inferior is using ELFv2 ABI.  Undefined for 32-bit
+   inferiors.  */
+
+static int
+is_elfv2_inferior (void)
+{
+  /* To be used as fallback if we're unable to determine the right result -
+     assume inferior uses the same ABI as gdbserver.  */
+#if _CALL_ELF == 2
+  const int def_res = 1;
+#else
+  const int def_res = 0;
+#endif
+  unsigned long phdr;
+  Elf64_Ehdr ehdr;
+
+  if (!ppc_get_auxv (AT_PHDR, &phdr))
+    return def_res;
+
+  /* Assume ELF header is at the beginning of the page where program headers
+     are located.  If it doesn't look like one, bail.  */
+
+  read_inferior_memory (phdr & ~0xfff, (unsigned char *) &ehdr, sizeof ehdr);
+  if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG))
+    return def_res;
+
+  return (ehdr.e_flags & EF_PPC64_ABI) == 2;
+}
+
+#endif
+
+/* 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)
+#define GEN_STWU(buf, rt, ra, si)	gen_d_form (buf, 37, rt, ra, si)
+
+/* Generate a xfx-form instruction in BUF and return the number of bytes
+   written.
+
+   0      6     11         21        31 32
+   | OPCD | RST |    RI    |    XO   |/|  */
+
+static int
+gen_xfx_form (uint32_t *buf, int opcd, int rst, int ri, int xo)
+{
+  uint32_t insn;
+  unsigned int n = ((ri & 0x1f) << 5) | ((ri >> 5) & 0x1f);
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((rst & ~0x1f) == 0);
+  gdb_assert ((xo & ~0x3ff) == 0);
+
+  insn = (rst << 21) | (n << 11) | (xo << 1);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* Followings are frequently used xfx-form instructions.  */
+
+#define GEN_MFSPR(buf, rt, spr)		gen_xfx_form (buf, 31, rt, spr, 339)
+#define GEN_MTSPR(buf, rt, spr)		gen_xfx_form (buf, 31, rt, spr, 467)
+#define GEN_MFCR(buf, rt)		gen_xfx_form (buf, 31, rt, 0, 19)
+#define GEN_MTCR(buf, rt)		gen_xfx_form (buf, 31, rt, 0x3cf, 144)
+#define GEN_SYNC(buf, L, E)             gen_xfx_form (buf, 31, L & 0x3, \
+						      E & 0xf, 598)
+#define GEN_LWSYNC(buf)			GEN_SYNC (buf, 1, 0)
+
+
+/* Generate a x-form instruction in BUF and return the number of bytes written.
+
+   0      6     11   16   21       31 32
+   | OPCD | RST | RA | RB |   XO   |RC|  */
+
+static int
+gen_x_form (uint32_t *buf, int opcd, int rst, int ra, int rb, int xo, int rc)
+{
+  uint32_t insn;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((rst & ~0x1f) == 0);
+  gdb_assert ((ra & ~0x1f) == 0);
+  gdb_assert ((rb & ~0x1f) == 0);
+  gdb_assert ((xo & ~0x3ff) == 0);
+  gdb_assert ((rc & ~1) == 0);
+
+  insn = (rst << 21) | (ra << 16) | (rb << 11) | (xo << 1) | rc;
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* Followings are frequently used x-form instructions.  */
+
+#define GEN_OR(buf, ra, rs, rb)		gen_x_form (buf, 31, rs, ra, rb, 444, 0)
+#define GEN_MR(buf, ra, rs)		GEN_OR (buf, ra, rs, rs)
+#define GEN_LWARX(buf, rt, ra, rb)	gen_x_form (buf, 31, rt, ra, rb, 20, 0)
+#define GEN_STWCX(buf, rs, ra, rb)	gen_x_form (buf, 31, rs, ra, rb, 150, 1)
+/* Assume bf = cr7.  */
+#define GEN_CMPW(buf, ra, rb)		gen_x_form (buf, 31, 28, ra, rb, 0, 0)
+
+
+/* Generate a md-form instruction in BUF and return the number of bytes written.
+
+   0      6    11   16   21   27   30 31 32
+   | OPCD | RS | RA | sh | mb | XO |sh|Rc|  */
+
+static int
+gen_md_form (uint32_t *buf, int opcd, int rs, int ra, int sh, int mb,
+	     int xo, int rc)
+{
+  uint32_t insn;
+  unsigned int n = ((mb & 0x1f) << 1) | ((mb >> 5) & 0x1);
+  unsigned int sh0_4 = sh & 0x1f;
+  unsigned int sh5 = (sh >> 5) & 1;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((rs & ~0x1f) == 0);
+  gdb_assert ((ra & ~0x1f) == 0);
+  gdb_assert ((sh & ~0x3f) == 0);
+  gdb_assert ((mb & ~0x3f) == 0);
+  gdb_assert ((xo & ~0x7) == 0);
+  gdb_assert ((rc & ~0x1) == 0);
+
+  insn = (rs << 21) | (ra << 16) | (sh0_4 << 11) | (n << 5)
+	 | (sh5 << 1) | (xo << 2) | (rc & 1);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* The following are frequently used md-form instructions.  */
+
+#define GEN_RLDICL(buf, ra, rs ,sh, mb) \
+				gen_md_form (buf, 30, rs, ra, sh, mb, 0, 0)
+#define GEN_RLDICR(buf, ra, rs ,sh, mb) \
+				gen_md_form (buf, 30, rs, ra, sh, mb, 1, 0)
+
+/* Generate a i-form instruction in BUF and return the number of bytes written.
+
+   0      6                          30 31 32
+   | OPCD |            LI            |AA|LK|  */
+
+static int
+gen_i_form (uint32_t *buf, int opcd, int li, int aa, int lk)
+{
+  uint32_t insn;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+
+  insn = (li & 0x3fffffc) | (aa & 1) | (lk & 1);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* The following are frequently used i-form instructions.  */
+
+#define GEN_B(buf, li)		gen_i_form (buf, 18, li, 0, 0)
+#define GEN_BL(buf, li)		gen_i_form (buf, 18, li, 0, 1)
+
+/* Generate a b-form instruction in BUF and return the number of bytes written.
+
+   0      6    11   16               30 31 32
+   | OPCD | BO | BI |      BD        |AA|LK|  */
+
+static int
+gen_b_form (uint32_t *buf, int opcd, int bo, int bi, int bd,
+	    int aa, int lk)
+{
+  uint32_t insn;
+
+  gdb_assert ((opcd & ~0x3f) == 0);
+  gdb_assert ((bo & ~0x1f) == 0);
+  gdb_assert ((bi & ~0x1f) == 0);
+
+  insn = (bo << 21) | (bi << 16) | (bd & 0xfffc) | (aa & 1) | (lk & 1);
+  *buf = (opcd << 26) | insn;
+  return 1;
+}
+
+/* The following are frequently used b-form instructions.  */
+/* Assume bi = cr7.  */
+#define GEN_BNE(buf, bd)  gen_b_form (buf, 16, 0x4, (7 << 2) | 2, bd, 0 ,0)
+
+/* GEN_LOAD and GEN_STORE generate 64- or 32-bit load/store for ppc64 or ppc32
+   respectively.  They are primary used for save/restore GPRs in jump-pad,
+   not used for bytecode compiling.  */
+
+#ifdef __powerpc64__
+#define GEN_LOAD(buf, rt, ra, si, is_64)	(is_64 ? \
+						 GEN_LD (buf, rt, ra, si) : \
+						 GEN_LWZ (buf, rt, ra, si))
+#define GEN_STORE(buf, rt, ra, si, is_64)	(is_64 ? \
+						 GEN_STD (buf, rt, ra, si) : \
+						 GEN_STW (buf, rt, ra, si))
+#else
+#define GEN_LOAD(buf, rt, ra, si, is_64)	GEN_LWZ (buf, rt, ra, si)
+#define GEN_STORE(buf, rt, ra, si, is_64)	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, int is_64)
+{
+  uint32_t *p = buf;
+
+  if ((imm + 32768) < 65536)
+    {
+      /* li	reg, imm[15:0] */
+      p += GEN_LI (p, reg, imm);
+    }
+  else if ((imm >> 32) == 0)
+    {
+      /* lis	reg, imm[31:16]
+	 ori	reg, reg, imm[15:0]
+	 rldicl reg, reg, 0, 32 */
+      p += GEN_LIS (p, reg, (imm >> 16) & 0xffff);
+      if ((imm & 0xffff) != 0)
+	p += GEN_ORI (p, reg, reg, imm & 0xffff);
+      /* Clear upper 32-bit if sign-bit is set.  */
+      if (imm & (1u << 31) && is_64)
+	p += GEN_RLDICL (p, reg, reg, 0, 32);
+    }
+  else
+    {
+      gdb_assert (is_64);
+      /* 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));
+      if (((imm >> 32) & 0xffff) != 0)
+        p += GEN_ORI (p, reg, reg, ((imm >> 32) & 0xffff));
+      p += GEN_RLDICR (p, reg, reg, 32, 31);
+      if (((imm >> 16) & 0xffff) != 0)
+        p += GEN_ORIS (p, reg, reg, ((imm >> 16) & 0xffff));
+      if ((imm & 0xffff) != 0)
+        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,
+		 int is_64)
+{
+  const int r_lock = 6;
+  const int r_old = 7;
+  const int r_tmp = 8;
+  uint32_t *p = buf;
+
+  /*
+  1: lwarx   TMP, 0, LOCK
+     cmpwi   TMP, OLD
+     bne     1b
+     stwcx.  NEW, 0, LOCK
+     bne     1b */
+
+  p += gen_limm (p, r_lock, lock, is_64);
+  p += gen_limm (p, r_old, old_value, is_64);
+
+  p += GEN_LWARX (p, r_tmp, 0, r_lock);
+  p += GEN_CMPW (p, r_tmp, r_old);
+  p += GEN_BNE (p, -8);
+  p += GEN_STWCX (p, r_new, 0, r_lock);
+  p += GEN_BNE (p, -16);
+
+  return p - buf;
+}
+
+/* Generate a sequence of instructions for calling a function
+   at address of FN.  Return the number of bytes are written in BUF.  */
+
+static int
+gen_call (uint32_t *buf, CORE_ADDR fn, int is_64, int is_opd)
+{
+  uint32_t *p = buf;
+
+  /* Must be called by r12 for caller to calculate TOC address. */
+  p += gen_limm (p, 12, fn, is_64);
+  if (is_opd)
+    {
+      p += GEN_LOAD (p, 11, 12, 16, is_64);
+      p += GEN_LOAD (p, 2, 12, 8, is_64);
+      p += GEN_LOAD (p, 12, 12, 0, is_64);
+    }
+  p += GEN_MTSPR (p, 12, 9);		/* mtctr  r12 */
+  *p++ = 0x4e800421;			/* bctrl */
+
+  return p - buf;
+}
+
+/* Copy the instruction from OLDLOC to *TO, and update *TO to *TO + size
+   of instruction.  This function is used to adjust pc-relative instructions
+   when copying.  */
+
+static void
+ppc_relocate_instruction (CORE_ADDR *to, CORE_ADDR oldloc)
+{
+  uint32_t insn, op6;
+  long rel, newrel;
+
+  read_inferior_memory (oldloc, (unsigned char *) &insn, 4);
+  op6 = PPC_OP6 (insn);
+
+  if (op6 == 18 && (insn & 2) == 0)
+    {
+      /* branch && AA = 0 */
+      rel = PPC_LI (insn);
+      newrel = (oldloc - *to) + rel;
+
+      /* Out of range. Cannot relocate instruction.  */
+      if (newrel >= (1 << 25) || newrel < -(1 << 25))
+	return;
+
+      insn = (insn & ~0x3fffffc) | (newrel & 0x3fffffc);
+    }
+  else if (op6 == 16 && (insn & 2) == 0)
+    {
+      /* conditional branch && AA = 0 */
+
+      /* If the new relocation is too big for even a 26-bit unconditional
+	 branch, there is nothing we can do.  Just abort.
+
+	 Otherwise, if it can be fit in 16-bit conditional branch, just
+	 copy the instruction and relocate the address.
+
+	 If the it's  big for conditional-branch (16-bit), try to invert the
+	 condition and jump with 26-bit branch.  For example,
+
+	 beq  .Lgoto
+	 INSN1
+
+	 =>
+
+	 bne  1f (+8)
+	 b    .Lgoto
+       1:INSN1
+
+	 After this transform, we are actually jump from *TO+4 instead of *TO,
+	 so check the relocation again because it will be 1-insn farther then
+	 before if *TO is after OLDLOC.
+
+
+	 For BDNZT (or so) is transformed from
+
+	 bdnzt  eq, .Lgoto
+	 INSN1
+
+	 =>
+
+	 bdz    1f (+12)
+	 bf     eq, 1f (+8)
+	 b      .Lgoto
+       1:INSN1
+
+	 See also "BO field encodings".  */
+
+      rel = PPC_BD (insn);
+      newrel = (oldloc - *to) + rel;
+
+      if (newrel < (1 << 15) && newrel >= -(1 << 15))
+	insn = (insn & ~0xfffc) | (newrel & 0xfffc);
+      else if ((PPC_BO (insn) & 0x14) == 0x4 || (PPC_BO (insn) & 0x14) == 0x10)
+	{
+	  newrel -= 4;
+
+	  /* Out of range. Cannot relocate instruction.  */
+	  if (newrel >= (1 << 25) || newrel < -(1 << 25))
+	    return;
+
+	  if ((PPC_BO (insn) & 0x14) == 0x4)
+	    insn ^= (1 << 24);
+	  else if ((PPC_BO (insn) & 0x14) == 0x10)
+	    insn ^= (1 << 22);
+
+	  /* Jump over the unconditional branch.  */
+	  insn = (insn & ~0xfffc) | 0x8;
+	  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+	  *to += 4;
+
+	  /* Build a unconditional branch and copy LK bit.  */
+	  insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3);
+	  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+	  *to += 4;
+
+	  return;
+	}
+      else if ((PPC_BO (insn) & 0x14) == 0)
+	{
+	  uint32_t bdnz_insn = (16 << 26) | (0x10 << 21) | 12;
+	  uint32_t bf_insn = (16 << 26) | (0x4 << 21) | 8;
+
+	  newrel -= 8;
+
+	  /* Out of range. Cannot relocate instruction.  */
+	  if (newrel >= (1 << 25) || newrel < -(1 << 25))
+	    return;
+
+	  /* Copy BI field.  */
+	  bf_insn |= (insn & 0x1f0000);
+
+	  /* Invert condition.  */
+	  bdnz_insn |= (insn ^ (1 << 22)) & (1 << 22);
+	  bf_insn |= (insn ^ (1 << 24)) & (1 << 24);
+
+	  write_inferior_memory (*to, (unsigned char *) &bdnz_insn, 4);
+	  *to += 4;
+	  write_inferior_memory (*to, (unsigned char *) &bf_insn, 4);
+	  *to += 4;
+
+	  /* Build a unconditional branch and copy LK bit.  */
+	  insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3);
+	  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+	  *to += 4;
+
+	  return;
+	}
+      else /* (BO & 0x14) == 0x14, branch always.  */
+	{
+	  /* Out of range. Cannot relocate instruction.  */
+	  if (newrel >= (1 << 25) || newrel < -(1 << 25))
+	    return;
+
+	  /* Build a unconditional branch and copy LK bit.  */
+	  insn = (18 << 26) | (0x3fffffc & newrel) | (insn & 0x3);
+	  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+	  *to += 4;
+
+	  return;
+	}
+    }
+
+  write_inferior_memory (*to, (unsigned char *) &insn, 4);
+  *to += 4;
+}
+
+/* Implement install_fast_tracepoint_jump_pad of target_ops.
+   See target.h for details.  */
+
+static int
+ppc_install_fast_tracepoint_jump_pad (CORE_ADDR tpoint, CORE_ADDR tpaddr,
+				      CORE_ADDR collector,
+				      CORE_ADDR lockaddr,
+				      ULONGEST orig_size,
+				      CORE_ADDR *jump_entry,
+				      CORE_ADDR *trampoline,
+				      ULONGEST *trampoline_size,
+				      unsigned char *jjump_pad_insn,
+				      ULONGEST *jjump_pad_insn_size,
+				      CORE_ADDR *adjusted_insn_addr,
+				      CORE_ADDR *adjusted_insn_addr_end,
+				      char *err)
+{
+  uint32_t buf[256];
+  uint32_t *p = buf;
+  int j, offset;
+  CORE_ADDR buildaddr = *jump_entry;
+  const CORE_ADDR entryaddr = *jump_entry;
+  int rsz, min_frame, frame_size, tp_reg;
+#ifdef __powerpc64__
+  struct regcache *regcache = get_thread_regcache (current_thread, 0);
+  int is_64 = register_size (regcache->tdesc, 0) == 8;
+  int is_opd = is_64 && !is_elfv2_inferior ();
+#else
+  int is_64 = 0, is_opd = 0;
+#endif
+
+#ifdef __powerpc64__
+  if (is_64)
+    {
+      /* Minimum frame size is 32 bytes for ELFv2, and 112 bytes for ELFv1.  */
+      rsz = 8;
+      min_frame = 112;
+      frame_size = (40 * rsz) + min_frame;
+      tp_reg = 13;
+    }
+  else
+    {
+#endif
+      rsz = 4;
+      min_frame = 16;
+      frame_size = (40 * rsz) + min_frame;
+      tp_reg = 2;
+#ifdef __powerpc64__
+    }
+#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.  */
+  if (is_64)
+    p += GEN_STDU (p, 1, 1, -frame_size);		/* stdu   r1,-frame_size(r1) */
+  else
+    p += GEN_STWU (p, 1, 1, -frame_size);		/* stwu   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, is_64);
+  p += GEN_STORE (p, 0, 1, min_frame + 0 * rsz, is_64);
+  /* 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, is_64);
+
+  /* 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, is_64);/* std    r3, 32(r1) */
+  p += GEN_STORE (p, 4, 1, min_frame + 33 * rsz, is_64);/* std    r4, 33(r1) */
+  p += GEN_STORE (p, 5, 1, min_frame + 34 * rsz, is_64);/* std    r5, 34(r1) */
+  p += GEN_STORE (p, 6, 1, min_frame + 35 * rsz, is_64);/* std    r6, 35(r1) */
+
+  /* Save PC<tpaddr>  */
+  p += gen_limm (p, 3, tpaddr, is_64);
+  p += GEN_STORE (p, 3, 1, min_frame + 36 * rsz, is_64);
+
+
+  /* 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, is_64);
+
+  /* Prepare collecting_t object for lock.  */
+  p += GEN_STORE (p, 3, 1, min_frame + 37 * rsz, is_64);
+  p += GEN_STORE (p, tp_reg, 1, min_frame + 38 * rsz, is_64);
+  /* Set R5 to collecting object.  */
+  p += GEN_ADDI (p, 5, 1, 37 * rsz);
+
+  p += GEN_LWSYNC (p);
+  p += gen_atomic_xchg (p, lockaddr, 0, 5, is_64);
+  p += GEN_LWSYNC (p);
+
+  /* Call to collector.  */
+  p += gen_call (p, collector, is_64, is_opd);
+
+  /* Simply write 0 to release the lock.  */
+  p += gen_limm (p, 3, lockaddr, is_64);
+  p += gen_limm (p, 4, 0, is_64);
+  p += GEN_LWSYNC (p);
+  p += GEN_STORE (p, 4, 3, 0, is_64);
+
+  /* Restore stack and registers.  */
+  p += GEN_LOAD (p, 3, 1, min_frame + 32 * rsz, is_64);	/* ld	r3, 32(r1) */
+  p += GEN_LOAD (p, 4, 1, min_frame + 33 * rsz, is_64);	/* ld	r4, 33(r1) */
+  p += GEN_LOAD (p, 5, 1, min_frame + 34 * rsz, is_64);	/* ld	r5, 34(r1) */
+  p += GEN_LOAD (p, 6, 1, min_frame + 35 * rsz, is_64);	/* 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, is_64);
+  p += GEN_LOAD (p, 0, 1, min_frame + 0 * rsz, is_64);
+  /* 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 (void)
+{
+  return 4;
+}
+
+/* Implementation of linux_target_ops method "get_ipa_tdesc_idx".  */
+
+static int
+ppc_get_ipa_tdesc_idx (void)
+{
+  struct regcache *regcache = get_thread_regcache (current_thread, 0);
+  const struct target_desc *tdesc = regcache->tdesc;
+
+#ifdef __powerpc64__
+  if (tdesc == tdesc_powerpc_64l)
+    return PPC_TDESC_BASE;
+  if (tdesc == tdesc_powerpc_altivec64l)
+    return PPC_TDESC_ALTIVEC;
+  if (tdesc == tdesc_powerpc_cell64l)
+    return PPC_TDESC_CELL;
+  if (tdesc == tdesc_powerpc_vsx64l)
+    return PPC_TDESC_VSX;
+  if (tdesc == tdesc_powerpc_isa205_64l)
+    return PPC_TDESC_ISA205;
+  if (tdesc == tdesc_powerpc_isa205_altivec64l)
+    return PPC_TDESC_ISA205_ALTIVEC;
+  if (tdesc == tdesc_powerpc_isa205_vsx64l)
+    return PPC_TDESC_ISA205_VSX;
+#endif
+
+  if (tdesc == tdesc_powerpc_32l)
+    return PPC_TDESC_BASE;
+  if (tdesc == tdesc_powerpc_altivec32l)
+    return PPC_TDESC_ALTIVEC;
+  if (tdesc == tdesc_powerpc_cell32l)
+    return PPC_TDESC_CELL;
+  if (tdesc == tdesc_powerpc_vsx32l)
+    return PPC_TDESC_VSX;
+  if (tdesc == tdesc_powerpc_isa205_32l)
+    return PPC_TDESC_ISA205;
+  if (tdesc == tdesc_powerpc_isa205_altivec32l)
+    return PPC_TDESC_ISA205_ALTIVEC;
+  if (tdesc == tdesc_powerpc_isa205_vsx32l)
+    return PPC_TDESC_ISA205_VSX;
+  if (tdesc == tdesc_powerpc_e500l)
+    return PPC_TDESC_E500;
+
+  return 0;
+}
+
 struct linux_target_ops the_low_target = {
   ppc_arch_setup,
   ppc_regs_info,
@@ -789,13 +1529,15 @@ struct linux_target_ops the_low_target = {
   NULL, /* prepare_to_resume */
   NULL, /* process_qsupported */
   ppc_supports_tracepoints,
-  NULL, /* get_thread_area */
-  NULL, /* install_fast_tracepoint_jump_pad */
+  ppc_get_thread_area,
+  ppc_install_fast_tracepoint_jump_pad,
   NULL, /* emit_ops */
-  NULL, /* get_min_fast_tracepoint_insn_len */
+  ppc_get_min_fast_tracepoint_insn_len,
   NULL, /* supports_range_stepping */
   NULL, /* breakpoint_kind_from_current_state */
   ppc_supports_hardware_single_step,
+  NULL, /* get_syscall_trapinfo */
+  ppc_get_ipa_tdesc_idx,
 };
 
 void
@@ -811,6 +1553,7 @@ initialize_low_arch (void)
   init_registers_powerpc_isa205_altivec32l ();
   init_registers_powerpc_isa205_vsx32l ();
   init_registers_powerpc_e500l ();
+#if __powerpc64__
   init_registers_powerpc_64l ();
   init_registers_powerpc_altivec64l ();
   init_registers_powerpc_cell64l ();
@@ -818,6 +1561,7 @@ initialize_low_arch (void)
   init_registers_powerpc_isa205_64l ();
   init_registers_powerpc_isa205_altivec64l ();
   init_registers_powerpc_isa205_vsx64l ();
+#endif
 
   initialize_regsets_info (&ppc_regsets_info);
 }
diff --git a/gdb/gdbserver/linux-ppc-tdesc.h b/gdb/gdbserver/linux-ppc-tdesc.h
new file mode 100644
index 0000000..d77b127
--- /dev/null
+++ b/gdb/gdbserver/linux-ppc-tdesc.h
@@ -0,0 +1,101 @@
+/* Low level support for ppc, shared between gdbserver and IPA.
+
+   Copyright (C) 2016 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/>.  */
+
+/* Note: since IPA obviously knows what ABI it's running on (32 vs 64),
+   it's sufficient to pass only the register set here.  This, together with
+   the ABI known at IPA compile time, maps to a tdesc.  */
+
+enum ppc_linux_tdesc {
+  PPC_TDESC_BASE,
+  PPC_TDESC_ALTIVEC,
+  PPC_TDESC_CELL,
+  PPC_TDESC_VSX,
+  PPC_TDESC_ISA205,
+  PPC_TDESC_ISA205_ALTIVEC,
+  PPC_TDESC_ISA205_VSX,
+  PPC_TDESC_E500,
+};
+
+#if !defined __powerpc64__ || !defined IN_PROCESS_AGENT
+
+/* Defined in auto-generated file powerpc-32l.c.  */
+void init_registers_powerpc_32l (void);
+extern const struct target_desc *tdesc_powerpc_32l;
+
+/* Defined in auto-generated file powerpc-altivec32l.c.  */
+void init_registers_powerpc_altivec32l (void);
+extern const struct target_desc *tdesc_powerpc_altivec32l;
+
+/* Defined in auto-generated file powerpc-cell32l.c.  */
+void init_registers_powerpc_cell32l (void);
+extern const struct target_desc *tdesc_powerpc_cell32l;
+
+/* Defined in auto-generated file powerpc-vsx32l.c.  */
+void init_registers_powerpc_vsx32l (void);
+extern const struct target_desc *tdesc_powerpc_vsx32l;
+
+/* Defined in auto-generated file powerpc-isa205-32l.c.  */
+void init_registers_powerpc_isa205_32l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_32l;
+
+/* Defined in auto-generated file powerpc-isa205-altivec32l.c.  */
+void init_registers_powerpc_isa205_altivec32l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_altivec32l;
+
+/* Defined in auto-generated file powerpc-isa205-vsx32l.c.  */
+void init_registers_powerpc_isa205_vsx32l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_vsx32l;
+
+/* Defined in auto-generated file powerpc-e500l.c.  */
+void init_registers_powerpc_e500l (void);
+extern const struct target_desc *tdesc_powerpc_e500l;
+
+#endif
+
+#if defined __powerpc64__
+
+/* Defined in auto-generated file powerpc-64l.c.  */
+void init_registers_powerpc_64l (void);
+extern const struct target_desc *tdesc_powerpc_64l;
+
+/* Defined in auto-generated file powerpc-altivec64l.c.  */
+void init_registers_powerpc_altivec64l (void);
+extern const struct target_desc *tdesc_powerpc_altivec64l;
+
+/* Defined in auto-generated file powerpc-cell64l.c.  */
+void init_registers_powerpc_cell64l (void);
+extern const struct target_desc *tdesc_powerpc_cell64l;
+
+/* Defined in auto-generated file powerpc-vsx64l.c.  */
+void init_registers_powerpc_vsx64l (void);
+extern const struct target_desc *tdesc_powerpc_vsx64l;
+
+/* Defined in auto-generated file powerpc-isa205-64l.c.  */
+void init_registers_powerpc_isa205_64l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_64l;
+
+/* Defined in auto-generated file powerpc-isa205-altivec64l.c.  */
+void init_registers_powerpc_isa205_altivec64l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_altivec64l;
+
+/* Defined in auto-generated file powerpc-isa205-vsx64l.c.  */
+void init_registers_powerpc_isa205_vsx64l (void);
+extern const struct target_desc *tdesc_powerpc_isa205_vsx64l;
+
+#endif
-- 
2.7.3

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

* [PATCH v2 4/4] gdbserver: Add emit_ops for powerpc.
  2016-03-16 17:16   ` Ulrich Weigand
@ 2016-03-18 15:10     ` Marcin Kościelnicki
  2016-03-29 18:25       ` Ulrich Weigand
  0 siblings, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-18 15:10 UTC (permalink / raw)
  To: uweigand; +Cc: gdb-patches, Marcin Kościelnicki

gdb/gdbserver/ChangeLog:

2016-03-14  Wei-cheng Wang  <cole945@gmail.com>
	    Marcin Kościelnicki  <koriakin@0x04.net>

	* linux-ppc-low.c (emit_insns): New function.
	(__EMIT_ASM, _EMIT_ASM, EMIT_ASM): New macros.
	(ppc_emit_prologue): New function.
	(ppc_emit_epilogue): New function.
	(ppc_emit_add): New function.
	(ppc_emit_sub): New function.
	(ppc_emit_mul): New function.
	(ppc_emit_lsh): New function.
	(ppc_emit_rsh_signed): New function.
	(ppc_emit_rsh_unsigned): New function.
	(ppc_emit_ext): New function.
	(ppc_emit_zero_ext): New function.
	(ppc_emit_log_not): New function.
	(ppc_emit_bit_and): New function.
	(ppc_emit_bit_or): New function.
	(ppc_emit_bit_xor): New function.
	(ppc_emit_bit_not): New function.
	(ppc_emit_equal): New function.
	(ppc_emit_less_signed): New function.
	(ppc_emit_less_unsigned): New function.
	(ppc_emit_ref): New function.
	(ppc_emit_const): New function.
	(ppc_emit_reg): New function.
	(ppc_emit_pop): New function.
	(ppc_emit_stack_flush): New function.
	(ppc_emit_swap): New function.
	(ppc_emit_stack_adjust): New function.
	(ppc_emit_call): New function.
	(ppc_emit_int_call_1): New function.
	(ppc_emit_void_call_2): New function.
	(ppc_emit_if_goto): New function.
	(ppc_emit_goto): New function.
	(ppc_emit_eq_goto): New function.
	(ppc_emit_ne_goto): New function.
	(ppc_emit_lt_goto): New function.
	(ppc_emit_le_goto): New function.
	(ppc_emit_gt_goto): New function.
	(ppc_emit_ge_goto): New function.
	(ppc_write_goto_address): New function.
	(ppc_emit_ops_impl): New static variable.
	(ppc64v1_emit_prologue): New function.
	(ppc64v2_emit_prologue): New function.
	(ppc64_emit_epilogue): New function.
	(ppc64_emit_add): New function.
	(ppc64_emit_sub): New function.
	(ppc64_emit_mul): New function.
	(ppc64_emit_lsh): New function.
	(ppc64_emit_rsh_signed): New function.
	(ppc64_emit_rsh_unsigned): New function.
	(ppc64_emit_ext): New function.
	(ppc64_emit_zero_ext): New function.
	(ppc64_emit_log_not): New function.
	(ppc64_emit_bit_and): New function.
	(ppc64_emit_bit_or): New function.
	(ppc64_emit_bit_xor): New function.
	(ppc64_emit_bit_not): New function.
	(ppc64_emit_equal): New function.
	(ppc64_emit_less_signed): New function.
	(ppc64_emit_less_unsigned): New function.
	(ppc64_emit_ref): New function.
	(ppc64_emit_const): New function.
	(ppc64v1_emit_reg): New function.
	(ppc64v2_emit_reg): New function.
	(ppc64_emit_pop): New function.
	(ppc64_emit_stack_flush): New function.
	(ppc64_emit_swap): New function.
	(ppc64v1_emit_call): New function.
	(ppc64v2_emit_call): New function.
	(ppc64v1_emit_int_call_1): New function.
	(ppc64v2_emit_int_call_1): New function.
	(ppc64v1_emit_void_call_2): New function.
	(ppc64v2_emit_void_call_2): New function.
	(ppc64_emit_if_goto): New function.
	(ppc64_emit_eq_goto): New function.
	(ppc64_emit_ne_goto): New function.
	(ppc64_emit_lt_goto): New function.
	(ppc64_emit_le_goto): New function.
	(ppc64_emit_gt_goto): New function.
	(ppc64_emit_ge_goto): New function.
	(ppc64v1_emit_ops_impl): New static variable.
	(ppc64v2_emit_ops_impl): New static variable.
	(ppc_emit_ops): New function.
	(linux_low_target): Wire in ppc_emit_ops.
---
The only change in this version is that is_elfv2_inferior is used instead of
assuming same ABI as gdbserver.

 gdb/gdbserver/ChangeLog       |   87 +++
 gdb/gdbserver/linux-ppc-low.c | 1596 ++++++++++++++++++++++++++++++++++++++++-
 2 files changed, 1682 insertions(+), 1 deletion(-)

diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 60b5f21..9c59eab 100644
--- a/gdb/gdbserver/ChangeLog
+++ b/gdb/gdbserver/ChangeLog
@@ -1,3 +1,90 @@
+2016-03-14  Wei-cheng Wang  <cole945@gmail.com>
+	    Marcin Kościelnicki  <koriakin@0x04.net>
+
+	* linux-ppc-low.c (emit_insns): New function.
+	(__EMIT_ASM, _EMIT_ASM, EMIT_ASM): New macros.
+	(ppc_emit_prologue): New function.
+	(ppc_emit_epilogue): New function.
+	(ppc_emit_add): New function.
+	(ppc_emit_sub): New function.
+	(ppc_emit_mul): New function.
+	(ppc_emit_lsh): New function.
+	(ppc_emit_rsh_signed): New function.
+	(ppc_emit_rsh_unsigned): New function.
+	(ppc_emit_ext): New function.
+	(ppc_emit_zero_ext): New function.
+	(ppc_emit_log_not): New function.
+	(ppc_emit_bit_and): New function.
+	(ppc_emit_bit_or): New function.
+	(ppc_emit_bit_xor): New function.
+	(ppc_emit_bit_not): New function.
+	(ppc_emit_equal): New function.
+	(ppc_emit_less_signed): New function.
+	(ppc_emit_less_unsigned): New function.
+	(ppc_emit_ref): New function.
+	(ppc_emit_const): New function.
+	(ppc_emit_reg): New function.
+	(ppc_emit_pop): New function.
+	(ppc_emit_stack_flush): New function.
+	(ppc_emit_swap): New function.
+	(ppc_emit_stack_adjust): New function.
+	(ppc_emit_call): New function.
+	(ppc_emit_int_call_1): New function.
+	(ppc_emit_void_call_2): New function.
+	(ppc_emit_if_goto): New function.
+	(ppc_emit_goto): New function.
+	(ppc_emit_eq_goto): New function.
+	(ppc_emit_ne_goto): New function.
+	(ppc_emit_lt_goto): New function.
+	(ppc_emit_le_goto): New function.
+	(ppc_emit_gt_goto): New function.
+	(ppc_emit_ge_goto): New function.
+	(ppc_write_goto_address): New function.
+	(ppc_emit_ops_impl): New static variable.
+	(ppc64v1_emit_prologue): New function.
+	(ppc64v2_emit_prologue): New function.
+	(ppc64_emit_epilogue): New function.
+	(ppc64_emit_add): New function.
+	(ppc64_emit_sub): New function.
+	(ppc64_emit_mul): New function.
+	(ppc64_emit_lsh): New function.
+	(ppc64_emit_rsh_signed): New function.
+	(ppc64_emit_rsh_unsigned): New function.
+	(ppc64_emit_ext): New function.
+	(ppc64_emit_zero_ext): New function.
+	(ppc64_emit_log_not): New function.
+	(ppc64_emit_bit_and): New function.
+	(ppc64_emit_bit_or): New function.
+	(ppc64_emit_bit_xor): New function.
+	(ppc64_emit_bit_not): New function.
+	(ppc64_emit_equal): New function.
+	(ppc64_emit_less_signed): New function.
+	(ppc64_emit_less_unsigned): New function.
+	(ppc64_emit_ref): New function.
+	(ppc64_emit_const): New function.
+	(ppc64v1_emit_reg): New function.
+	(ppc64v2_emit_reg): New function.
+	(ppc64_emit_pop): New function.
+	(ppc64_emit_stack_flush): New function.
+	(ppc64_emit_swap): New function.
+	(ppc64v1_emit_call): New function.
+	(ppc64v2_emit_call): New function.
+	(ppc64v1_emit_int_call_1): New function.
+	(ppc64v2_emit_int_call_1): New function.
+	(ppc64v1_emit_void_call_2): New function.
+	(ppc64v2_emit_void_call_2): New function.
+	(ppc64_emit_if_goto): New function.
+	(ppc64_emit_eq_goto): New function.
+	(ppc64_emit_ne_goto): New function.
+	(ppc64_emit_lt_goto): New function.
+	(ppc64_emit_le_goto): New function.
+	(ppc64_emit_gt_goto): New function.
+	(ppc64_emit_ge_goto): New function.
+	(ppc64v1_emit_ops_impl): New static variable.
+	(ppc64v2_emit_ops_impl): New static variable.
+	(ppc_emit_ops): New function.
+	(linux_low_target): Wire in ppc_emit_ops.
+
 2016-03-13  Wei-cheng Wang  <cole945@gmail.com>
 	    Marcin Kościelnicki  <koriakin@0x04.net>
 
diff --git a/gdb/gdbserver/linux-ppc-low.c b/gdb/gdbserver/linux-ppc-low.c
index be64401..c1b0c46 100644
--- a/gdb/gdbserver/linux-ppc-low.c
+++ b/gdb/gdbserver/linux-ppc-low.c
@@ -1457,6 +1457,1600 @@ ppc_get_min_fast_tracepoint_insn_len (void)
   return 4;
 }
 
+/* Emits a given buffer into the target at current_insn_ptr.  Length
+   is in units of 32-bit words.  */
+
+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 - 32-bit
+
+	|  LR save area           (SP + 4)
+ 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 and 16-byte alignment.
+        |  16 bytes.
+ SP     +- Back-chain (SP')
+
+  initial frame size
+  = 16 + (4 * 4) + 64
+  = 96
+
+   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 the high part of TOP value.
+       It was the first argument, pointer to regs.
+   r4  is used for cache of the low part of TOP value.
+       It was the second argument, pointer to the result.
+       We should set *result = TOP after leaving this function.
+
+ Note:
+ * To restore stack at epilogue
+   => sp = r31
+ * To check stack is big enough for bytecode execution.
+   => r30 - 8 > SP + 8
+ * To return execution result.
+   => 0(r4) = TOP
+
+ */
+
+/* Regardless of endian, register 3 is always high part, 4 is low part.
+   These defines are used when the register pair is stored/loaded.
+   Likewise, to simplify code, have a similiar define for 5:6. */
+
+#if __BYTE_ORDER == __LITTLE_ENDIAN
+#define TOP_FIRST	"4"
+#define TOP_SECOND	"3"
+#define TMP_FIRST	"6"
+#define TMP_SECOND	"5"
+#else
+#define TOP_FIRST	"3"
+#define TOP_SECOND	"4"
+#define TMP_FIRST	"5"
+#define TMP_SECOND	"6"
+#endif
+
+/* Emit prologue in inferior memory.  See above comments.  */
+
+static void
+ppc_emit_prologue (void)
+{
+  EMIT_ASM (/* Save return address.  */
+	    "mflr  0		\n"
+	    "stw   0, 4(1)	\n"
+	    /* Adjust SP.  96 is the initial frame size.  */
+	    "stwu  1, -96(1)	\n"
+	    /* Save r30 and incoming arguments.  */
+	    "stw   31, 96-4(1)	\n"
+	    "stw   30, 96-8(1)	\n"
+	    "stw   4, 96-12(1)	\n"
+	    "stw   3, 96-16(1)	\n"
+	    /* Point r31 to original r1 for access arguments.  */
+	    "addi  31, 1, 96	\n"
+	    /* Set r30 to pointing stack-top.  */
+	    "addi  30, 1, 64	\n"
+	    /* Initial r3/TOP to 0.  */
+	    "li    3, 0		\n"
+	    "li    4, 0		\n");
+}
+
+/* Emit epilogue in inferior memory.  See above comments.  */
+
+static void
+ppc_emit_epilogue (void)
+{
+  EMIT_ASM (/* *result = TOP */
+	    "lwz   5, -12(31)	\n"
+	    "stw   " TOP_FIRST ", 0(5)	\n"
+	    "stw   " TOP_SECOND ", 4(5)	\n"
+	    /* Restore registers.  */
+	    "lwz   31, -4(31)	\n"
+	    "lwz   30, -8(31)	\n"
+	    /* Restore SP.  */
+	    "lwz   1, 0(1)      \n"
+	    /* Restore LR.  */
+	    "lwz   0, 4(1)	\n"
+	    /* Return 0 for no-error.  */
+	    "li    3, 0		\n"
+	    "mtlr  0		\n"
+	    "blr		\n");
+}
+
+/* TOP = stack[--sp] + TOP  */
+
+static void
+ppc_emit_add (void)
+{
+  EMIT_ASM ("lwzu  " TMP_FIRST ", 8(30)	\n"
+	    "lwz   " TMP_SECOND ", 4(30)\n"
+	    "addc  4, 6, 4	\n"
+	    "adde  3, 5, 3	\n");
+}
+
+/* TOP = stack[--sp] - TOP  */
+
+static void
+ppc_emit_sub (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "subfc  4, 4, 6	\n"
+	    "subfe  3, 3, 5	\n");
+}
+
+/* TOP = stack[--sp] * TOP  */
+
+static void
+ppc_emit_mul (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "mulhwu 7, 6, 4	\n"
+	    "mullw  3, 6, 3	\n"
+	    "mullw  5, 4, 5	\n"
+	    "mullw  4, 6, 4	\n"
+	    "add    3, 5, 3	\n"
+	    "add    3, 7, 3	\n");
+}
+
+/* TOP = stack[--sp] << TOP  */
+
+static void
+ppc_emit_lsh (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "subfic 3, 4, 32\n"		/* r3 = 32 - TOP */
+	    "addi   7, 4, -32\n"	/* r7 = TOP - 32 */
+	    "slw    5, 5, 4\n"		/* Shift high part left */
+	    "slw    4, 6, 4\n"		/* Shift low part left */
+	    "srw    3, 6, 3\n"		/* Shift low to high if shift < 32 */
+	    "slw    7, 6, 7\n"		/* Shift low to high if shift >= 32 */
+	    "or     3, 5, 3\n"
+	    "or     3, 7, 3\n");	/* Assemble high part */
+}
+
+/* Top = stack[--sp] >> TOP
+   (Arithmetic shift right)  */
+
+static void
+ppc_emit_rsh_signed (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "addi   7, 4, -32\n"	/* r7 = TOP - 32 */
+	    "sraw   3, 5, 4\n"		/* Shift high part right */
+	    "cmpwi  7, 1\n"
+	    "blt    0, 1f\n"		/* If shift <= 32, goto 1: */
+	    "sraw   4, 5, 7\n"		/* Shift high to low */
+	    "b      2f\n"
+	    "1:\n"
+	    "subfic 7, 4, 32\n"		/* r7 = 32 - TOP */
+	    "srw    4, 6, 4\n"		/* Shift low part right */
+	    "slw    5, 5, 7\n"		/* Shift high to low */
+	    "or     4, 4, 5\n"		/* Assemble low part */
+	    "2:\n");
+}
+
+/* Top = stack[--sp] >> TOP
+   (Logical shift right)  */
+
+static void
+ppc_emit_rsh_unsigned (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "subfic 3, 4, 32\n"		/* r3 = 32 - TOP */
+	    "addi   7, 4, -32\n"	/* r7 = TOP - 32 */
+	    "srw    6, 6, 4\n"		/* Shift low part right */
+	    "slw    3, 5, 3\n"		/* Shift high to low if shift < 32 */
+	    "srw    7, 5, 7\n"		/* Shift high to low if shift >= 32 */
+	    "or     6, 6, 3\n"
+	    "srw    3, 5, 4\n"		/* Shift high part right */
+	    "or     4, 6, 7\n");	/* Assemble low part */
+}
+
+/* Emit code for signed-extension specified by ARG.  */
+
+static void
+ppc_emit_ext (int arg)
+{
+  switch (arg)
+    {
+    case 8:
+      EMIT_ASM ("extsb  4, 4\n"
+		"srawi 3, 4, 31");
+      break;
+    case 16:
+      EMIT_ASM ("extsh  4, 4\n"
+		"srawi 3, 4, 31");
+      break;
+    case 32:
+      EMIT_ASM ("srawi 3, 4, 31");
+      break;
+    default:
+      emit_error = 1;
+    }
+}
+
+/* Emit code for zero-extension specified by ARG.  */
+
+static void
+ppc_emit_zero_ext (int arg)
+{
+  switch (arg)
+    {
+    case 8:
+      EMIT_ASM ("clrlwi 4,4,24\n"
+		"li 3, 0\n");
+      break;
+    case 16:
+      EMIT_ASM ("clrlwi 4,4,16\n"
+		"li 3, 0\n");
+      break;
+    case 32:
+      EMIT_ASM ("li 3, 0");
+      break;
+    default:
+      emit_error = 1;
+    }
+}
+
+/* TOP = !TOP
+   i.e., TOP = (TOP == 0) ? 1 : 0;  */
+
+static void
+ppc_emit_log_not (void)
+{
+  EMIT_ASM ("or      4, 3, 4	\n"
+	    "cntlzw  4, 4	\n"
+	    "srwi    4, 4, 5	\n"
+	    "li      3, 0	\n");
+}
+
+/* TOP = stack[--sp] & TOP  */
+
+static void
+ppc_emit_bit_and (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "and  4, 6, 4	\n"
+	    "and  3, 5, 3	\n");
+}
+
+/* TOP = stack[--sp] | TOP  */
+
+static void
+ppc_emit_bit_or (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "or  4, 6, 4	\n"
+	    "or  3, 5, 3	\n");
+}
+
+/* TOP = stack[--sp] ^ TOP  */
+
+static void
+ppc_emit_bit_xor (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "xor  4, 6, 4	\n"
+	    "xor  3, 5, 3	\n");
+}
+
+/* TOP = ~TOP
+   i.e., TOP = ~(TOP | TOP)  */
+
+static void
+ppc_emit_bit_not (void)
+{
+  EMIT_ASM ("nor  3, 3, 3	\n"
+	    "nor  4, 4, 4	\n");
+}
+
+/* TOP = stack[--sp] == TOP  */
+
+static void
+ppc_emit_equal (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "xor     4, 6, 4	\n"
+	    "xor     3, 5, 3	\n"
+	    "or      4, 3, 4	\n"
+	    "cntlzw  4, 4	\n"
+	    "srwi    4, 4, 5	\n"
+	    "li      3, 0	\n");
+}
+
+/* TOP = stack[--sp] < TOP
+   (Signed comparison)  */
+
+static void
+ppc_emit_less_signed (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "cmplw   6, 6, 4		\n"
+	    "cmpw    7, 5, 3		\n"
+	    /* CR6 bit 0 = low less and high equal */
+	    "crand   6*4+0, 6*4+0, 7*4+2\n"
+	    /* CR7 bit 0 = (low less and high equal) or high less */
+	    "cror    7*4+0, 7*4+0, 6*4+0\n"
+	    "mfcr    4			\n"
+	    "rlwinm  4, 4, 29, 31, 31	\n"
+	    "li      3, 0		\n");
+}
+
+/* TOP = stack[--sp] < TOP
+   (Unsigned comparison)  */
+
+static void
+ppc_emit_less_unsigned (void)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "cmplw   6, 6, 4		\n"
+	    "cmplw   7, 5, 3		\n"
+	    /* CR6 bit 0 = low less and high equal */
+	    "crand   6*4+0, 6*4+0, 7*4+2\n"
+	    /* CR7 bit 0 = (low less and high equal) or high less */
+	    "cror    7*4+0, 7*4+0, 6*4+0\n"
+	    "mfcr    4			\n"
+	    "rlwinm  4, 4, 29, 31, 31	\n"
+	    "li      3, 0		\n");
+}
+
+/* Access the memory address in TOP in size of SIZE.
+   Zero-extend the read value.  */
+
+static void
+ppc_emit_ref (int size)
+{
+  switch (size)
+    {
+    case 1:
+      EMIT_ASM ("lbz   4, 0(4)\n"
+		"li    3, 0");
+      break;
+    case 2:
+      EMIT_ASM ("lhz   4, 0(4)\n"
+		"li    3, 0");
+      break;
+    case 4:
+      EMIT_ASM ("lwz   4, 0(4)\n"
+		"li    3, 0");
+      break;
+    case 8:
+      if (__BYTE_ORDER == __LITTLE_ENDIAN)
+	EMIT_ASM ("lwz   3, 4(4)\n"
+		  "lwz   4, 0(4)");
+      else
+	EMIT_ASM ("lwz   3, 0(4)\n"
+		  "lwz   4, 4(4)");
+      break;
+    }
+}
+
+/* TOP = NUM  */
+
+static void
+ppc_emit_const (LONGEST num)
+{
+  uint32_t buf[10];
+  uint32_t *p = buf;
+
+  p += gen_limm (p, 3, num >> 32 & 0xffffffff, 0);
+  p += gen_limm (p, 4, num & 0xffffffff, 0);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (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
+ppc_emit_reg (int reg)
+{
+  uint32_t buf[13];
+  uint32_t *p = buf;
+
+  /* fctx->regs is passed in r3 and then saved in -16(31).  */
+  p += GEN_LWZ (p, 3, 31, -16);
+  p += GEN_LI (p, 4, reg);	/* li	r4, reg */
+  p += gen_call (p, get_raw_reg_func_addr (), 0, 0);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+
+  if (__BYTE_ORDER == __LITTLE_ENDIAN)
+    {
+      EMIT_ASM ("mr 5, 4\n"
+		"mr 4, 3\n"
+		"mr 3, 5\n");
+    }
+}
+
+/* TOP = stack[--sp] */
+
+static void
+ppc_emit_pop (void)
+{
+  EMIT_ASM ("lwzu " TOP_FIRST ", 8(30)	\n"
+	    "lwz " TOP_SECOND ", 4(30)	\n");
+}
+
+/* stack[sp++] = TOP
+
+   Because we may use up bytecode stack, expand 8 doublewords more
+   if needed.  */
+
+static void
+ppc_emit_stack_flush (void)
+{
+  /* Make sure bytecode stack is big enough before push.
+     Otherwise, expand 64-byte more.  */
+
+  EMIT_ASM ("  stw   " TOP_FIRST ", 0(30)	\n"
+	    "  stw   " TOP_SECOND ", 4(30)\n"
+	    "  addi  5, 30, -(8 + 8)	\n"
+	    "  cmpw  7, 5, 1		\n"
+	    "  bgt   7, 1f		\n"
+	    "  stwu  31, -64(1)		\n"
+	    "1:addi  30, 30, -8		\n");
+}
+
+/* Swap TOP and stack[sp-1]  */
+
+static void
+ppc_emit_swap (void)
+{
+  EMIT_ASM ("lwz  " TMP_FIRST ", 8(30)	\n"
+	    "lwz  " TMP_SECOND ", 12(30)	\n"
+	    "stw  " TOP_FIRST ", 8(30)	\n"
+	    "stw  " TOP_SECOND ", 12(30)	\n"
+	    "mr   3, 5		\n"
+	    "mr   4, 6		\n");
+}
+
+/* Discard N elements in the stack.  Also used for ppc64.  */
+
+static void
+ppc_emit_stack_adjust (int n)
+{
+  uint32_t buf[6];
+  uint32_t *p = buf;
+
+  n = n << 3;
+  if ((n >> 15) != 0)
+    {
+      emit_error = 1;
+      return;
+    }
+
+  p += GEN_ADDI (p, 30, 30, n);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+}
+
+/* Call function FN.  */
+
+static void
+ppc_emit_call (CORE_ADDR fn)
+{
+  uint32_t buf[11];
+  uint32_t *p = buf;
+
+  p += gen_call (p, fn, 0, 0);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+}
+
+/* FN's prototype is `LONGEST(*fn)(int)'.
+   TOP = fn (arg1)
+  */
+
+static void
+ppc_emit_int_call_1 (CORE_ADDR fn, int arg1)
+{
+  uint32_t buf[15];
+  uint32_t *p = buf;
+
+  /* Setup argument.  arg1 is a 16-bit value.  */
+  p += gen_limm (p, 3, (uint32_t) arg1, 0);
+  p += gen_call (p, fn, 0, 0);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+
+  if (__BYTE_ORDER == __LITTLE_ENDIAN)
+    {
+      EMIT_ASM ("mr 5, 4\n"
+		"mr 4, 3\n"
+		"mr 3, 5\n");
+    }
+}
+
+/* FN's prototype is `void(*fn)(int,LONGEST)'.
+   fn (arg1, TOP)
+
+   TOP should be preserved/restored before/after the call.  */
+
+static void
+ppc_emit_void_call_2 (CORE_ADDR fn, int arg1)
+{
+  uint32_t buf[21];
+  uint32_t *p = buf;
+
+  /* Save TOP.  0(30) is next-empty.  */
+  p += GEN_STW (p, 3, 30, 0);
+  p += GEN_STW (p, 4, 30, 4);
+
+  /* Setup argument.  arg1 is a 16-bit value.  */
+  if (__BYTE_ORDER == __LITTLE_ENDIAN)
+    {
+       p += GEN_MR (p, 5, 4);
+       p += GEN_MR (p, 6, 3);
+    }
+  else
+    {
+       p += GEN_MR (p, 5, 3);
+       p += GEN_MR (p, 6, 4);
+    }
+  p += gen_limm (p, 3, (uint32_t) arg1, 0);
+  p += gen_call (p, fn, 0, 0);
+
+  /* Restore TOP */
+  p += GEN_LWZ (p, 3, 30, 0);
+  p += GEN_LWZ (p, 4, 30, 4);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (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
+ppc_emit_if_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("or.    3, 3, 4	\n"
+	    "lwzu " TOP_FIRST ", 8(30)	\n"
+	    "lwz " TOP_SECOND ", 4(30)	\n"
+	    "1:bne  0, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 12;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Unconditional goto.  Also used for ppc64.  */
+
+static void
+ppc_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
+ppc_emit_eq_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("lwzu  " TMP_FIRST ", 8(30)	\n"
+	    "lwz   " TMP_SECOND ", 4(30)	\n"
+	    "xor   4, 6, 4	\n"
+	    "xor   3, 5, 3	\n"
+	    "or.   3, 3, 4	\n"
+	    "lwzu  " TOP_FIRST ", 8(30)	\n"
+	    "lwz   " TOP_SECOND ", 4(30)	\n"
+	    "1:beq 0, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 28;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Goto if stack[--sp] != TOP  */
+
+static void
+ppc_emit_ne_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("lwzu  " TMP_FIRST ", 8(30)	\n"
+	    "lwz   " TMP_SECOND ", 4(30)	\n"
+	    "xor   4, 6, 4	\n"
+	    "xor   3, 5, 3	\n"
+	    "or.   3, 3, 4	\n"
+	    "lwzu  " TOP_FIRST ", 8(30)	\n"
+	    "lwz   " TOP_SECOND ", 4(30)	\n"
+	    "1:bne 0, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 28;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Goto if stack[--sp] < TOP  */
+
+static void
+ppc_emit_lt_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "cmplw   6, 6, 4		\n"
+	    "cmpw    7, 5, 3		\n"
+	    /* CR6 bit 0 = low less and high equal */
+	    "crand   6*4+0, 6*4+0, 7*4+2\n"
+	    /* CR7 bit 0 = (low less and high equal) or high less */
+	    "cror    7*4+0, 7*4+0, 6*4+0\n"
+	    "lwzu    " TOP_FIRST ", 8(30)	\n"
+	    "lwz     " TOP_SECOND ", 4(30)\n"
+	    "1:blt   7, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 32;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Goto if stack[--sp] <= TOP  */
+
+static void
+ppc_emit_le_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "cmplw   6, 6, 4		\n"
+	    "cmpw    7, 5, 3		\n"
+	    /* CR6 bit 0 = low less/equal and high equal */
+	    "crandc   6*4+0, 7*4+2, 6*4+1\n"
+	    /* CR7 bit 0 = (low less/eq and high equal) or high less */
+	    "cror    7*4+0, 7*4+0, 6*4+0\n"
+	    "lwzu    " TOP_FIRST ", 8(30)	\n"
+	    "lwz     " TOP_SECOND ", 4(30)\n"
+	    "1:blt   7, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 32;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Goto if stack[--sp] > TOP  */
+
+static void
+ppc_emit_gt_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "cmplw   6, 6, 4		\n"
+	    "cmpw    7, 5, 3		\n"
+	    /* CR6 bit 0 = low greater and high equal */
+	    "crand   6*4+0, 6*4+1, 7*4+2\n"
+	    /* CR7 bit 0 = (low greater and high equal) or high greater */
+	    "cror    7*4+0, 7*4+1, 6*4+0\n"
+	    "lwzu    " TOP_FIRST ", 8(30)	\n"
+	    "lwz     " TOP_SECOND ", 4(30)\n"
+	    "1:blt   7, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 32;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* Goto if stack[--sp] >= TOP  */
+
+static void
+ppc_emit_ge_goto (int *offset_p, int *size_p)
+{
+  EMIT_ASM ("lwzu " TMP_FIRST ", 8(30)	\n"
+	    "lwz " TMP_SECOND ", 4(30)	\n"
+	    "cmplw   6, 6, 4		\n"
+	    "cmpw    7, 5, 3		\n"
+	    /* CR6 bit 0 = low ge and high equal */
+	    "crandc  6*4+0, 7*4+2, 6*4+0\n"
+	    /* CR7 bit 0 = (low ge and high equal) or high greater */
+	    "cror    7*4+0, 7*4+1, 6*4+0\n"
+	    "lwzu    " TOP_FIRST ", 8(30)\n"
+	    "lwz     " TOP_SECOND ", 4(30)\n"
+	    "1:blt   7, 1b	\n");
+
+  if (offset_p)
+    *offset_p = 32;
+  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.
+   Also used for ppc64.  */
+
+static void
+ppc_write_goto_address (CORE_ADDR from, CORE_ADDR to, int size)
+{
+  long 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);
+}
+
+/* Table of emit ops for 32-bit.  */
+
+static struct emit_ops ppc_emit_ops_impl =
+{
+  ppc_emit_prologue,
+  ppc_emit_epilogue,
+  ppc_emit_add,
+  ppc_emit_sub,
+  ppc_emit_mul,
+  ppc_emit_lsh,
+  ppc_emit_rsh_signed,
+  ppc_emit_rsh_unsigned,
+  ppc_emit_ext,
+  ppc_emit_log_not,
+  ppc_emit_bit_and,
+  ppc_emit_bit_or,
+  ppc_emit_bit_xor,
+  ppc_emit_bit_not,
+  ppc_emit_equal,
+  ppc_emit_less_signed,
+  ppc_emit_less_unsigned,
+  ppc_emit_ref,
+  ppc_emit_if_goto,
+  ppc_emit_goto,
+  ppc_write_goto_address,
+  ppc_emit_const,
+  ppc_emit_call,
+  ppc_emit_reg,
+  ppc_emit_pop,
+  ppc_emit_stack_flush,
+  ppc_emit_zero_ext,
+  ppc_emit_swap,
+  ppc_emit_stack_adjust,
+  ppc_emit_int_call_1,
+  ppc_emit_void_call_2,
+  ppc_emit_eq_goto,
+  ppc_emit_ne_goto,
+  ppc_emit_lt_goto,
+  ppc_emit_le_goto,
+  ppc_emit_gt_goto,
+  ppc_emit_ge_goto
+};
+
+#ifdef __powerpc64__
+
+/*
+
+  Bytecode execution stack frame - 64-bit
+
+	|  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
+ * 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
+ppc64v1_emit_prologue (void)
+{
+  /* On ELFv1, function pointers really point to function descriptor,
+     so emit one here.  We don't care about contents of words 1 and 2,
+     so let them just overlap out code.  */
+  uint64_t opd = current_insn_ptr + 8;
+  uint32_t buf[2];
+
+  /* Mind the strict aliasing rules.  */
+  memcpy (buf, &opd, sizeof buf);
+  emit_insns(buf, 2);
+  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 prologue in inferior memory.  See above comments.  */
+
+static void
+ppc64v2_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"
+	    "mfcr    3			\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"
+	    "mfcr    3			\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, 1);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (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
+ppc64v1_emit_reg (int reg)
+{
+  uint32_t buf[15];
+  uint32_t *p = buf;
+
+  /* fctx->regs is passed in r3 and then saved in 176(1).  */
+  p += GEN_LD (p, 3, 31, -32);
+  p += GEN_LI (p, 4, reg);
+  p += GEN_STD (p, 2, 1, 40);	/* Save TOC.  */
+  p += gen_call (p, get_raw_reg_func_addr (), 1, 1);
+  p += GEN_LD (p, 2, 1, 40);	/* Restore TOC.  */
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+}
+
+/* Likewise, for ELFv2.  */
+
+static void
+ppc64v2_emit_reg (int reg)
+{
+  uint32_t buf[12];
+  uint32_t *p = buf;
+
+  /* fctx->regs is passed in r3 and then saved in 176(1).  */
+  p += GEN_LD (p, 3, 31, -32);
+  p += GEN_LI (p, 4, reg);
+  p += GEN_STD (p, 2, 1, 24);	/* Save TOC.  */
+  p += gen_call (p, get_raw_reg_func_addr (), 1, 0);
+  p += GEN_LD (p, 2, 1, 24);	/* Restore TOC.  */
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (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"
+	    "  stdu  31, -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");
+}
+
+/* Call function FN - ELFv1.  */
+
+static void
+ppc64v1_emit_call (CORE_ADDR fn)
+{
+  uint32_t buf[13];
+  uint32_t *p = buf;
+
+  p += GEN_STD (p, 2, 1, 40);	/* Save TOC.  */
+  p += gen_call (p, fn, 1, 1);
+  p += GEN_LD (p, 2, 1, 40);	/* Restore TOC.  */
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+}
+
+/* Call function FN - ELFv2.  */
+
+static void
+ppc64v2_emit_call (CORE_ADDR fn)
+{
+  uint32_t buf[10];
+  uint32_t *p = buf;
+
+  p += GEN_STD (p, 2, 1, 24);	/* Save TOC.  */
+  p += gen_call (p, fn, 1, 0);
+  p += GEN_LD (p, 2, 1, 24);	/* Restore TOC.  */
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+}
+
+/* FN's prototype is `LONGEST(*fn)(int)'.
+   TOP = fn (arg1)
+  */
+
+static void
+ppc64v1_emit_int_call_1 (CORE_ADDR fn, int arg1)
+{
+  uint32_t buf[13];
+  uint32_t *p = buf;
+
+  /* Setup argument.  arg1 is a 16-bit value.  */
+  p += gen_limm (p, 3, arg1, 1);
+  p += GEN_STD (p, 2, 1, 40);	/* Save TOC.  */
+  p += gen_call (p, fn, 1, 1);
+  p += GEN_LD (p, 2, 1, 40);	/* Restore TOC.  */
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+}
+
+/* Likewise for ELFv2.  */
+
+static void
+ppc64v2_emit_int_call_1 (CORE_ADDR fn, int arg1)
+{
+  uint32_t buf[10];
+  uint32_t *p = buf;
+
+  /* Setup argument.  arg1 is a 16-bit value.  */
+  p += gen_limm (p, 3, arg1, 1);
+  p += GEN_STD (p, 2, 1, 24);	/* Save TOC.  */
+  p += gen_call (p, fn, 1, 0);
+  p += GEN_LD (p, 2, 1, 24);	/* Restore TOC.  */
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (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
+ppc64v1_emit_void_call_2 (CORE_ADDR fn, int arg1)
+{
+  uint32_t buf[17];
+  uint32_t *p = buf;
+
+  /* Save TOP.  0(30) is next-empty.  */
+  p += GEN_STD (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, 1);
+  p += GEN_STD (p, 2, 1, 40);	/* Save TOC.  */
+  p += gen_call (p, fn, 1, 1);
+  p += GEN_LD (p, 2, 1, 40);	/* Restore TOC.  */
+
+  /* Restore TOP */
+  p += GEN_LD (p, 3, 30, 0);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+}
+
+/* Likewise for ELFv2.  */
+
+static void
+ppc64v2_emit_void_call_2 (CORE_ADDR fn, int arg1)
+{
+  uint32_t buf[14];
+  uint32_t *p = buf;
+
+  /* Save TOP.  0(30) is next-empty.  */
+  p += GEN_STD (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, 1);
+  p += GEN_STD (p, 2, 1, 24);	/* Save TOC.  */
+  p += gen_call (p, fn, 1, 0);
+  p += GEN_LD (p, 2, 1, 24);	/* Restore TOC.  */
+
+  /* Restore TOP */
+  p += GEN_LD (p, 3, 30, 0);
+
+  emit_insns (buf, p - buf);
+  gdb_assert ((p - buf) <= (sizeof (buf) / sizeof (*buf)));
+}
+
+/* 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 = 8;
+  if (size_p)
+    *size_p = 14;
+}
+
+/* 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;
+}
+
+/* Table of emit ops for 64-bit ELFv1.  */
+
+static struct emit_ops ppc64v1_emit_ops_impl =
+{
+  ppc64v1_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,
+  ppc_emit_goto,
+  ppc_write_goto_address,
+  ppc64_emit_const,
+  ppc64v1_emit_call,
+  ppc64v1_emit_reg,
+  ppc64_emit_pop,
+  ppc64_emit_stack_flush,
+  ppc64_emit_zero_ext,
+  ppc64_emit_swap,
+  ppc_emit_stack_adjust,
+  ppc64v1_emit_int_call_1,
+  ppc64v1_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
+};
+
+/* Table of emit ops for 64-bit ELFv2.  */
+
+static struct emit_ops ppc64v2_emit_ops_impl =
+{
+  ppc64v2_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,
+  ppc_emit_goto,
+  ppc_write_goto_address,
+  ppc64_emit_const,
+  ppc64v2_emit_call,
+  ppc64v2_emit_reg,
+  ppc64_emit_pop,
+  ppc64_emit_stack_flush,
+  ppc64_emit_zero_ext,
+  ppc64_emit_swap,
+  ppc_emit_stack_adjust,
+  ppc64v2_emit_int_call_1,
+  ppc64v2_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
+};
+
+#endif
+
+/* Implementation of linux_target_ops method "emit_ops".  */
+
+static struct emit_ops *
+ppc_emit_ops (void)
+{
+#ifdef __powerpc64__
+  struct regcache *regcache = get_thread_regcache (current_thread, 0);
+
+  if (register_size (regcache->tdesc, 0) == 8)
+    {
+      if (is_elfv2_inferior ())
+        return &ppc64v2_emit_ops_impl;
+      else
+        return &ppc64v1_emit_ops_impl;
+    }
+#endif
+  return &ppc_emit_ops_impl;
+}
+
 /* Implementation of linux_target_ops method "get_ipa_tdesc_idx".  */
 
 static int
@@ -1531,7 +3125,7 @@ struct linux_target_ops the_low_target = {
   ppc_supports_tracepoints,
   ppc_get_thread_area,
   ppc_install_fast_tracepoint_jump_pad,
-  NULL, /* emit_ops */
+  ppc_emit_ops,
   ppc_get_min_fast_tracepoint_insn_len,
   NULL, /* supports_range_stepping */
   NULL, /* breakpoint_kind_from_current_state */
-- 
2.7.3

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

* Re: [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers.
  2016-03-14 17:49       ` Ulrich Weigand
@ 2016-03-22  9:19         ` Marcin Kościelnicki
  2016-03-29 18:08           ` Ulrich Weigand
  0 siblings, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-22  9:19 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches

On 14/03/16 18:49, Ulrich Weigand wrote:
> Marcin Kościelnicki wrote:
>> On 14/03/16 15:41, Ulrich Weigand wrote:
>>> I'm not sure I really like your approach, it seems odd to make common
>>> code jump through "unnatural" hoops just so that powerpc64 works.
>>> On the other hand, your approach certainly involves the least amount
>>> of changes to the current code base.
>>>
>> Yeah, I'm not that happy with it either... but we're going to need to
>> jump through some hoops in gdbserver anyway - eg. for gdb_collect, we
>> need the descriptor address, while for stop_tracing, we need the code
>> address.  So we will need some special handling for one of these sets of
>> symbols either way, and uglify the common code with it.
>
> That's certainly true as well.  Also, implementing the descriptor to
> code address lookup in exactly the same way as GDB does might be
> difficult for gdbserver to do, since it is currently reading the BFD,
> which gdbserver doesn't have available.
>
>>> I am somewhat confused about one thing, though.  In your other patch
>>> https://sourceware.org/ml/gdb-patches/2016-03/msg00201.html
>>> you seem to imply that qSymbol for function symbols simply does not
>>> work at all on powerpc64 at the moment.
>>
>> It works *sometimes* - I'm not sure what it depends on, as I'm not
>> familiar with BFD internals, but it seems gdb could have the necessary
>> information cached and not need to read the file during qSymbol
>> processing.  I, for one, had one hell of a debugging session, since my
>> simple test program linked against the IPA had all the IPA symbols
>> properly fetched, while the testsuite programs failed at the same.
>> Could be something like library load order...
>
> Hmm.  I just checked, and it turns out that as of Dec 2015 gdbserver
> actually no longer even uses the td_ta_set_event libthread_db
> callback at all.  Instead, it now always relies on PTRACE_EVENT_CLONE
> to detect new inferior threads.  This means that thread support
> shouldn't actually require qSymbol on a function symbol any more.
>
> In addition, it probably used to work in the past because GDB only
> uses the vFile packet when it is reading the target libraries from
> the target itself.  In past, GDB usually required copies of the
> target libraries to be present on the host system as well, and
> used them from there.  While there was support for loading target
> libraries remotely for a while, it was only made default about
> a year ago.
>
>
>> Yep, I thought about it, but there's the protocol compatibility issue...
>
> The more I think about it, the more I tend to agree that your
> proposal is actually the best solution.  I'd still like to give
> it a couple of days to give others a chance to comment as well ...
>
> Bye,
> Ulrich
>

Alright, so what should we do about this issue?

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

* Re: [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers.
  2016-03-22  9:19         ` Marcin Kościelnicki
@ 2016-03-29 18:08           ` Ulrich Weigand
  2016-03-29 21:51             ` Pedro Alves
  2016-03-29 21:52             ` Marcin Kościelnicki
  0 siblings, 2 replies; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-29 18:08 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: gdb-patches

Marcin Kościelnicki wrote:
> On 14/03/16 18:49, Ulrich Weigand wrote:
> > The more I think about it, the more I tend to agree that your
> > proposal is actually the best solution.  I'd still like to give
> > it a couple of days to give others a chance to comment as well ...
> 
> Alright, so what should we do about this issue?

Since nobody came up with a better idea, and since your patch doesn't
actually preclude anybody from implementing any better idea they might
come up later (since it doesn't actually change anything in the
gdbserver protocol), I'd say we just go with your patch for now.

However, there does seem to be one issue: your patch changes the
interface between gdbserver and the in-process agent in an incompatible
way.  Binaries with an old IPA built in will no longer work with a
new gdbserver, since it will will expect exported symbols like
gdb_collect_ptr, which the old binary doesn't export.

I think it would be preferable to implement a backward-compatible
way where gdbserver checks for the new symbol, and if it isn't
present, falls back to the old symbol.

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH 2/4 v2] IPA: Add alloc_jump_pad_buffer target hook.
  2016-03-18 15:08   ` [PATCH 2/4 v2] " Marcin Kościelnicki
@ 2016-03-29 18:18     ` Ulrich Weigand
  2016-03-29 22:04       ` Marcin Kościelnicki
  2016-03-31  1:16       ` [PATCH 2/4 v3] " Marcin Kościelnicki
  0 siblings, 2 replies; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-29 18:18 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: gdb-patches, Marcin Kościelnicki

Marcin Kościelnicki wrote:

> Targets may have various requirements on the required location of the jump
> pad area.  Currently IPA allocates it at the lowest possible address,
> so that it is reachable by branches from the executable.  However, this
> fails on powerpc, which has executable link address (0x10000000) much
> larger than branch reach (+/- 32MiB).
> 
> This makes jump pad buffer allocation a target hook instead.  The current
> implementations are as follows:
> 
> - i386: Branches can reach anywhere, so just mmap it.  This avoids
>   the linear search dance.
> - x86_64: Branches have +/-2GiB of reach, and executable is loaded low,
>   so just call mmap with MAP_32BIT.  Likewise avoids the linear search.
> - aarch64: Branches have +-128MiB of reach, executable loaded at 4MiB.
>   Do a linear search from 4MiB-size downwards to page_size.

This makes sense to me, but I agree that this needs testing on the
affected platforms, in particular aarch64.

> +void *alloc_jump_pad_buffer (size_t size);
> +#ifdef HAVE_GETAUXVAL
> +unsigned long getauxval (unsigned long type);
> +#endif

Shouldn't this use a guard like
#if !defined HAVE_GETAUXVAL && defined IN_PROCESS_AGENT
just as in the source file?

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH v2 3/4] gdbserver: Add powerpc fast tracepoint support.
  2016-03-18 15:09           ` [PATCH v2 3/4] " Marcin Kościelnicki
@ 2016-03-29 18:23             ` Ulrich Weigand
  2016-03-30 14:52             ` Simon Marchi
  1 sibling, 0 replies; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-29 18:23 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: gdb-patches, Marcin Kościelnicki

> gdb/gdbserver/ChangeLog:
> 
> 2016-03-13  Wei-cheng Wang  <cole945@gmail.com>
> 	    Marcin Kościelnicki  <koriakin@0x04.net>
> 
> 	* Makefile.in: Add powerpc-*-ipa.o
> 	* configure.srv: Add ipa_obj for powerpc*-linux.
> 	* linux-ppc-ipa.c: New file.
> 	* linux-ppc-low.c: Added linux-ppc-tdesc.h, ax.h,
> 	tracepoint.h includes.
> 	(PPC_FIELD): New macro.
> 	(PPC_SEXT): New macro.
> 	(PPC_OP6): New macro.
> 	(PPC_BO): New macro.
> 	(PPC_LI): New macro.
> 	(PPC_BD): New macro.
> 	(init_registers_*): Move prototype to linux-ppc-tdesc.h.
> 	(tdesc_*): Move declaration to linux-ppc-tdesc.h.
> 	(ppc_get_hwcap): Rename to ppc_get_auxv and add type parameter.
> 	(ppc_get_thread_area): New function.
> 	(is_elfv2_inferior): New function.
> 	(gen_ds_form): New function.
> 	(GEN_STD): New macro.
> 	(GEN_STDU): New macro.
> 	(GEN_LD): New macro.
> 	(GEN_LDU): New macro.
> 	(gen_d_form): New function.
> 	(GEN_ADDI): New macro.
> 	(GEN_ADDIS): New macro.
> 	(GEN_LI): New macro.
> 	(GEN_LIS): New macro.
> 	(GEN_ORI): New macro.
> 	(GEN_ORIS): New macro.
> 	(GEN_LWZ): New macro.
> 	(GEN_STW): New macro.
> 	(GEN_STWU): New macro.
> 	(gen_xfx_form): New function.
> 	(GEN_MFSPR): New macro.
> 	(GEN_MTSPR): New macro.
> 	(GEN_MFCR): New macro.
> 	(GEN_MTCR): New macro.
> 	(GEN_SYNC): New macro.
> 	(GEN_LWSYNC): New macro.
> 	(gen_x_form): New function.
> 	(GEN_OR): New macro.
> 	(GEN_MR): New macro.
> 	(GEN_LWARX): New macro.
> 	(GEN_STWCX): New macro.
> 	(GEN_CMPW): New macro.
> 	(gen_md_form): New function.
> 	(GEN_RLDICL): New macro.
> 	(GEN_RLDICR): New macro.
> 	(gen_i_form): New function.
> 	(GEN_B): New macro.
> 	(GEN_BL): New macro.
> 	(gen_b_form): New function.
> 	(GEN_BNE): New macro.
> 	(GEN_LOAD): New macro.
> 	(GEN_STORE): New macro.
> 	(gen_limm): New function.
> 	(gen_atomic_xchg): New function.
> 	(gen_call): New function.
> 	(ppc_relocate_instruction): New function.
> 	(ppc_install_fast_tracepoint_jump_pad): New function.
> 	(ppc_get_min_fast_tracepoint_insn_len): New function.
> 	(ppc_get_ipa_tdesc_idx): New function.
> 	(the_low_target): Wire in the new functions.
> 	(initialize_low_arch) [!__powerpc64__]: Don'it initialize 64-bit
> 	tdescs.
> 	* linux-ppc-tdesc.h: New file.

This is OK once the pre-requisite patches are in.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH v2 4/4] gdbserver: Add emit_ops for powerpc.
  2016-03-18 15:10     ` [PATCH v2 " Marcin Kościelnicki
@ 2016-03-29 18:25       ` Ulrich Weigand
  2016-03-31 13:45         ` Marcin Kościelnicki
  0 siblings, 1 reply; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-29 18:25 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: gdb-patches, Marcin Kościelnicki

> gdb/gdbserver/ChangeLog:
> 
> 2016-03-14  Wei-cheng Wang  <cole945@gmail.com>
> 	    Marcin Kościelnicki  <koriakin@0x04.net>
> 
> 	* linux-ppc-low.c (emit_insns): New function.
> 	(__EMIT_ASM, _EMIT_ASM, EMIT_ASM): New macros.
> 	(ppc_emit_prologue): New function.
> 	(ppc_emit_epilogue): New function.
> 	(ppc_emit_add): New function.
> 	(ppc_emit_sub): New function.
> 	(ppc_emit_mul): New function.
> 	(ppc_emit_lsh): New function.
> 	(ppc_emit_rsh_signed): New function.
> 	(ppc_emit_rsh_unsigned): New function.
> 	(ppc_emit_ext): New function.
> 	(ppc_emit_zero_ext): New function.
> 	(ppc_emit_log_not): New function.
> 	(ppc_emit_bit_and): New function.
> 	(ppc_emit_bit_or): New function.
> 	(ppc_emit_bit_xor): New function.
> 	(ppc_emit_bit_not): New function.
> 	(ppc_emit_equal): New function.
> 	(ppc_emit_less_signed): New function.
> 	(ppc_emit_less_unsigned): New function.
> 	(ppc_emit_ref): New function.
> 	(ppc_emit_const): New function.
> 	(ppc_emit_reg): New function.
> 	(ppc_emit_pop): New function.
> 	(ppc_emit_stack_flush): New function.
> 	(ppc_emit_swap): New function.
> 	(ppc_emit_stack_adjust): New function.
> 	(ppc_emit_call): New function.
> 	(ppc_emit_int_call_1): New function.
> 	(ppc_emit_void_call_2): New function.
> 	(ppc_emit_if_goto): New function.
> 	(ppc_emit_goto): New function.
> 	(ppc_emit_eq_goto): New function.
> 	(ppc_emit_ne_goto): New function.
> 	(ppc_emit_lt_goto): New function.
> 	(ppc_emit_le_goto): New function.
> 	(ppc_emit_gt_goto): New function.
> 	(ppc_emit_ge_goto): New function.
> 	(ppc_write_goto_address): New function.
> 	(ppc_emit_ops_impl): New static variable.
> 	(ppc64v1_emit_prologue): New function.
> 	(ppc64v2_emit_prologue): New function.
> 	(ppc64_emit_epilogue): New function.
> 	(ppc64_emit_add): New function.
> 	(ppc64_emit_sub): New function.
> 	(ppc64_emit_mul): New function.
> 	(ppc64_emit_lsh): New function.
> 	(ppc64_emit_rsh_signed): New function.
> 	(ppc64_emit_rsh_unsigned): New function.
> 	(ppc64_emit_ext): New function.
> 	(ppc64_emit_zero_ext): New function.
> 	(ppc64_emit_log_not): New function.
> 	(ppc64_emit_bit_and): New function.
> 	(ppc64_emit_bit_or): New function.
> 	(ppc64_emit_bit_xor): New function.
> 	(ppc64_emit_bit_not): New function.
> 	(ppc64_emit_equal): New function.
> 	(ppc64_emit_less_signed): New function.
> 	(ppc64_emit_less_unsigned): New function.
> 	(ppc64_emit_ref): New function.
> 	(ppc64_emit_const): New function.
> 	(ppc64v1_emit_reg): New function.
> 	(ppc64v2_emit_reg): New function.
> 	(ppc64_emit_pop): New function.
> 	(ppc64_emit_stack_flush): New function.
> 	(ppc64_emit_swap): New function.
> 	(ppc64v1_emit_call): New function.
> 	(ppc64v2_emit_call): New function.
> 	(ppc64v1_emit_int_call_1): New function.
> 	(ppc64v2_emit_int_call_1): New function.
> 	(ppc64v1_emit_void_call_2): New function.
> 	(ppc64v2_emit_void_call_2): New function.
> 	(ppc64_emit_if_goto): New function.
> 	(ppc64_emit_eq_goto): New function.
> 	(ppc64_emit_ne_goto): New function.
> 	(ppc64_emit_lt_goto): New function.
> 	(ppc64_emit_le_goto): New function.
> 	(ppc64_emit_gt_goto): New function.
> 	(ppc64_emit_ge_goto): New function.
> 	(ppc64v1_emit_ops_impl): New static variable.
> 	(ppc64v2_emit_ops_impl): New static variable.
> 	(ppc_emit_ops): New function.
> 	(linux_low_target): Wire in ppc_emit_ops.
> ---
> The only change in this version is that is_elfv2_inferior is used instead of
> assuming same ABI as gdbserver.

Still OK once the rest is in.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers.
  2016-03-29 18:08           ` Ulrich Weigand
@ 2016-03-29 21:51             ` Pedro Alves
  2016-03-30 11:30               ` Ulrich Weigand
  2016-03-29 21:52             ` Marcin Kościelnicki
  1 sibling, 1 reply; 56+ messages in thread
From: Pedro Alves @ 2016-03-29 21:51 UTC (permalink / raw)
  To: Ulrich Weigand, Marcin Kościelnicki; +Cc: gdb-patches

On 03/29/2016 07:08 PM, Ulrich Weigand wrote:

> However, there does seem to be one issue: your patch changes the
> interface between gdbserver and the in-process agent in an incompatible
> way.  Binaries with an old IPA built in will no longer work with a
> new gdbserver, since it will will expect exported symbols like
> gdb_collect_ptr, which the old binary doesn't export.
> 
> I think it would be preferable to implement a backward-compatible
> way where gdbserver checks for the new symbol, and if it isn't
> present, falls back to the old symbol.

So far, given the tight coupling between gdbserver and the IPA's
implementation, we've required that gdbserver and the IPA must
be of the same version.  We're added new functions to the
interface before without trying to maintain backwards compatibility.

Thanks,
Pedro Alves

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

* Re: [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers.
  2016-03-29 18:08           ` Ulrich Weigand
  2016-03-29 21:51             ` Pedro Alves
@ 2016-03-29 21:52             ` Marcin Kościelnicki
  2016-03-30 11:32               ` Ulrich Weigand
  1 sibling, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-29 21:52 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches

On 29/03/16 20:08, Ulrich Weigand wrote:
> Marcin Kościelnicki wrote:
>> On 14/03/16 18:49, Ulrich Weigand wrote:
>>> The more I think about it, the more I tend to agree that your
>>> proposal is actually the best solution.  I'd still like to give
>>> it a couple of days to give others a chance to comment as well ...
>>
>> Alright, so what should we do about this issue?
>
> Since nobody came up with a better idea, and since your patch doesn't
> actually preclude anybody from implementing any better idea they might
> come up later (since it doesn't actually change anything in the
> gdbserver protocol), I'd say we just go with your patch for now.

Very well, then.  For this to be actually useful for powerpc64, I'll 
also need an ack on the other patch 
(https://sourceware.org/ml/gdb-patches/2016-03/msg00201.html).

> However, there does seem to be one issue: your patch changes the
> interface between gdbserver and the in-process agent in an incompatible
> way.  Binaries with an old IPA built in will no longer work with a
> new gdbserver, since it will will expect exported symbols like
> gdb_collect_ptr, which the old binary doesn't export.
>
> I think it would be preferable to implement a backward-compatible
> way where gdbserver checks for the new symbol, and if it isn't
> present, falls back to the old symbol.

Alright, I can do that, though I seem to recall we don't care about 
gdbserver/IPA interface compatibility (and IPA is always built as 
shared, so there's no concern about an executable with old version built 
in).
>
> Bye,
> Ulrich
>

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

* Re: [PATCH 2/4 v2] IPA: Add alloc_jump_pad_buffer target hook.
  2016-03-29 18:18     ` Ulrich Weigand
@ 2016-03-29 22:04       ` Marcin Kościelnicki
  2016-03-30 11:38         ` Ulrich Weigand
  2016-03-31  1:16       ` [PATCH 2/4 v3] " Marcin Kościelnicki
  1 sibling, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-29 22:04 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches

On 29/03/16 20:18, Ulrich Weigand wrote:
> Marcin Kościelnicki wrote:
>
>> Targets may have various requirements on the required location of the jump
>> pad area.  Currently IPA allocates it at the lowest possible address,
>> so that it is reachable by branches from the executable.  However, this
>> fails on powerpc, which has executable link address (0x10000000) much
>> larger than branch reach (+/- 32MiB).
>>
>> This makes jump pad buffer allocation a target hook instead.  The current
>> implementations are as follows:
>>
>> - i386: Branches can reach anywhere, so just mmap it.  This avoids
>>    the linear search dance.
>> - x86_64: Branches have +/-2GiB of reach, and executable is loaded low,
>>    so just call mmap with MAP_32BIT.  Likewise avoids the linear search.
>> - aarch64: Branches have +-128MiB of reach, executable loaded at 4MiB.
>>    Do a linear search from 4MiB-size downwards to page_size.
>
> This makes sense to me, but I agree that this needs testing on the
> affected platforms, in particular aarch64.

Right.  I've tested on i386 and x86_64.  Unfortunately I have no means 
of testing on aarch64 - could someone lend a hand here?

Also, since s390 tracepoints have just landed, I'll update the patch to 
cover s390 and s390x as well.
>
>> +void *alloc_jump_pad_buffer (size_t size);
>> +#ifdef HAVE_GETAUXVAL
>> +unsigned long getauxval (unsigned long type);
>> +#endif
>
> Shouldn't this use a guard like
> #if !defined HAVE_GETAUXVAL && defined IN_PROCESS_AGENT
> just as in the source file?

Whoops, you're obviously right - I'm going to change the guard to 
#ifndef HAVE_GETAUXVAL (since it's already inside #ifdef 
IN_PROCESS_AGENT).  I'll send this fix in v3 along with s390 support.
>
> Bye,
> Ulrich
>

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

* Re: [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers.
  2016-03-29 21:51             ` Pedro Alves
@ 2016-03-30 11:30               ` Ulrich Weigand
  0 siblings, 0 replies; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-30 11:30 UTC (permalink / raw)
  To: Pedro Alves; +Cc: Marcin Kościelnicki, gdb-patches

Pedro Alves wrote:
> On 03/29/2016 07:08 PM, Ulrich Weigand wrote:
> 
> > However, there does seem to be one issue: your patch changes the
> > interface between gdbserver and the in-process agent in an incompatible
> > way.  Binaries with an old IPA built in will no longer work with a
> > new gdbserver, since it will will expect exported symbols like
> > gdb_collect_ptr, which the old binary doesn't export.
> > 
> > I think it would be preferable to implement a backward-compatible
> > way where gdbserver checks for the new symbol, and if it isn't
> > present, falls back to the old symbol.
> 
> So far, given the tight coupling between gdbserver and the IPA's
> implementation, we've required that gdbserver and the IPA must
> be of the same version.  We're added new functions to the
> interface before without trying to maintain backwards compatibility.

Ah, OK, I didn't realize that.  That's fine with me as well.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers.
  2016-03-29 21:52             ` Marcin Kościelnicki
@ 2016-03-30 11:32               ` Ulrich Weigand
  2016-03-30 22:02                 ` Marcin Kościelnicki
  0 siblings, 1 reply; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-30 11:32 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: gdb-patches

Marcin Kościelnicki wrote:
> On 29/03/16 20:08, Ulrich Weigand wrote:
> > Marcin Kościelnicki wrote:
> >> On 14/03/16 18:49, Ulrich Weigand wrote:
> >>> The more I think about it, the more I tend to agree that your
> >>> proposal is actually the best solution.  I'd still like to give
> >>> it a couple of days to give others a chance to comment as well ...
> >>
> >> Alright, so what should we do about this issue?
> >
> > Since nobody came up with a better idea, and since your patch doesn't
> > actually preclude anybody from implementing any better idea they might
> > come up later (since it doesn't actually change anything in the
> > gdbserver protocol), I'd say we just go with your patch for now.
> 
> Very well, then.  For this to be actually useful for powerpc64, I'll 
> also need an ack on the other patch 
> (https://sourceware.org/ml/gdb-patches/2016-03/msg00201.html).

This looks to be resolved now.

> > However, there does seem to be one issue: your patch changes the
> > interface between gdbserver and the in-process agent in an incompatible
> > way.  Binaries with an old IPA built in will no longer work with a
> > new gdbserver, since it will will expect exported symbols like
> > gdb_collect_ptr, which the old binary doesn't export.
> >
> > I think it would be preferable to implement a backward-compatible
> > way where gdbserver checks for the new symbol, and if it isn't
> > present, falls back to the old symbol.
> 
> Alright, I can do that, though I seem to recall we don't care about 
> gdbserver/IPA interface compatibility (and IPA is always built as 
> shared, so there's no concern about an executable with old version built 
> in).

And this turns out to be not necessary after all, see the recent
mail by Pedro.  Sorry for the confusion.

I think the patch should be OK now.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH 2/4 v2] IPA: Add alloc_jump_pad_buffer target hook.
  2016-03-29 22:04       ` Marcin Kościelnicki
@ 2016-03-30 11:38         ` Ulrich Weigand
  2016-03-30 14:50           ` Yao Qi
  0 siblings, 1 reply; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-30 11:38 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: gdb-patches, pierre.langlois, yao.qi

Marcin Kościelnicki wrote:
> On 29/03/16 20:18, Ulrich Weigand wrote:
> > Marcin Kościelnicki wrote:
> >
> >> Targets may have various requirements on the required location of the jump
> >> pad area.  Currently IPA allocates it at the lowest possible address,
> >> so that it is reachable by branches from the executable.  However, this
> >> fails on powerpc, which has executable link address (0x10000000) much
> >> larger than branch reach (+/- 32MiB).
> >>
> >> This makes jump pad buffer allocation a target hook instead.  The current
> >> implementations are as follows:
> >>
> >> - i386: Branches can reach anywhere, so just mmap it.  This avoids
> >>    the linear search dance.
> >> - x86_64: Branches have +/-2GiB of reach, and executable is loaded low,
> >>    so just call mmap with MAP_32BIT.  Likewise avoids the linear search.
> >> - aarch64: Branches have +-128MiB of reach, executable loaded at 4MiB.
> >>    Do a linear search from 4MiB-size downwards to page_size.
> >
> > This makes sense to me, but I agree that this needs testing on the
> > affected platforms, in particular aarch64.
> 
> Right.  I've tested on i386 and x86_64.  Unfortunately I have no means 
> of testing on aarch64 - could someone lend a hand here?

Pierre or Yao ... you've been working in this area recently, could you
have a look at Marcin's patch and give it a test?   Thanks!

> Also, since s390 tracepoints have just landed, I'll update the patch to 
> cover s390 and s390x as well.
> >
> >> +void *alloc_jump_pad_buffer (size_t size);
> >> +#ifdef HAVE_GETAUXVAL
> >> +unsigned long getauxval (unsigned long type);
> >> +#endif
> >
> > Shouldn't this use a guard like
> > #if !defined HAVE_GETAUXVAL && defined IN_PROCESS_AGENT
> > just as in the source file?
> 
> Whoops, you're obviously right - I'm going to change the guard to 
> #ifndef HAVE_GETAUXVAL (since it's already inside #ifdef 
> IN_PROCESS_AGENT).  I'll send this fix in v3 along with s390 support.

OK, thanks!

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH 2/4 v2] IPA: Add alloc_jump_pad_buffer target hook.
  2016-03-30 11:38         ` Ulrich Weigand
@ 2016-03-30 14:50           ` Yao Qi
  2016-03-30 14:58             ` Ulrich Weigand
  0 siblings, 1 reply; 56+ messages in thread
From: Yao Qi @ 2016-03-30 14:50 UTC (permalink / raw)
  To: Ulrich Weigand, Marcin Kościelnicki
  Cc: gdb-patches, pierre.langlois, yao.qi

Hi Ulrich,

On 30/03/16 12:38, Ulrich Weigand wrote:
>> Right.  I've tested on i386 and x86_64.  Unfortunately I have no means
>> >of testing on aarch64 - could someone lend a hand here?
> Pierre or Yao ... you've been working in this area recently, could you
> have a look at Marcin's patch and give it a test?   Thanks!
>

No problem, I'll do a test on my aarch64 box, and let you know the
result.  Do you want me to test this single patch or the whole patch series?

b.t.w, there are some aarch64 linux boxes on gcc compile farm and you 
can use them.  See https://gcc.gnu.org/wiki/CompileFarm

-- 
Yao (齐尧)

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

* Re: [PATCH v2 3/4] gdbserver: Add powerpc fast tracepoint support.
  2016-03-18 15:09           ` [PATCH v2 3/4] " Marcin Kościelnicki
  2016-03-29 18:23             ` Ulrich Weigand
@ 2016-03-30 14:52             ` Simon Marchi
  2016-03-30 14:57               ` Ulrich Weigand
  1 sibling, 1 reply; 56+ messages in thread
From: Simon Marchi @ 2016-03-30 14:52 UTC (permalink / raw)
  To: Marcin Kościelnicki, uweigand; +Cc: gdb-patches

Hi Marcin,

One note below.

On 16-03-18 11:09 AM, Marcin Kościelnicki wrote:
> +#ifdef __powerpc64__
> +
> +/* Returns 1 if inferior is using ELFv2 ABI.  Undefined for 32-bit
> +   inferiors.  */
> +
> +static int
> +is_elfv2_inferior (void)
> +{
> +  /* To be used as fallback if we're unable to determine the right result -
> +     assume inferior uses the same ABI as gdbserver.  */
> +#if _CALL_ELF == 2
> +  const int def_res = 1;
> +#else
> +  const int def_res = 0;
> +#endif
> +  unsigned long phdr;
> +  Elf64_Ehdr ehdr;
> +
> +  if (!ppc_get_auxv (AT_PHDR, &phdr))
> +    return def_res;
> +
> +  /* Assume ELF header is at the beginning of the page where program headers
> +     are located.  If it doesn't look like one, bail.  */
> +
> +  read_inferior_memory (phdr & ~0xfff, (unsigned char *) &ehdr, sizeof ehdr);
> +  if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG))
> +    return def_res;
> +
> +  return (ehdr.e_flags & EF_PPC64_ABI) == 2;
> +}

This gives me an error when building on the gcc compile farm machine gcc110.  I just
applied your patches on today's master.

linux-ppc-low.c: In function ‘is_elfv2_inferior’:
linux-ppc-low.c:774:26: error: ‘EF_PPC64_ABI’ undeclared (first use in this function)
   return (ehdr.e_flags & EF_PPC64_ABI) == 2;
                          ^
linux-ppc-low.c:774:26: note: each undeclared identifier is reported only once for each function it appears in
linux-ppc-low.c:775:1: error: control reaches end of non-void function [-Werror=return-type]
 }
 ^

I am not familiar with PPC, so I have no idea how to fix it.  I just replaced it "return 0"
so that it built, and I was able to test what I wanted to test :).

Side note, would it be possible to avoid putting the ChangeLog changes in the diff?  It makes
it overly complicated to apply patches since there are constantly some conflicts.  It's common
to put them in the commit message for the review, and add them to the actual patch at commit
time.

Thanks!

Simon

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

* Re: [PATCH v2 3/4] gdbserver: Add powerpc fast tracepoint support.
  2016-03-30 14:52             ` Simon Marchi
@ 2016-03-30 14:57               ` Ulrich Weigand
  2016-03-30 15:24                 ` Simon Marchi
  0 siblings, 1 reply; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-30 14:57 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Marcin Kościelnicki, gdb-patches

Hi Marcin,

> This gives me an error when building on the gcc compile farm machine gcc110.
> I just applied your patches on today's master.

> linux-ppc-low.c: In function 'is_elfv2_inferior':
> linux-ppc-low.c:774:26: error: 'EF_PPC64_ABI' undeclared (f=
> irst use in this function)
>    return (ehdr.e_flags & EF_PPC64_ABI) == 2;

You probably should add

#include "elf/ppc64.h"

to make sure you always got the latest defines from the in-tree
BFD headers, and not the (possibly outdated) system headers.

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH 2/4 v2] IPA: Add alloc_jump_pad_buffer target hook.
  2016-03-30 14:50           ` Yao Qi
@ 2016-03-30 14:58             ` Ulrich Weigand
  2016-03-31  7:34               ` Yao Qi
  0 siblings, 1 reply; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-30 14:58 UTC (permalink / raw)
  To: Yao Qi; +Cc: Marcin Kościelnicki, gdb-patches, pierre.langlois, yao.qi

Hi Yao,

> On 30/03/16 12:38, Ulrich Weigand wrote:
> >> Right.  I've tested on i386 and x86_64.  Unfortunately I have no means
> >> >of testing on aarch64 - could someone lend a hand here?
> > Pierre or Yao ... you've been working in this area recently, could you
> > have a look at Marcin's patch and give it a test?   Thanks!
> >
> 
> No problem, I'll do a test on my aarch64 box, and let you know the
> result.  Do you want me to test this single patch or the whole patch series?

Many thanks!  Just testing the single patch should be OK.

> b.t.w, there are some aarch64 linux boxes on gcc compile farm and you 
> can use them.  See https://gcc.gnu.org/wiki/CompileFarm

Ah, good to know for next time :-)

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH v2 3/4] gdbserver: Add powerpc fast tracepoint support.
  2016-03-30 14:57               ` Ulrich Weigand
@ 2016-03-30 15:24                 ` Simon Marchi
  2016-03-30 15:28                   ` Simon Marchi
  0 siblings, 1 reply; 56+ messages in thread
From: Simon Marchi @ 2016-03-30 15:24 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: Marcin Kościelnicki, gdb-patches

On 16-03-30 10:57 AM, Ulrich Weigand wrote:
> Hi Marcin,
> 
>> This gives me an error when building on the gcc compile farm machine gcc110.
>> I just applied your patches on today's master.
> 
>> linux-ppc-low.c: In function 'is_elfv2_inferior':
>> linux-ppc-low.c:774:26: error: 'EF_PPC64_ABI' undeclared (f=
>> irst use in this function)
>>    return (ehdr.e_flags & EF_PPC64_ABI) == 2;
> 
> You probably should add
> 
> #include "elf/ppc64.h"
> 
> to make sure you always got the latest defines from the in-tree
> BFD headers, and not the (possibly outdated) system headers.
> 
> Bye,
> Ulrich

I now get this:

In file included from ./../../include/elf/ppc64.h:24:0,
                 from linux-ppc-low.c:30:
./../../include/elf/ppc64.h:28:17: error: expected identifier before numeric constant
   RELOC_NUMBER (R_PPC64_NONE,       0)
                 ^
./../../include/elf/reloc-macros.h:122:37: note: in definition of macro ‘RELOC_NUMBER’
 #define RELOC_NUMBER(name, number)  name = number,
                                     ^
In file included from linux-ppc-low.c:30:0:
./../../include/elf/ppc64.h:240:0: error: "DT_PPC64_GLINK" redefined [-Werror]
 #define DT_PPC64_GLINK  DT_LOPROC
 ^
In file included from linux-ppc-low.c:23:0:
/usr/include/elf.h:2264:0: note: this is the location of the previous definition
 #define DT_PPC64_GLINK  (DT_LOPROC + 0)
 ^

Simon

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

* Re: [PATCH v2 3/4] gdbserver: Add powerpc fast tracepoint support.
  2016-03-30 15:24                 ` Simon Marchi
@ 2016-03-30 15:28                   ` Simon Marchi
  2016-03-30 15:35                     ` Ulrich Weigand
  0 siblings, 1 reply; 56+ messages in thread
From: Simon Marchi @ 2016-03-30 15:28 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: Marcin Kościelnicki, gdb-patches

On 16-03-30 11:24 AM, Simon Marchi wrote:
> On 16-03-30 10:57 AM, Ulrich Weigand wrote:
>> Hi Marcin,
>>
>>> This gives me an error when building on the gcc compile farm machine gcc110.
>>> I just applied your patches on today's master.
>>
>>> linux-ppc-low.c: In function 'is_elfv2_inferior':
>>> linux-ppc-low.c:774:26: error: 'EF_PPC64_ABI' undeclared (f=
>>> irst use in this function)
>>>    return (ehdr.e_flags & EF_PPC64_ABI) == 2;
>>
>> You probably should add
>>
>> #include "elf/ppc64.h"
>>
>> to make sure you always got the latest defines from the in-tree
>> BFD headers, and not the (possibly outdated) system headers.
>>
>> Bye,
>> Ulrich
> 
> I now get this:
> 
> In file included from ./../../include/elf/ppc64.h:24:0,
>                  from linux-ppc-low.c:30:
> ./../../include/elf/ppc64.h:28:17: error: expected identifier before numeric constant
>    RELOC_NUMBER (R_PPC64_NONE,       0)
>                  ^
> ./../../include/elf/reloc-macros.h:122:37: note: in definition of macro ‘RELOC_NUMBER’
>  #define RELOC_NUMBER(name, number)  name = number,
>                                      ^
> In file included from linux-ppc-low.c:30:0:
> ./../../include/elf/ppc64.h:240:0: error: "DT_PPC64_GLINK" redefined [-Werror]
>  #define DT_PPC64_GLINK  DT_LOPROC
>  ^
> In file included from linux-ppc-low.c:23:0:
> /usr/include/elf.h:2264:0: note: this is the location of the previous definition
>  #define DT_PPC64_GLINK  (DT_LOPROC + 0)
>  ^
> 
> Simon

Ahh, it seems like the ordering is important here.  If I include it before <elf.h> (and
everything that includes <elf.h>), it works.

Thanks,

Simon




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

* Re: [PATCH v2 3/4] gdbserver: Add powerpc fast tracepoint support.
  2016-03-30 15:28                   ` Simon Marchi
@ 2016-03-30 15:35                     ` Ulrich Weigand
  2016-03-31  1:31                       ` Marcin Kościelnicki
  0 siblings, 1 reply; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-30 15:35 UTC (permalink / raw)
  To: Simon Marchi; +Cc: Marcin Kościelnicki, gdb-patches

Simon Marchi wrote:

> Ahh, it seems like the ordering is important here.  If I include it before
> <elf.h> (and everything that includes <elf.h>), it works.

Hmm, it would probably be best to avoid mixing in-tree BFD headers and
system headers this way.  I'd suggest to *not* include <elf.h> at all,
but instead use:

#include "elf/common.h"
#include "elf/ppc64.h"

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers.
  2016-03-30 11:32               ` Ulrich Weigand
@ 2016-03-30 22:02                 ` Marcin Kościelnicki
  2016-03-31 18:22                   ` Sergio Durigan Junior
  0 siblings, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-30 22:02 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches

On 30/03/16 13:32, Ulrich Weigand wrote:
> Marcin Kościelnicki wrote:
>> On 29/03/16 20:08, Ulrich Weigand wrote:
>>> Marcin Kościelnicki wrote:
>>>> On 14/03/16 18:49, Ulrich Weigand wrote:
>>>>> The more I think about it, the more I tend to agree that your
>>>>> proposal is actually the best solution.  I'd still like to give
>>>>> it a couple of days to give others a chance to comment as well ...
>>>>
>>>> Alright, so what should we do about this issue?
>>>
>>> Since nobody came up with a better idea, and since your patch doesn't
>>> actually preclude anybody from implementing any better idea they might
>>> come up later (since it doesn't actually change anything in the
>>> gdbserver protocol), I'd say we just go with your patch for now.
>>
>> Very well, then.  For this to be actually useful for powerpc64, I'll
>> also need an ack on the other patch
>> (https://sourceware.org/ml/gdb-patches/2016-03/msg00201.html).
>
> This looks to be resolved now.
>
>>> However, there does seem to be one issue: your patch changes the
>>> interface between gdbserver and the in-process agent in an incompatible
>>> way.  Binaries with an old IPA built in will no longer work with a
>>> new gdbserver, since it will will expect exported symbols like
>>> gdb_collect_ptr, which the old binary doesn't export.
>>>
>>> I think it would be preferable to implement a backward-compatible
>>> way where gdbserver checks for the new symbol, and if it isn't
>>> present, falls back to the old symbol.
>>
>> Alright, I can do that, though I seem to recall we don't care about
>> gdbserver/IPA interface compatibility (and IPA is always built as
>> shared, so there's no concern about an executable with old version built
>> in).
>
> And this turns out to be not necessary after all, see the recent
> mail by Pedro.  Sorry for the confusion.
>
> I think the patch should be OK now.

Thanks.  I've resolved a trivial interaction with the s390 changes 
pushed in the meantime (linux-s390-ipa.c needs an identical fix to the 
others) and pushed it.

>
> Thanks,
> Ulrich
>

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

* [PATCH 2/4 v3] IPA: Add alloc_jump_pad_buffer target hook.
  2016-03-29 18:18     ` Ulrich Weigand
  2016-03-29 22:04       ` Marcin Kościelnicki
@ 2016-03-31  1:16       ` Marcin Kościelnicki
  2016-03-31 11:38         ` Ulrich Weigand
  2016-04-01 14:43         ` Ulrich Weigand
  1 sibling, 2 replies; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-31  1:16 UTC (permalink / raw)
  To: uweigand; +Cc: gdb-patches, Marcin Kościelnicki

Targets may have various requirements on the required location of the jump
pad area.  Currently IPA allocates it at the lowest possible address,
so that it is reachable by branches from the executable.  However, this
fails on powerpc, which has executable link address (0x10000000) much
larger than branch reach (+/- 32MiB).

This makes jump pad buffer allocation a target hook instead.  The current
implementations are as follows:

- i386 and s390: Branches can reach anywhere, so just mmap it.  This
  avoids the linear search dance.
- x86_64: Branches have +/-2GiB of reach, and executable is loaded low,
  so just call mmap with MAP_32BIT.  Likewise avoids the linear search.
- aarch64: Branches have +-128MiB of reach, executable loaded at 4MiB.
  Do a linear search from 4MiB-size downwards to page_size.
- s390x: Branches have +-4GiB of reach, executable loaded at 2GiB.
  Do like on aarch64.

gdb/gdbserver/ChangeLog:

	* linux-aarch64-ipa.c: Add <sys/mman.h> and <sys/auxv.h> includes.
	(alloc_jump_pad_buffer): New function.
	* linux-amd64-ipa.c: Add <sys/mman.h> include.
	(alloc_jump_pad_buffer): New function.
	* linux-i386-ipa.c (alloc_jump_pad_buffer): New function.
	* linux-s390-ipa.c: Add <sys/mman.h> and <sys/auxv.h> includes.
	(alloc_jump_pad_buffer): New function.
	* tracepoint.c (getauxval) [!HAVE_GETAUXVAL]: New function.
	(initialize_tracepoint): Delegate to alloc_jump_pad_buffer.
	* tracepoint.h (alloc_jump_pad_buffer): New prototype.
	(getauxval) [!HAVE_GETAUXVAL]: New prototype.
---
This version has the fixed HAVE_GETAUXVAL guard and the s390
implementations in linux-s390-ipa.c .

 gdb/gdbserver/linux-aarch64-ipa.c | 50 +++++++++++++++++++++++++++++++++
 gdb/gdbserver/linux-amd64-ipa.c   | 18 ++++++++++++
 gdb/gdbserver/linux-i386-ipa.c    | 15 ++++++++++
 gdb/gdbserver/linux-s390-ipa.c    | 59 +++++++++++++++++++++++++++++++++++++++
 gdb/gdbserver/tracepoint.c        | 53 ++++++++++++++++++++++-------------
 gdb/gdbserver/tracepoint.h        |  4 +++
 6 files changed, 180 insertions(+), 19 deletions(-)

diff --git a/gdb/gdbserver/linux-aarch64-ipa.c b/gdb/gdbserver/linux-aarch64-ipa.c
index 00cbf3e..50caeae 100644
--- a/gdb/gdbserver/linux-aarch64-ipa.c
+++ b/gdb/gdbserver/linux-aarch64-ipa.c
@@ -19,7 +19,11 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
+#include <sys/mman.h>
 #include "tracepoint.h"
+#ifdef HAVE_GETAUXVAL
+#include <sys/auxv.h>
+#endif
 
 /* Defined in auto-generated file aarch64.c.  */
 void init_registers_aarch64 (void);
@@ -153,6 +157,52 @@ get_ipa_tdesc (int idx)
   return tdesc_aarch64;
 }
 
+/* Allocate buffer for the jump pads.  The branch instruction has a reach
+   of +/- 128MiB, and the executable is loaded at 0x400000 (4MiB).
+   To maximize the area of executable that can use tracepoints, try
+   allocating at 0x400000 - size initially, decreasing until we hit
+   a free area.  */
+
+void *
+alloc_jump_pad_buffer (size_t size)
+{
+  uintptr_t addr;
+  uintptr_t exec_base = getauxval (AT_PHDR);
+  int pagesize;
+  void *res;
+
+  if (exec_base == 0)
+    exec_base = 0x400000;
+
+  pagesize = sysconf (_SC_PAGE_SIZE);
+  if (pagesize == -1)
+    perror_with_name ("sysconf");
+
+  addr = exec_base - size;
+
+  /* size should already be page-aligned, but this can't hurt.  */
+  addr &= ~(pagesize - 1);
+
+  /* Search for a free area.  If we hit 0, we're out of luck.  */
+  for (; addr; addr -= pagesize)
+    {
+      /* No MAP_FIXED - we don't want to zap someone's mapping.  */
+      res = mmap ((void *) addr, size,
+		  PROT_READ | PROT_WRITE | PROT_EXEC,
+		  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+      /* If we got what we wanted, return.  */
+      if ((uintptr_t) res == addr)
+	return res;
+
+      /* If we got a mapping, but at a wrong address, undo it.  */
+      if (res != MAP_FAILED)
+	munmap (res, size);
+    }
+
+  return NULL;
+}
+
 void
 initialize_low_tracepoint (void)
 {
diff --git a/gdb/gdbserver/linux-amd64-ipa.c b/gdb/gdbserver/linux-amd64-ipa.c
index 70889d2..c623dc2 100644
--- a/gdb/gdbserver/linux-amd64-ipa.c
+++ b/gdb/gdbserver/linux-amd64-ipa.c
@@ -19,6 +19,7 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
+#include <sys/mman.h>
 #include "tracepoint.h"
 #include "linux-x86-tdesc.h"
 
@@ -190,6 +191,23 @@ get_ipa_tdesc (int idx)
     }
 }
 
+/* Allocate buffer for the jump pads.  Since we're using 32-bit jumps
+   to reach them, and the executable is at low addresses, MAP_32BIT
+   works just fine.  Shared libraries, being allocated at the top,
+   are unfortunately out of luck.  */
+
+void *
+alloc_jump_pad_buffer (size_t size)
+{
+  void *res = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC,
+		    MAP_PRIVATE | MAP_ANONYMOUS | MAP_32BIT, -1, 0);
+
+  if (res == MAP_FAILED)
+    return NULL;
+
+  return res;
+}
+
 void
 initialize_low_tracepoint (void)
 {
diff --git a/gdb/gdbserver/linux-i386-ipa.c b/gdb/gdbserver/linux-i386-ipa.c
index 7159eee..45e5a0d 100644
--- a/gdb/gdbserver/linux-i386-ipa.c
+++ b/gdb/gdbserver/linux-i386-ipa.c
@@ -269,6 +269,21 @@ get_ipa_tdesc (int idx)
     }
 }
 
+/* Allocate buffer for the jump pads.  On i386, we can reach an arbitrary
+   address with a jump instruction, so just allocate normally.  */
+
+void *
+alloc_jump_pad_buffer (size_t size)
+{
+  void *res = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC,
+		    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+  if (res == MAP_FAILED)
+    return NULL;
+
+  return res;
+}
+
 void
 initialize_low_tracepoint (void)
 {
diff --git a/gdb/gdbserver/linux-s390-ipa.c b/gdb/gdbserver/linux-s390-ipa.c
index cd4fadd..a9f86ad 100644
--- a/gdb/gdbserver/linux-s390-ipa.c
+++ b/gdb/gdbserver/linux-s390-ipa.c
@@ -19,8 +19,12 @@
    along with this program.  If not, see <http://www.gnu.org/licenses/>.  */
 
 #include "server.h"
+#include <sys/mman.h>
 #include "tracepoint.h"
 #include "linux-s390-tdesc.h"
+#ifdef HAVE_GETAUXVAL
+#include <sys/auxv.h>
+#endif
 
 #define FT_FPR(x) (0x000 + (x) * 0x10)
 #define FT_VR(x) (0x000 + (x) * 0x10)
@@ -370,6 +374,61 @@ get_ipa_tdesc (int idx)
     }
 }
 
+/* Allocate buffer for the jump pads.  On 31-bit, JG reaches everywhere,
+   so just allocate normally.  On 64-bit, we have +/-4GiB of reach, and
+   the executable is usually mapped at 0x80000000 - aim for somewhere
+   below it.  */
+
+void *
+alloc_jump_pad_buffer (size_t size)
+{
+#ifdef __s390x__
+  uintptr_t addr;
+  uintptr_t exec_base = getauxval (AT_PHDR);
+  int pagesize;
+  void *res;
+
+  if (exec_base == 0)
+    exec_base = 0x80000000;
+
+  pagesize = sysconf (_SC_PAGE_SIZE);
+  if (pagesize == -1)
+    perror_with_name ("sysconf");
+
+  addr = exec_base - size;
+
+  /* size should already be page-aligned, but this can't hurt.  */
+  addr &= ~(pagesize - 1);
+
+  /* Search for a free area.  If we hit 0, we're out of luck.  */
+  for (; addr; addr -= pagesize)
+    {
+      /* No MAP_FIXED - we don't want to zap someone's mapping.  */
+      res = mmap ((void *) addr, size,
+		  PROT_READ | PROT_WRITE | PROT_EXEC,
+		  MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+      /* If we got what we wanted, return.  */
+      if ((uintptr_t) res == addr)
+	return res;
+
+      /* If we got a mapping, but at a wrong address, undo it.  */
+      if (res != MAP_FAILED)
+	munmap (res, size);
+    }
+
+  return NULL;
+#else
+  void *res = mmap (NULL, size, PROT_READ | PROT_WRITE | PROT_EXEC,
+		    MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);
+
+  if (res == MAP_FAILED)
+    return NULL;
+
+  return res;
+#endif
+}
+
 void
 initialize_low_tracepoint (void)
 {
diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index 83d1830..56b8e69 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -216,6 +216,34 @@ static struct ipa_sym_addresses ipa_sym_addrs;
 
 static int read_inferior_integer (CORE_ADDR symaddr, int *val);
 
+#if !defined HAVE_GETAUXVAL && defined IN_PROCESS_AGENT
+/* Retrieve the value of TYPE from the auxiliary vector.  If TYPE is not
+   found, 0 is returned.  This function is provided if glibc is too old.  */
+
+unsigned long
+getauxval (unsigned long type)
+{
+  unsigned long data[2];
+  FILE *f = fopen ("/proc/self/auxv", "r");
+  unsigned long value = 0;
+
+  if (f == NULL)
+    return 0;
+
+  while (fread (data, sizeof (data), 1, f) > 0)
+    {
+      if (data[0] == type)
+	{
+	  value = data[1];
+	  break;
+	}
+    }
+
+  fclose (f);
+  return value;
+}
+#endif
+
 /* Returns true if both the in-process agent library and the static
    tracepoints libraries are loaded in the inferior, and agent has
    capability on static tracepoints.  */
@@ -7400,35 +7428,22 @@ initialize_tracepoint (void)
 
 #ifdef IN_PROCESS_AGENT
   {
-    uintptr_t addr;
     int pagesize;
+    size_t jump_pad_size;
 
     pagesize = sysconf (_SC_PAGE_SIZE);
     if (pagesize == -1)
       perror_with_name ("sysconf");
 
-    gdb_tp_heap_buffer = (char *) xmalloc (5 * 1024 * 1024);
-
 #define SCRATCH_BUFFER_NPAGES 20
 
-    /* Allocate scratch buffer aligned on a page boundary, at a low
-       address (close to the main executable's code).  */
-    for (addr = pagesize; addr != 0; addr += pagesize)
-      {
-	gdb_jump_pad_buffer
-	  = (char *) mmap ((void *) addr,
-			   pagesize * SCRATCH_BUFFER_NPAGES,
-			   PROT_READ | PROT_WRITE | PROT_EXEC,
-			   MAP_PRIVATE | MAP_ANONYMOUS | MAP_FIXED,
-			   -1, 0);
-	if (gdb_jump_pad_buffer != MAP_FAILED)
-	  break;
-      }
+    jump_pad_size = pagesize * SCRATCH_BUFFER_NPAGES;
 
-    if (addr == 0)
+    gdb_tp_heap_buffer = (char *) xmalloc (5 * 1024 * 1024);
+    gdb_jump_pad_buffer = alloc_jump_pad_buffer (jump_pad_size);
+    if (gdb_jump_pad_buffer == NULL)
       perror_with_name ("mmap");
-
-    gdb_jump_pad_buffer_end = gdb_jump_pad_buffer + pagesize * SCRATCH_BUFFER_NPAGES;
+    gdb_jump_pad_buffer_end = gdb_jump_pad_buffer + jump_pad_size;
   }
 
   gdb_trampoline_buffer = gdb_trampoline_buffer_end = 0;
diff --git a/gdb/gdbserver/tracepoint.h b/gdb/gdbserver/tracepoint.h
index df815ef..679a32a 100644
--- a/gdb/gdbserver/tracepoint.h
+++ b/gdb/gdbserver/tracepoint.h
@@ -132,6 +132,10 @@ void supply_static_tracepoint_registers (struct regcache *regcache,
 					 CORE_ADDR pc);
 void set_trampoline_buffer_space (CORE_ADDR begin, CORE_ADDR end,
 				  char *errmsg);
+void *alloc_jump_pad_buffer (size_t size);
+#ifndef HAVE_GETAUXVAL
+unsigned long getauxval (unsigned long type);
+#endif
 #else
 void stop_tracing (void);
 
-- 
2.7.4

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

* Re: [PATCH v2 3/4] gdbserver: Add powerpc fast tracepoint support.
  2016-03-30 15:35                     ` Ulrich Weigand
@ 2016-03-31  1:31                       ` Marcin Kościelnicki
  2016-03-31 11:39                         ` Ulrich Weigand
  0 siblings, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-31  1:31 UTC (permalink / raw)
  To: Ulrich Weigand, Simon Marchi; +Cc: gdb-patches

On 30/03/16 17:35, Ulrich Weigand wrote:
> Simon Marchi wrote:
>
>> Ahh, it seems like the ordering is important here.  If I include it before
>> <elf.h> (and everything that includes <elf.h>), it works.
>
> Hmm, it would probably be best to avoid mixing in-tree BFD headers and
> system headers this way.  I'd suggest to *not* include <elf.h> at all,
> but instead use:
>
> #include "elf/common.h"
> #include "elf/ppc64.h"
>
> Bye,
> Ulrich
>

That doesn't work either:

../../../gdb/gdbserver/linux-ppc-low.c: In function ‘is_elfv2_inferior’:
../../../gdb/gdbserver/linux-ppc-low.c:763:3: error: unknown type name 
‘Elf64_Ehdr’
    Elf64_Ehdr ehdr;
    ^
../../../gdb/gdbserver/linux-ppc-low.c:772:18: error: request for member 
‘e_ident’ in something not a structure or union
    if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG))
                   ^
../../../gdb/gdbserver/linux-ppc-low.c:772:28: error: ‘ELFMAG’ 
undeclared (first use in this function)
    if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG))
                             ^
../../../gdb/gdbserver/linux-ppc-low.c:772:28: note: each undeclared 
identifier is reported only once for each function it appears in
../../../gdb/gdbserver/linux-ppc-low.c:772:36: error: ‘SELFMAG’ 
undeclared (first use in this function)
    if (memcmp(ehdr.e_ident, ELFMAG, SELFMAG))
                                     ^
../../../gdb/gdbserver/linux-ppc-low.c:775:15: error: request for member 
‘e_flags’ in something not a structure or union
    return (ehdr.e_flags & EF_PPC64_ABI) == 2;
                ^
../../../gdb/gdbserver/linux-ppc-low.c:776:1: error: control reaches end 
of non-void function [-Werror=return-type]
  }
  ^

There's no equivalent to ELFMAG in the BFD headers, and getting to 
e_flags requires more work too (you need elf/external.h and manually 
assemble the word from bytes).  Perhaps it'd be simpler to just define 
EF_PPC64_ABI manually if it's not defined?

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

* Re: [PATCH 2/4 v2] IPA: Add alloc_jump_pad_buffer target hook.
  2016-03-30 14:58             ` Ulrich Weigand
@ 2016-03-31  7:34               ` Yao Qi
  2016-03-31 11:37                 ` Ulrich Weigand
  0 siblings, 1 reply; 56+ messages in thread
From: Yao Qi @ 2016-03-31  7:34 UTC (permalink / raw)
  To: Ulrich Weigand
  Cc: Yao Qi, Marcin Kościelnicki, gdb-patches, pierre.langlois

"Ulrich Weigand" <uweigand@de.ibm.com> writes:

> Many thanks!  Just testing the single patch should be OK.

This patch is tested on aarch64-linux.  No regressions.

-- 
Yao (齐尧)

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

* Re: [PATCH 2/4 v2] IPA: Add alloc_jump_pad_buffer target hook.
  2016-03-31  7:34               ` Yao Qi
@ 2016-03-31 11:37                 ` Ulrich Weigand
  0 siblings, 0 replies; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-31 11:37 UTC (permalink / raw)
  To: Yao Qi; +Cc: Yao Qi, Marcin Kościelnicki, gdb-patches, pierre.langlois

Yao Qi wrote:
> "Ulrich Weigand" <uweigand@de.ibm.com> writes:
> 
> > Many thanks!  Just testing the single patch should be OK.
> 
> This patch is tested on aarch64-linux.  No regressions.

Excellent!

Thanks again,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH 2/4 v3] IPA: Add alloc_jump_pad_buffer target hook.
  2016-03-31  1:16       ` [PATCH 2/4 v3] " Marcin Kościelnicki
@ 2016-03-31 11:38         ` Ulrich Weigand
  2016-03-31 13:42           ` Marcin Kościelnicki
  2016-04-01 14:43         ` Ulrich Weigand
  1 sibling, 1 reply; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-31 11:38 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: gdb-patches, Marcin Kościelnicki


> gdb/gdbserver/ChangeLog:
> 
> 	* linux-aarch64-ipa.c: Add <sys/mman.h> and <sys/auxv.h> includes.
> 	(alloc_jump_pad_buffer): New function.
> 	* linux-amd64-ipa.c: Add <sys/mman.h> include.
> 	(alloc_jump_pad_buffer): New function.
> 	* linux-i386-ipa.c (alloc_jump_pad_buffer): New function.
> 	* linux-s390-ipa.c: Add <sys/mman.h> and <sys/auxv.h> includes.
> 	(alloc_jump_pad_buffer): New function.
> 	* tracepoint.c (getauxval) [!HAVE_GETAUXVAL]: New function.
> 	(initialize_tracepoint): Delegate to alloc_jump_pad_buffer.
> 	* tracepoint.h (alloc_jump_pad_buffer): New prototype.
> 	(getauxval) [!HAVE_GETAUXVAL]: New prototype.

This is OK.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH v2 3/4] gdbserver: Add powerpc fast tracepoint support.
  2016-03-31  1:31                       ` Marcin Kościelnicki
@ 2016-03-31 11:39                         ` Ulrich Weigand
  2016-03-31 13:45                           ` Marcin Kościelnicki
  0 siblings, 1 reply; 56+ messages in thread
From: Ulrich Weigand @ 2016-03-31 11:39 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: Simon Marchi, gdb-patches

> There's no equivalent to ELFMAG in the BFD headers, and getting to 
> e_flags requires more work too (you need elf/external.h and manually 
> assemble the word from bytes).

Huh, that's indeed annoying.

> Perhaps it'd be simpler to just define 
> EF_PPC64_ABI manually if it's not defined?

This is fine with me too.

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH 2/4 v3] IPA: Add alloc_jump_pad_buffer target hook.
  2016-03-31 11:38         ` Ulrich Weigand
@ 2016-03-31 13:42           ` Marcin Kościelnicki
  0 siblings, 0 replies; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-31 13:42 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches

On 31/03/16 13:38, Ulrich Weigand wrote:
>
>> gdb/gdbserver/ChangeLog:
>>
>> 	* linux-aarch64-ipa.c: Add <sys/mman.h> and <sys/auxv.h> includes.
>> 	(alloc_jump_pad_buffer): New function.
>> 	* linux-amd64-ipa.c: Add <sys/mman.h> include.
>> 	(alloc_jump_pad_buffer): New function.
>> 	* linux-i386-ipa.c (alloc_jump_pad_buffer): New function.
>> 	* linux-s390-ipa.c: Add <sys/mman.h> and <sys/auxv.h> includes.
>> 	(alloc_jump_pad_buffer): New function.
>> 	* tracepoint.c (getauxval) [!HAVE_GETAUXVAL]: New function.
>> 	(initialize_tracepoint): Delegate to alloc_jump_pad_buffer.
>> 	* tracepoint.h (alloc_jump_pad_buffer): New prototype.
>> 	(getauxval) [!HAVE_GETAUXVAL]: New prototype.
>
> This is OK.
>
> Thanks,
> Ulrich
>

Thanks, pushed.

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

* Re: [PATCH v2 4/4] gdbserver: Add emit_ops for powerpc.
  2016-03-29 18:25       ` Ulrich Weigand
@ 2016-03-31 13:45         ` Marcin Kościelnicki
  0 siblings, 0 replies; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-31 13:45 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches

On 29/03/16 20:25, Ulrich Weigand wrote:
>> gdb/gdbserver/ChangeLog:
>>
>> 2016-03-14  Wei-cheng Wang  <cole945@gmail.com>
>> 	    Marcin Kościelnicki  <koriakin@0x04.net>
>>
>> 	* linux-ppc-low.c (emit_insns): New function.
>> 	(__EMIT_ASM, _EMIT_ASM, EMIT_ASM): New macros.
>> 	(ppc_emit_prologue): New function.
>> 	(ppc_emit_epilogue): New function.
>> 	(ppc_emit_add): New function.
>> 	(ppc_emit_sub): New function.
>> 	(ppc_emit_mul): New function.
>> 	(ppc_emit_lsh): New function.
>> 	(ppc_emit_rsh_signed): New function.
>> 	(ppc_emit_rsh_unsigned): New function.
>> 	(ppc_emit_ext): New function.
>> 	(ppc_emit_zero_ext): New function.
>> 	(ppc_emit_log_not): New function.
>> 	(ppc_emit_bit_and): New function.
>> 	(ppc_emit_bit_or): New function.
>> 	(ppc_emit_bit_xor): New function.
>> 	(ppc_emit_bit_not): New function.
>> 	(ppc_emit_equal): New function.
>> 	(ppc_emit_less_signed): New function.
>> 	(ppc_emit_less_unsigned): New function.
>> 	(ppc_emit_ref): New function.
>> 	(ppc_emit_const): New function.
>> 	(ppc_emit_reg): New function.
>> 	(ppc_emit_pop): New function.
>> 	(ppc_emit_stack_flush): New function.
>> 	(ppc_emit_swap): New function.
>> 	(ppc_emit_stack_adjust): New function.
>> 	(ppc_emit_call): New function.
>> 	(ppc_emit_int_call_1): New function.
>> 	(ppc_emit_void_call_2): New function.
>> 	(ppc_emit_if_goto): New function.
>> 	(ppc_emit_goto): New function.
>> 	(ppc_emit_eq_goto): New function.
>> 	(ppc_emit_ne_goto): New function.
>> 	(ppc_emit_lt_goto): New function.
>> 	(ppc_emit_le_goto): New function.
>> 	(ppc_emit_gt_goto): New function.
>> 	(ppc_emit_ge_goto): New function.
>> 	(ppc_write_goto_address): New function.
>> 	(ppc_emit_ops_impl): New static variable.
>> 	(ppc64v1_emit_prologue): New function.
>> 	(ppc64v2_emit_prologue): New function.
>> 	(ppc64_emit_epilogue): New function.
>> 	(ppc64_emit_add): New function.
>> 	(ppc64_emit_sub): New function.
>> 	(ppc64_emit_mul): New function.
>> 	(ppc64_emit_lsh): New function.
>> 	(ppc64_emit_rsh_signed): New function.
>> 	(ppc64_emit_rsh_unsigned): New function.
>> 	(ppc64_emit_ext): New function.
>> 	(ppc64_emit_zero_ext): New function.
>> 	(ppc64_emit_log_not): New function.
>> 	(ppc64_emit_bit_and): New function.
>> 	(ppc64_emit_bit_or): New function.
>> 	(ppc64_emit_bit_xor): New function.
>> 	(ppc64_emit_bit_not): New function.
>> 	(ppc64_emit_equal): New function.
>> 	(ppc64_emit_less_signed): New function.
>> 	(ppc64_emit_less_unsigned): New function.
>> 	(ppc64_emit_ref): New function.
>> 	(ppc64_emit_const): New function.
>> 	(ppc64v1_emit_reg): New function.
>> 	(ppc64v2_emit_reg): New function.
>> 	(ppc64_emit_pop): New function.
>> 	(ppc64_emit_stack_flush): New function.
>> 	(ppc64_emit_swap): New function.
>> 	(ppc64v1_emit_call): New function.
>> 	(ppc64v2_emit_call): New function.
>> 	(ppc64v1_emit_int_call_1): New function.
>> 	(ppc64v2_emit_int_call_1): New function.
>> 	(ppc64v1_emit_void_call_2): New function.
>> 	(ppc64v2_emit_void_call_2): New function.
>> 	(ppc64_emit_if_goto): New function.
>> 	(ppc64_emit_eq_goto): New function.
>> 	(ppc64_emit_ne_goto): New function.
>> 	(ppc64_emit_lt_goto): New function.
>> 	(ppc64_emit_le_goto): New function.
>> 	(ppc64_emit_gt_goto): New function.
>> 	(ppc64_emit_ge_goto): New function.
>> 	(ppc64v1_emit_ops_impl): New static variable.
>> 	(ppc64v2_emit_ops_impl): New static variable.
>> 	(ppc_emit_ops): New function.
>> 	(linux_low_target): Wire in ppc_emit_ops.
>> ---
>> The only change in this version is that is_elfv2_inferior is used instead of
>> assuming same ABI as gdbserver.
>
> Still OK once the rest is in.
>
> Thanks,
> Ulrich
>

Thanks, pushed.

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

* Re: [PATCH v2 3/4] gdbserver: Add powerpc fast tracepoint support.
  2016-03-31 11:39                         ` Ulrich Weigand
@ 2016-03-31 13:45                           ` Marcin Kościelnicki
  0 siblings, 0 replies; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-31 13:45 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: Simon Marchi, gdb-patches

On 31/03/16 13:39, Ulrich Weigand wrote:
>> There's no equivalent to ELFMAG in the BFD headers, and getting to
>> e_flags requires more work too (you need elf/external.h and manually
>> assemble the word from bytes).
>
> Huh, that's indeed annoying.
>
>> Perhaps it'd be simpler to just define
>> EF_PPC64_ABI manually if it's not defined?
>
> This is fine with me too.
>
> Bye,
> Ulrich
>

Thanks, I pushed the patch with this fragment added before 
is_elfv2_inferior:

+/* Older glibc doesn't provide this.  */
+
+#ifndef EF_PPC64_ABI
+#define EF_PPC64_ABI 3
+#endif

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

* Re: [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers.
  2016-03-30 22:02                 ` Marcin Kościelnicki
@ 2016-03-31 18:22                   ` Sergio Durigan Junior
  2016-03-31 21:42                     ` [PATCH obv] gdbserver: Fix C++ build errors in tracepoint.c Marcin Kościelnicki
  0 siblings, 1 reply; 56+ messages in thread
From: Sergio Durigan Junior @ 2016-03-31 18:22 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: Ulrich Weigand, gdb-patches

On Wednesday, March 30 2016, Marcin Kościelnicki wrote:

> On 30/03/16 13:32, Ulrich Weigand wrote:
>> Marcin Kościelnicki wrote:
>>> On 29/03/16 20:08, Ulrich Weigand wrote:
>>>> Marcin Kościelnicki wrote:
>>>>> On 14/03/16 18:49, Ulrich Weigand wrote:
>>>>>> The more I think about it, the more I tend to agree that your
>>>>>> proposal is actually the best solution.  I'd still like to give
>>>>>> it a couple of days to give others a chance to comment as well ...
>>>>>
>>>>> Alright, so what should we do about this issue?
>>>>
>>>> Since nobody came up with a better idea, and since your patch doesn't
>>>> actually preclude anybody from implementing any better idea they might
>>>> come up later (since it doesn't actually change anything in the
>>>> gdbserver protocol), I'd say we just go with your patch for now.
>>>
>>> Very well, then.  For this to be actually useful for powerpc64, I'll
>>> also need an ack on the other patch
>>> (https://sourceware.org/ml/gdb-patches/2016-03/msg00201.html).
>>
>> This looks to be resolved now.
>>
>>>> However, there does seem to be one issue: your patch changes the
>>>> interface between gdbserver and the in-process agent in an incompatible
>>>> way.  Binaries with an old IPA built in will no longer work with a
>>>> new gdbserver, since it will will expect exported symbols like
>>>> gdb_collect_ptr, which the old binary doesn't export.
>>>>
>>>> I think it would be preferable to implement a backward-compatible
>>>> way where gdbserver checks for the new symbol, and if it isn't
>>>> present, falls back to the old symbol.
>>>
>>> Alright, I can do that, though I seem to recall we don't care about
>>> gdbserver/IPA interface compatibility (and IPA is always built as
>>> shared, so there's no concern about an executable with old version built
>>> in).
>>
>> And this turns out to be not necessary after all, see the recent
>> mail by Pedro.  Sorry for the confusion.
>>
>> I think the patch should be OK now.
>
> Thanks.  I've resolved a trivial interaction with the s390 changes
> pushed in the meantime (linux-s390-ipa.c needs an identical fix to the
> others) and pushed it.

Hi Marcin,

Your patch broke the C++ build:

  <http://gdb-build.sergiodj.net/builders/Fedora-x86_64-cxx-build-m64/builds/2220>

Thanks,

-- 
Sergio
GPG key ID: 237A 54B1 0287 28BF 00EF  31F4 D0EB 7628 65FC 5E36
Please send encrypted e-mail if possible
http://sergiodj.net/

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

* [PATCH obv] gdbserver: Fix C++ build errors in tracepoint.c
  2016-03-31 18:22                   ` Sergio Durigan Junior
@ 2016-03-31 21:42                     ` Marcin Kościelnicki
  0 siblings, 0 replies; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-03-31 21:42 UTC (permalink / raw)
  To: sergiodj; +Cc: gdb-patches, uweigand, Marcin Kościelnicki

These were introduced by 1cda1512689aabb36588a01370002632a0c8e560
and a13c46966d308297a1273e35ccc807a3912d573d .  One is a simple
missing cast, the other is const usage on global function pointers
exported from IPA: in C++, consts are static, and thus won't be
exported from the DSO (the build error was because of non-applicable
visibility("default")).

gdb/gdbserver/ChangeLog:

	* tracepoint.c (gdb_collect_ptr): Remove const qualifier.
	(get_raw_reg_ptr): Likewise.
	(get_trace_state_variable_value_ptr): Likewise.
	(set_trace_state_variable_value_ptr): Likewise.
	(initialize_tracepoint): Cast alloc_jump_pad_buffer result to
	char *.
---
Thanks for noticing that.  Here's the fix, pushed as obvious.

 gdb/gdbserver/tracepoint.c | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index 56b8e69..8f71325 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -5903,11 +5903,11 @@ typedef LONGEST (*get_trace_state_variable_value_ptr_type) (int);
 typedef void (*set_trace_state_variable_value_ptr_type) (int, LONGEST);
 
 EXTERN_C_PUSH
-IP_AGENT_EXPORT_VAR const gdb_collect_ptr_type gdb_collect_ptr = gdb_collect;
-IP_AGENT_EXPORT_VAR const get_raw_reg_ptr_type get_raw_reg_ptr = get_raw_reg;
-IP_AGENT_EXPORT_VAR const get_trace_state_variable_value_ptr_type
+IP_AGENT_EXPORT_VAR gdb_collect_ptr_type gdb_collect_ptr = gdb_collect;
+IP_AGENT_EXPORT_VAR get_raw_reg_ptr_type get_raw_reg_ptr = get_raw_reg;
+IP_AGENT_EXPORT_VAR get_trace_state_variable_value_ptr_type
   get_trace_state_variable_value_ptr = get_trace_state_variable_value;
-IP_AGENT_EXPORT_VAR const set_trace_state_variable_value_ptr_type
+IP_AGENT_EXPORT_VAR set_trace_state_variable_value_ptr_type
   set_trace_state_variable_value_ptr = set_trace_state_variable_value;
 EXTERN_C_POP
 
@@ -7440,7 +7440,7 @@ initialize_tracepoint (void)
     jump_pad_size = pagesize * SCRATCH_BUFFER_NPAGES;
 
     gdb_tp_heap_buffer = (char *) xmalloc (5 * 1024 * 1024);
-    gdb_jump_pad_buffer = alloc_jump_pad_buffer (jump_pad_size);
+    gdb_jump_pad_buffer = (char *) alloc_jump_pad_buffer (jump_pad_size);
     if (gdb_jump_pad_buffer == NULL)
       perror_with_name ("mmap");
     gdb_jump_pad_buffer_end = gdb_jump_pad_buffer + jump_pad_size;
-- 
2.7.4

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

* Re: [PATCH 2/4 v3] IPA: Add alloc_jump_pad_buffer target hook.
  2016-03-31  1:16       ` [PATCH 2/4 v3] " Marcin Kościelnicki
  2016-03-31 11:38         ` Ulrich Weigand
@ 2016-04-01 14:43         ` Ulrich Weigand
  2016-04-03 12:31           ` [PATCH] IPA: Fix build problem on !HAVE_GETAUXVAL Marcin Kościelnicki
  1 sibling, 1 reply; 56+ messages in thread
From: Ulrich Weigand @ 2016-04-01 14:43 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: gdb-patches, Marcin Kościelnicki


> 	* linux-aarch64-ipa.c: Add <sys/mman.h> and <sys/auxv.h> includes.
> 	(alloc_jump_pad_buffer): New function.
> 	* linux-amd64-ipa.c: Add <sys/mman.h> include.
> 	(alloc_jump_pad_buffer): New function.
> 	* linux-i386-ipa.c (alloc_jump_pad_buffer): New function.
> 	* linux-s390-ipa.c: Add <sys/mman.h> and <sys/auxv.h> includes.
> 	(alloc_jump_pad_buffer): New function.
> 	* tracepoint.c (getauxval) [!HAVE_GETAUXVAL]: New function.
> 	(initialize_tracepoint): Delegate to alloc_jump_pad_buffer.
> 	* tracepoint.h (alloc_jump_pad_buffer): New prototype.
> 	(getauxval) [!HAVE_GETAUXVAL]: New prototype.

This caused a build failure on my RHEL5 Cell daily build, due to
gdb/gdbserver/linux-ppc-ipa.c: In function 'alloc_jump_pad_buffer':
gdb/gdbserver/linux-ppc-ipa.c:120: error: 'AT_PHDR' undeclared (first use in this function)

The problem seems to be that this system is so old it doesn't have
a <sys/auvx.h> header.  You do provide a fallback getauxval implementation
for those systems, but the AT_PHDR value isn't available.  It is actually
defined in my system headers, in <elf.h>, but this isn't pulled in ---
usually it would be implicitly included from <sys/auxv.h>.

It might be best to add an explicit #include <elf.h> to all files that
make use of AT_... constants, in case HAVE_GETAUXVAL is false.

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* [PATCH] IPA: Fix build problem on !HAVE_GETAUXVAL
  2016-04-01 14:43         ` Ulrich Weigand
@ 2016-04-03 12:31           ` Marcin Kościelnicki
  2016-04-03 16:26             ` Ulrich Weigand
  0 siblings, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-04-03 12:31 UTC (permalink / raw)
  To: uweigand; +Cc: gdb-patches, Marcin Kościelnicki

These files need AT_PHDR, which is defined in elf.h.  If HAVE_GETAUXVAL
is set, it's implicitely included by sys/auxv.h.  Include it manually
for the opposite case.

gdb/gdbserver/ChangeLog:

	* linux-aarch64-ipa.c: Add <elf.h> include.
	* linux-ppc-ipa.c: Add <elf.h> include.
	* linux-s390-ipa.c: Add <elf.h> include.
---
Here's a fix.  Does that sound right?

 gdb/gdbserver/linux-aarch64-ipa.c | 1 +
 gdb/gdbserver/linux-ppc-ipa.c     | 1 +
 gdb/gdbserver/linux-s390-ipa.c    | 1 +
 3 files changed, 3 insertions(+)

diff --git a/gdb/gdbserver/linux-aarch64-ipa.c b/gdb/gdbserver/linux-aarch64-ipa.c
index 50caeae..601d61c 100644
--- a/gdb/gdbserver/linux-aarch64-ipa.c
+++ b/gdb/gdbserver/linux-aarch64-ipa.c
@@ -21,6 +21,7 @@
 #include "server.h"
 #include <sys/mman.h>
 #include "tracepoint.h"
+#include <elf.h>
 #ifdef HAVE_GETAUXVAL
 #include <sys/auxv.h>
 #endif
diff --git a/gdb/gdbserver/linux-ppc-ipa.c b/gdb/gdbserver/linux-ppc-ipa.c
index 8489c6e..d8f118e 100644
--- a/gdb/gdbserver/linux-ppc-ipa.c
+++ b/gdb/gdbserver/linux-ppc-ipa.c
@@ -22,6 +22,7 @@
 #include <sys/mman.h>
 #include "tracepoint.h"
 #include "linux-ppc-tdesc.h"
+#include <elf.h>
 #ifdef HAVE_GETAUXVAL
 #include <sys/auxv.h>
 #endif
diff --git a/gdb/gdbserver/linux-s390-ipa.c b/gdb/gdbserver/linux-s390-ipa.c
index a9f86ad..cdf2fe7 100644
--- a/gdb/gdbserver/linux-s390-ipa.c
+++ b/gdb/gdbserver/linux-s390-ipa.c
@@ -22,6 +22,7 @@
 #include <sys/mman.h>
 #include "tracepoint.h"
 #include "linux-s390-tdesc.h"
+#include <elf.h>
 #ifdef HAVE_GETAUXVAL
 #include <sys/auxv.h>
 #endif
-- 
2.8.0

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

* Re: [PATCH] IPA: Fix build problem on !HAVE_GETAUXVAL
  2016-04-03 12:31           ` [PATCH] IPA: Fix build problem on !HAVE_GETAUXVAL Marcin Kościelnicki
@ 2016-04-03 16:26             ` Ulrich Weigand
  2016-04-03 16:28               ` Marcin Kościelnicki
  0 siblings, 1 reply; 56+ messages in thread
From: Ulrich Weigand @ 2016-04-03 16:26 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: gdb-patches, Marcin Kościelnicki

> These files need AT_PHDR, which is defined in elf.h.  If HAVE_GETAUXVAL
> is set, it's implicitely included by sys/auxv.h.  Include it manually
> for the opposite case.
> 
> gdb/gdbserver/ChangeLog:
> 
> 	* linux-aarch64-ipa.c: Add <elf.h> include.
> 	* linux-ppc-ipa.c: Add <elf.h> include.
> 	* linux-s390-ipa.c: Add <elf.h> include.
> ---
> Here's a fix.  Does that sound right?

This is OK.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH] IPA: Fix build problem on !HAVE_GETAUXVAL
  2016-04-03 16:26             ` Ulrich Weigand
@ 2016-04-03 16:28               ` Marcin Kościelnicki
  2016-04-04 14:41                 ` Ulrich Weigand
  0 siblings, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-04-03 16:28 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches

On 03/04/16 18:20, Ulrich Weigand wrote:
>> These files need AT_PHDR, which is defined in elf.h.  If HAVE_GETAUXVAL
>> is set, it's implicitely included by sys/auxv.h.  Include it manually
>> for the opposite case.
>>
>> gdb/gdbserver/ChangeLog:
>>
>> 	* linux-aarch64-ipa.c: Add <elf.h> include.
>> 	* linux-ppc-ipa.c: Add <elf.h> include.
>> 	* linux-s390-ipa.c: Add <elf.h> include.
>> ---
>> Here's a fix.  Does that sound right?
>
> This is OK.
>
> Thanks,
> Ulrich
>

Thanks, pushed.

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

* Re: [PATCH] IPA: Fix build problem on !HAVE_GETAUXVAL
  2016-04-03 16:28               ` Marcin Kościelnicki
@ 2016-04-04 14:41                 ` Ulrich Weigand
  2016-04-05 13:33                   ` [PATCH] IPA: Move getauxval out of #ifndef IN_PROCESS_AGENT Marcin Kościelnicki
  0 siblings, 1 reply; 56+ messages in thread
From: Ulrich Weigand @ 2016-04-04 14:41 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: gdb-patches

> On 03/04/16 18:20, Ulrich Weigand wrote:
> >> These files need AT_PHDR, which is defined in elf.h.  If HAVE_GETAUXVAL
> >> is set, it's implicitely included by sys/auxv.h.  Include it manually
> >> for the opposite case.
> >>
> >> gdb/gdbserver/ChangeLog:
> >>
> >> 	* linux-aarch64-ipa.c: Add <elf.h> include.
> >> 	* linux-ppc-ipa.c: Add <elf.h> include.
> >> 	* linux-s390-ipa.c: Add <elf.h> include.
> >> ---
> >> Here's a fix.  Does that sound right?
> >
> > This is OK.
> >
> > Thanks,
> > Ulrich
> >
> 
> Thanks, pushed.

Hmm, it turns out build still fails for me, this time in the link step:

linux-ppc-ipa.o: In function `alloc_jump_pad_buffer':
gdb/gdbserver/linux-ppc-ipa.c:121: undefined reference to `getauxval'

Looking at tracepoint.c, I notice that the definition of getauxval

#if !defined HAVE_GETAUXVAL && defined IN_PROCESS_AGENT
/* Retrieve the value of TYPE from the auxiliary vector.  If TYPE is not
   found, 0 is returned.  This function is provided if glibc is too old.  */

unsigned long
getauxval (unsigned long type)

is itself within a

#ifndef IN_PROCESS_AGENT

block, and so never has any effect ...

Bye,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* [PATCH] IPA: Move getauxval out of #ifndef IN_PROCESS_AGENT
  2016-04-04 14:41                 ` Ulrich Weigand
@ 2016-04-05 13:33                   ` Marcin Kościelnicki
  2016-04-05 15:04                     ` Ulrich Weigand
  0 siblings, 1 reply; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-04-05 13:33 UTC (permalink / raw)
  To: uweigand; +Cc: gdb-patches, Marcin Kościelnicki

The getauxval code was wrongly included in code area only compiled for
gdbserver.  Move it to a #ifdef IN_PROCESS_AGENT area that already
contains lots of IPA-only code.

gdb/gdbserver/ChangeLog:

	* tracepoint.c (getauxval): Move to #ifdef IN_PROCESS_AGENT.
---
Ugh.  I don't have a machine with sufficiently old glibc, so I tested
my patch by manually removing HAVE_GETAUXVAL from config.h.  Little
did I know that it was always regenerated by the build process from
config.status.

Here's a fix, this time tested with HAVE_GETAUXVAL actually undefined
on s390x.

 gdb/gdbserver/tracepoint.c | 56 +++++++++++++++++++++++-----------------------
 1 file changed, 28 insertions(+), 28 deletions(-)

diff --git a/gdb/gdbserver/tracepoint.c b/gdb/gdbserver/tracepoint.c
index 8f71325..620b94f 100644
--- a/gdb/gdbserver/tracepoint.c
+++ b/gdb/gdbserver/tracepoint.c
@@ -216,34 +216,6 @@ static struct ipa_sym_addresses ipa_sym_addrs;
 
 static int read_inferior_integer (CORE_ADDR symaddr, int *val);
 
-#if !defined HAVE_GETAUXVAL && defined IN_PROCESS_AGENT
-/* Retrieve the value of TYPE from the auxiliary vector.  If TYPE is not
-   found, 0 is returned.  This function is provided if glibc is too old.  */
-
-unsigned long
-getauxval (unsigned long type)
-{
-  unsigned long data[2];
-  FILE *f = fopen ("/proc/self/auxv", "r");
-  unsigned long value = 0;
-
-  if (f == NULL)
-    return 0;
-
-  while (fread (data, sizeof (data), 1, f) > 0)
-    {
-      if (data[0] == type)
-	{
-	  value = data[1];
-	  break;
-	}
-    }
-
-  fclose (f);
-  return value;
-}
-#endif
-
 /* Returns true if both the in-process agent library and the static
    tracepoints libraries are loaded in the inferior, and agent has
    capability on static tracepoints.  */
@@ -7395,6 +7367,34 @@ initialize_tracepoint_ftlib (void)
   gdb_agent_init ();
 }
 
+#ifndef HAVE_GETAUXVAL
+/* Retrieve the value of TYPE from the auxiliary vector.  If TYPE is not
+   found, 0 is returned.  This function is provided if glibc is too old.  */
+
+unsigned long
+getauxval (unsigned long type)
+{
+  unsigned long data[2];
+  FILE *f = fopen ("/proc/self/auxv", "r");
+  unsigned long value = 0;
+
+  if (f == NULL)
+    return 0;
+
+  while (fread (data, sizeof (data), 1, f) > 0)
+    {
+      if (data[0] == type)
+	{
+	  value = data[1];
+	  break;
+	}
+    }
+
+  fclose (f);
+  return value;
+}
+#endif
+
 #endif /* IN_PROCESS_AGENT */
 
 /* Return a timestamp, expressed as microseconds of the usual Unix
-- 
2.8.0

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

* Re: [PATCH] IPA: Move getauxval out of #ifndef IN_PROCESS_AGENT
  2016-04-05 13:33                   ` [PATCH] IPA: Move getauxval out of #ifndef IN_PROCESS_AGENT Marcin Kościelnicki
@ 2016-04-05 15:04                     ` Ulrich Weigand
  2016-04-05 16:55                       ` Marcin Kościelnicki
  0 siblings, 1 reply; 56+ messages in thread
From: Ulrich Weigand @ 2016-04-05 15:04 UTC (permalink / raw)
  To: Marcin Kościelnicki; +Cc: gdb-patches, Marcin Kościelnicki

> gdb/gdbserver/ChangeLog:
> 
> 	* tracepoint.c (getauxval): Move to #ifdef IN_PROCESS_AGENT.

This is OK.

Thanks,
Ulrich

-- 
  Dr. Ulrich Weigand
  GNU/Linux compilers and toolchain
  Ulrich.Weigand@de.ibm.com

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

* Re: [PATCH] IPA: Move getauxval out of #ifndef IN_PROCESS_AGENT
  2016-04-05 15:04                     ` Ulrich Weigand
@ 2016-04-05 16:55                       ` Marcin Kościelnicki
  0 siblings, 0 replies; 56+ messages in thread
From: Marcin Kościelnicki @ 2016-04-05 16:55 UTC (permalink / raw)
  To: Ulrich Weigand; +Cc: gdb-patches

On 05/04/16 17:03, Ulrich Weigand wrote:
>> gdb/gdbserver/ChangeLog:
>>
>> 	* tracepoint.c (getauxval): Move to #ifdef IN_PROCESS_AGENT.
>
> This is OK.
>
> Thanks,
> Ulrich
>

Thanks, pushed.

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

end of thread, other threads:[~2016-04-05 16:55 UTC | newest]

Thread overview: 56+ messages (download: mbox.gz / follow: Atom feed)
-- links below jump to the message on this page --
2016-03-13  2:31 [PATCH 0/3] gdbserver: Add powerpc fast tracepoint support Marcin Kościelnicki
2016-03-13  2:32 ` [PATCH 3/3] " Marcin Kościelnicki
2016-03-14 22:10   ` [PATCH 3/4 v2] " Marcin Kościelnicki
2016-03-16 16:58     ` Ulrich Weigand
2016-03-16 17:55       ` Marcin Kościelnicki
2016-03-17  6:30         ` Ulrich Weigand
2016-03-18 15:09           ` [PATCH v2 3/4] " Marcin Kościelnicki
2016-03-29 18:23             ` Ulrich Weigand
2016-03-30 14:52             ` Simon Marchi
2016-03-30 14:57               ` Ulrich Weigand
2016-03-30 15:24                 ` Simon Marchi
2016-03-30 15:28                   ` Simon Marchi
2016-03-30 15:35                     ` Ulrich Weigand
2016-03-31  1:31                       ` Marcin Kościelnicki
2016-03-31 11:39                         ` Ulrich Weigand
2016-03-31 13:45                           ` Marcin Kościelnicki
2016-03-13  2:32 ` [PATCH 2/3] IPA: Add alloc_jump_pad_buffer target hook Marcin Kościelnicki
2016-03-18 15:08   ` [PATCH 2/4 v2] " Marcin Kościelnicki
2016-03-29 18:18     ` Ulrich Weigand
2016-03-29 22:04       ` Marcin Kościelnicki
2016-03-30 11:38         ` Ulrich Weigand
2016-03-30 14:50           ` Yao Qi
2016-03-30 14:58             ` Ulrich Weigand
2016-03-31  7:34               ` Yao Qi
2016-03-31 11:37                 ` Ulrich Weigand
2016-03-31  1:16       ` [PATCH 2/4 v3] " Marcin Kościelnicki
2016-03-31 11:38         ` Ulrich Weigand
2016-03-31 13:42           ` Marcin Kościelnicki
2016-04-01 14:43         ` Ulrich Weigand
2016-04-03 12:31           ` [PATCH] IPA: Fix build problem on !HAVE_GETAUXVAL Marcin Kościelnicki
2016-04-03 16:26             ` Ulrich Weigand
2016-04-03 16:28               ` Marcin Kościelnicki
2016-04-04 14:41                 ` Ulrich Weigand
2016-04-05 13:33                   ` [PATCH] IPA: Move getauxval out of #ifndef IN_PROCESS_AGENT Marcin Kościelnicki
2016-04-05 15:04                     ` Ulrich Weigand
2016-04-05 16:55                       ` Marcin Kościelnicki
2016-03-13  2:32 ` [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers Marcin Kościelnicki
2016-03-14 14:41   ` Ulrich Weigand
2016-03-14 14:53     ` Marcin Kościelnicki
2016-03-14 17:49       ` Ulrich Weigand
2016-03-22  9:19         ` Marcin Kościelnicki
2016-03-29 18:08           ` Ulrich Weigand
2016-03-29 21:51             ` Pedro Alves
2016-03-30 11:30               ` Ulrich Weigand
2016-03-29 21:52             ` Marcin Kościelnicki
2016-03-30 11:32               ` Ulrich Weigand
2016-03-30 22:02                 ` Marcin Kościelnicki
2016-03-31 18:22                   ` Sergio Durigan Junior
2016-03-31 21:42                     ` [PATCH obv] gdbserver: Fix C++ build errors in tracepoint.c Marcin Kościelnicki
2016-03-14 17:08     ` [PATCH 1/3] gdbserver/IPA: Export some functions via global function pointers Simon Marchi
2016-03-14 17:40       ` Ulrich Weigand
2016-03-14 22:25 ` [PATCH 4/4] gdbserver: Add emit_ops for powerpc Marcin Kościelnicki
2016-03-16 17:16   ` Ulrich Weigand
2016-03-18 15:10     ` [PATCH v2 " Marcin Kościelnicki
2016-03-29 18:25       ` Ulrich Weigand
2016-03-31 13:45         ` Marcin Kościelnicki

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).