IPA: Add alloc_jump_pad_buffer target hook.
authorMarcin Kościelnicki <koriakin@0x04.net>
Sat, 12 Mar 2016 23:30:11 +0000 (00:30 +0100)
committerMarcin Kościelnicki <koriakin@0x04.net>
Thu, 31 Mar 2016 13:36:38 +0000 (15:36 +0200)
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.

gdb/gdbserver/ChangeLog
gdb/gdbserver/linux-aarch64-ipa.c
gdb/gdbserver/linux-amd64-ipa.c
gdb/gdbserver/linux-i386-ipa.c
gdb/gdbserver/linux-s390-ipa.c
gdb/gdbserver/tracepoint.c
gdb/gdbserver/tracepoint.h

index 644a81088fe62821eaecaf5a57d501dbe7d12f44..045faee1ba1504cb7d31c4af13d9eaf82be6a585 100644 (file)
@@ -1,3 +1,17 @@
+2016-03-31  Marcin Kościelnicki  <koriakin@0x04.net>
+
+       * 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.
+
 2016-03-30  Marcin Kościelnicki  <koriakin@0x04.net>
 
        * linux-aarch64-ipa.c: Rename gdb_agent_get_raw_reg to get_raw_reg.
index 00cbf3ee89d3bedc9961077aa039714d961ba687..50caeae4f3f46d58daffaed948d32757f1802832 100644 (file)
    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)
 {
index 70889d293a72ccc4f7e903f57cd25c57a1b09fd8..c623dc204bed7b34694494cdb4e849ed1efe67ee 100644 (file)
@@ -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)
 {
index 7159eeed3967076d052aee1db9a53fd1cf23049a..45e5a0d5f84a83acebe558e11e56d0021fdd208e 100644 (file)
@@ -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)
 {
index cd4faddae8adef87938e1ef9b841376bcbfe1dd1..a9f86ad44416bc17ceccdb4256fe15b90a7b2e36 100644 (file)
    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)
 {
index 83d1830db2bf2e4c6e6ab11802c1f0f8efd0a16e..56b8e69556ca5ef61ac4390c7d8fa883875bc6c0 100644 (file)
@@ -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;
index df815efef54d537f4d542b7ed5c6991b92b6fea0..679a32a3999a20f57db72893a96da925321e49fb 100644 (file)
@@ -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);
 
This page took 0.03461 seconds and 4 git commands to generate.