summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorMarcin Kościelnicki <koriakin@0x04.net>2016-03-13 00:30:11 +0100
committerMarcin Kościelnicki <koriakin@0x04.net>2016-03-14 14:12:19 +0100
commit17bc04a7dee6e178489d77c036ef96660c9128dc (patch)
treeaa65733d26928bab8ec7fc72011ce8c17ddeb552
parent6257f9a4f7d3391a18bf5e39e3411dd9131cb217 (diff)
downloadbinutils-gdb-17bc04a7dee6e178489d77c036ef96660c9128dc.tar.gz
IPA: Add alloc_jump_pad_buffer target hook.
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.
-rw-r--r--gdb/gdbserver/ChangeLog11
-rw-r--r--gdb/gdbserver/linux-aarch64-ipa.c43
-rw-r--r--gdb/gdbserver/linux-amd64-ipa.c18
-rw-r--r--gdb/gdbserver/linux-i386-ipa.c15
-rw-r--r--gdb/gdbserver/tracepoint.c25
-rw-r--r--gdb/gdbserver/tracepoint.h1
6 files changed, 94 insertions, 19 deletions
diff --git a/gdb/gdbserver/ChangeLog b/gdb/gdbserver/ChangeLog
index 31120c5abf4..4a4a9bff42e 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 00cbf3ee89d..b95751b4f08 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 70889d293a7..9ee0fe83085 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 7159eeed396..52c0581ac29 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 061e1614d0b..0b6d3274955 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 df815efef54..0f4d4980161 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);