aboutsummaryrefslogtreecommitdiff
path: root/gdb/linux-tdep.c
diff options
context:
space:
mode:
Diffstat (limited to 'gdb/linux-tdep.c')
-rw-r--r--gdb/linux-tdep.c102
1 files changed, 100 insertions, 2 deletions
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
index 2ffd992..ffc3e87 100644
--- a/gdb/linux-tdep.c
+++ b/gdb/linux-tdep.c
@@ -32,6 +32,7 @@
#include "cli/cli-utils.h"
#include "arch-utils.h"
#include "gdb_obstack.h"
+#include "observer.h"
#include <ctype.h>
@@ -119,6 +120,72 @@ get_linux_gdbarch_data (struct gdbarch *gdbarch)
return gdbarch_data (gdbarch, linux_gdbarch_data_handle);
}
+/* Per-inferior data key. */
+static const struct inferior_data *linux_inferior_data;
+
+/* Linux-specific cached data. This is used by GDB for caching
+ purposes for each inferior. This helps reduce the overhead of
+ transfering data from a remote target to the local host. */
+struct linux_info
+{
+ /* Cache of the inferior's vsyscall/vDSO mapping range. Only valid
+ if VSYSCALL_RANGE_P is positive. This is cached because getting
+ at this info requires an auxv lookup (which is itself cached),
+ and looking through the inferior's mappings (which change
+ throughout execution and therefore cannot be cached). */
+ struct mem_range vsyscall_range;
+
+ /* Zero if we haven't tried looking up the vsyscall's range before
+ yet. Positive if we tried looking it up, and found it. Negative
+ if we tried looking it up but failed. */
+ int vsyscall_range_p;
+};
+
+/* Frees whatever allocated space there is to be freed and sets INF's
+ linux cache data pointer to NULL. */
+
+static void
+invalidate_linux_cache_inf (struct inferior *inf)
+{
+ struct linux_info *info;
+
+ info = inferior_data (inf, linux_inferior_data);
+ if (info != NULL)
+ {
+ xfree (info);
+ set_inferior_data (inf, linux_inferior_data, NULL);
+ }
+}
+
+/* Handles the cleanup of the linux cache for inferior INF. ARG is
+ ignored. Callback for the inferior_appeared and inferior_exit
+ events. */
+
+static void
+linux_inferior_data_cleanup (struct inferior *inf, void *arg)
+{
+ invalidate_linux_cache_inf (inf);
+}
+
+/* Fetch the linux cache info for INF. This function always returns a
+ valid INFO pointer. */
+
+static struct linux_info *
+get_linux_inferior_data (void)
+{
+ struct linux_info *info;
+ struct inferior *inf = current_inferior ();
+
+ info = inferior_data (inf, linux_inferior_data);
+ if (info == NULL)
+ {
+ info = XCNEW (struct linux_info);
+ set_inferior_data (inf, linux_inferior_data, info);
+ }
+
+ return info;
+}
+
/* This function is suitable for architectures that don't
extend/override the standard siginfo structure. */
@@ -1813,10 +1880,11 @@ find_mapping_size (CORE_ADDR vaddr, unsigned long size,
return 0;
}
-/* Implementation of the "vsyscall_range" gdbarch hook. */
+/* Helper for linux_vsyscall_range that does the real work of finding
+ the vsyscall's address range. */
static int
-linux_vsyscall_range (struct gdbarch *gdbarch, struct mem_range *range)
+linux_vsyscall_range_raw (struct gdbarch *gdbarch, struct mem_range *range)
{
if (target_auxv_search (&current_target, AT_SYSINFO_EHDR, &range->start) <= 0)
return 0;
@@ -1830,6 +1898,29 @@ linux_vsyscall_range (struct gdbarch *gdbarch, struct mem_range *range)
return 1;
}
+/* Implementation of the "vsyscall_range" gdbarch hook. Handles
+ caching, and defers the real work to linux_vsyscall_range_raw. */
+
+static int
+linux_vsyscall_range (struct gdbarch *gdbarch, struct mem_range *range)
+{
+ struct linux_info *info = get_linux_inferior_data ();
+
+ if (info->vsyscall_range_p == 0)
+ {
+ if (linux_vsyscall_range_raw (gdbarch, &info->vsyscall_range))
+ info->vsyscall_range_p = 1;
+ else
+ info->vsyscall_range_p = -1;
+ }
+
+ if (info->vsyscall_range_p < 0)
+ return 0;
+
+ *range = info->vsyscall_range;
+ return 1;
+}
+
/* To be called from the various GDB_OSABI_LINUX handlers for the
various GNU/Linux architectures and machine types. */
@@ -1858,4 +1949,11 @@ _initialize_linux_tdep (void)
{
linux_gdbarch_data_handle =
gdbarch_data_register_post_init (init_linux_gdbarch_data);
+
+ /* Set a cache per-inferior. */
+ linux_inferior_data
+ = register_inferior_data_with_cleanup (NULL, linux_inferior_data_cleanup);
+ /* Observers used to invalidate the cache when needed. */
+ observer_attach_inferior_exit (invalidate_linux_cache_inf);
+ observer_attach_inferior_appeared (invalidate_linux_cache_inf);
}