aboutsummaryrefslogtreecommitdiff
path: root/gdb/auxv.c
diff options
context:
space:
mode:
authorLuis Machado <luisgpm@br.ibm.com>2011-11-15 13:17:05 +0000
committerLuis Machado <luisgpm@br.ibm.com>2011-11-15 13:17:05 +0000
commit865ecab4b2b7d6efeaec3072ee843d2d830d2dae (patch)
tree2a17c5ab92a7196613bac62de02b19c000c30465 /gdb/auxv.c
parent080f9e4f20da18de6c34ef23a9a015ba81c5d6e7 (diff)
downloadgdb-865ecab4b2b7d6efeaec3072ee843d2d830d2dae.zip
gdb-865ecab4b2b7d6efeaec3072ee843d2d830d2dae.tar.gz
gdb-865ecab4b2b7d6efeaec3072ee843d2d830d2dae.tar.bz2
2011-11-15 Pedro Alves <pedro@codesourcery.com>
Luis Machado <lgustavo@codesourcery.com> * auxv.c: Include observer.h. (auxv_inferior_data_cleanup): New. (invalidate_auxv_cache_inf): New. (invalidate_auxv_cache): New. (get_auxv_inferior_data): New. (auxv_inferior_data): New static global. (auxv_info): New structure. (target_auxv_search): Use get_auxv_inferior_data instead of target_read_alloc and don't free cached buffers. (fprint_target_auxv): Likewise (_initialize_auxv): Register per-inferior auxv cache and register observers to invalidate auxv cache when needed.
Diffstat (limited to 'gdb/auxv.c')
-rw-r--r--gdb/auxv.c117
1 files changed, 101 insertions, 16 deletions
diff --git a/gdb/auxv.c b/gdb/auxv.c
index 28196b4..934441b 100644
--- a/gdb/auxv.c
+++ b/gdb/auxv.c
@@ -26,6 +26,7 @@
#include "valprint.h"
#include "gdb_assert.h"
#include "gdbcore.h"
+#include "observer.h"
#include "auxv.h"
#include "elf/common.h"
@@ -277,6 +278,78 @@ target_auxv_parse (struct target_ops *ops, gdb_byte **readptr,
return default_auxv_parse (ops, readptr, endptr, typep, valp);
}
+
+/* Per-inferior data key for auxv. */
+static const struct inferior_data *auxv_inferior_data;
+
+/* Auxiliary Vector information structure. 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 auxv_info
+{
+ LONGEST length;
+ gdb_byte *data;
+};
+
+/* Handles the cleanup of the auxv cache for inferior INF. ARG is ignored.
+ Frees whatever allocated space there is to be freed and sets INF's auxv cache
+ data pointer to NULL.
+
+ This function is called when the following events occur: inferior_appeared,
+ inferior_exit and executable_changed. */
+
+static void
+auxv_inferior_data_cleanup (struct inferior *inf, void *arg)
+{
+ struct auxv_info *info;
+
+ info = inferior_data (inf, auxv_inferior_data);
+ if (info != NULL)
+ {
+ xfree (info->data);
+ xfree (info);
+ set_inferior_data (inf, auxv_inferior_data, NULL);
+ }
+}
+
+/* Invalidate INF's auxv cache. */
+
+static void
+invalidate_auxv_cache_inf (struct inferior *inf)
+{
+ auxv_inferior_data_cleanup (inf, NULL);
+}
+
+/* Invalidate current inferior's auxv cache. */
+
+static void
+invalidate_auxv_cache (void)
+{
+ invalidate_auxv_cache_inf (current_inferior ());
+}
+
+/* Fetch the auxv object from inferior INF. If auxv is cached already,
+ return a pointer to the cache. If not, fetch the auxv object from the
+ target and cache it. This function always returns a valid INFO pointer. */
+
+static struct auxv_info *
+get_auxv_inferior_data (struct target_ops *ops)
+{
+ struct auxv_info *info;
+ struct inferior *inf = current_inferior ();
+
+ info = inferior_data (inf, auxv_inferior_data);
+ if (info == NULL)
+ {
+ info = XZALLOC (struct auxv_info);
+ info->length = target_read_alloc (ops, TARGET_OBJECT_AUXV,
+ NULL, &info->data);
+ set_inferior_data (inf, auxv_inferior_data, info);
+ }
+
+ return info;
+}
+
/* Extract the auxiliary vector entry with a_type matching MATCH.
Return zero if no such entry was found, or -1 if there was
an error getting the information. On success, return 1 after
@@ -286,28 +359,30 @@ target_auxv_search (struct target_ops *ops, CORE_ADDR match, CORE_ADDR *valp)
{
CORE_ADDR type, val;
gdb_byte *data;
- LONGEST n = target_read_alloc (ops, TARGET_OBJECT_AUXV, NULL, &data);
- gdb_byte *ptr = data;
+ gdb_byte *ptr;
+ struct auxv_info *info;
+
+ info = get_auxv_inferior_data (ops);
+
+ data = info->data;
+ ptr = data;
- if (n <= 0)
- return n;
+ if (info->length <= 0)
+ return info->length;
while (1)
- switch (target_auxv_parse (ops, &ptr, data + n, &type, &val))
+ switch (target_auxv_parse (ops, &ptr, data + info->length, &type, &val))
{
case 1: /* Here's an entry, check it. */
if (type == match)
{
- xfree (data);
*valp = val;
return 1;
}
break;
case 0: /* End of the vector. */
- xfree (data);
return 0;
default: /* Bogosity. */
- xfree (data);
return -1;
}
@@ -321,15 +396,18 @@ fprint_target_auxv (struct ui_file *file, struct target_ops *ops)
{
CORE_ADDR type, val;
gdb_byte *data;
- LONGEST len = target_read_alloc (ops, TARGET_OBJECT_AUXV, NULL,
- &data);
- gdb_byte *ptr = data;
+ gdb_byte *ptr;
+ struct auxv_info *info;
int ents = 0;
- if (len <= 0)
- return len;
+ info = get_auxv_inferior_data (ops);
- while (target_auxv_parse (ops, &ptr, data + len, &type, &val) > 0)
+ data = info->data;
+ ptr = data;
+ if (info->length <= 0)
+ return info->length;
+
+ while (target_auxv_parse (ops, &ptr, data + info->length, &type, &val) > 0)
{
const char *name = "???";
const char *description = "";
@@ -418,8 +496,6 @@ fprint_target_auxv (struct ui_file *file, struct target_ops *ops)
break;
}
- xfree (data);
-
return ents;
}
@@ -448,4 +524,13 @@ _initialize_auxv (void)
add_info ("auxv", info_auxv_command,
_("Display the inferior's auxiliary vector.\n\
This is information provided by the operating system at program startup."));
+
+ /* Set an auxv cache per-inferior. */
+ auxv_inferior_data
+ = register_inferior_data_with_cleanup (auxv_inferior_data_cleanup);
+
+ /* Observers used to invalidate the auxv cache when needed. */
+ observer_attach_inferior_exit (invalidate_auxv_cache_inf);
+ observer_attach_inferior_appeared (invalidate_auxv_cache_inf);
+ observer_attach_executable_changed (invalidate_auxv_cache);
}