[PATCH 1/4 v3] Refactor internal variable mechanism

Sergio Durigan Junior
2012-04-23T04:57:33Z

Hi,

This is the first patch of the series. This piece didn't change since
the first iteraction.

http://sourceware.org/ml/gdb-patches/2012-03/msg00354.html

OK to check-in?

Thanks.

2012-04-23 Sergio Durigan Junior <sergiodj@redhat.com>
Tom Tromey <tromey@redhat.com>

* ax-gdb.c (gen_expr): Clean up code to handle internal variables
and to compile agent expressions.
* infrun.c (siginfo_make_value): New argument `ignore'.
(siginfo_funcs): New struct.
(_initialize_infrun): New argument when calling
`create_internalvar_type_lazy'.
* thread.c (thread_id_make_value): New argument `ignore'.
(thread_funcs): New struct.
(_initialize_thread): New argument when calling
`create_internalvar_type_lazy'.
* tracepoint.c (sdata_make_value): New argument `ignore'.
(sdata_funcs): New struct.
(_initialize_tracepoint): New argument when calling
`create_internalvar_type_lazy'.
* value.c (make_value): New struct.
(create_internalvar_type_lazy): New argument `data'.
(compile_internalvar_to_ax): New function.
(value_of_internalvar): Properly handling `make_value' case.
(clear_internalvar): Likewise.
(show_convenience): Adding `TRY_CATCH' block.
* value.h (internalvar_make_value): Delete, replace by...
(struct internalvar_funcs): ... this.
(create_internalvar_type_lazy) <fun>: Delete argument.
(create_internalvar_type_lazy) <funcs>, : New arguments.
(compile_internalvar_to_ax): New function.
* windows-tdep.c (tlb_make_value): New argument `ignore'.
(tlb_funcs): New struct.
(_initialize_windows_tdep): New argument when calling
`create_internalvar_type_lazy'.

---
gdb/ax-gdb.c | 5 +++--
gdb/infrun.c | 14 ++++++++++++--
gdb/thread.c | 14 ++++++++++++--
gdb/tracepoint.c | 14 ++++++++++++--
gdb/value.c | 44 +++++++++++++++++++++++++++++++++++++++-----
gdb/value.h | 48 +++++++++++++++++++++++++++++++++++++++++++++---
gdb/windows-tdep.c | 13 +++++++++++--
7 files changed, 134 insertions(+), 18 deletions(-)

diff --git a/gdb/ax-gdb.c b/gdb/ax-gdb.c
index aaefed6..eebe61a 100644
--- a/gdb/ax-gdb.c
+++ b/gdb/ax-gdb.c
@@ -2038,7 +2038,8 @@ gen_expr (struct expression *exp, union exp_element **pc,

case OP_INTERNALVAR:
{
- const char *name = internalvar_name ((*pc)[1].internalvar);
+ struct internalvar *var = (*pc)[1].internalvar;
+ const char *name = internalvar_name (var);
struct trace_state_variable *tsv;

(*pc) += 3;
@@ -2052,7 +2053,7 @@ gen_expr (struct expression *exp, union exp_element **pc,
value->kind = axs_rvalue;
value->type = builtin_type (exp->gdbarch)->builtin_long_long;
}
- else
+ else if (! compile_internalvar_to_ax (var, ax, value))
error (_("$%s is not a trace state variable; GDB agent "
"expressions cannot use convenience variables."), name);
}
diff --git a/gdb/infrun.c b/gdb/infrun.c
index a7d6c3c..c8a697a 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -6599,7 +6599,8 @@ static const struct lval_funcs siginfo_value_funcs =
if there's no object available. */

static struct value *
-siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+siginfo_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
{
if (target_has_stack
&& !ptid_equal (inferior_ptid, null_ptid)
@@ -7021,6 +7022,15 @@ show_schedule_multiple (struct ui_file *file, int from_tty,
"of all processes is %s.\n"), value);
}

+/* Implementation of `siginfo' variable. */
+
+static const struct internalvar_funcs siginfo_funcs =
+{
+ siginfo_make_value,
+ NULL,
+ NULL
+};
+
void
_initialize_infrun (void)
{
@@ -7309,7 +7319,7 @@ enabled by default on some platforms."),
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_siginfo", siginfo_make_value);
+ create_internalvar_type_lazy ("_siginfo", &siginfo_funcs, NULL);

add_setshow_boolean_cmd ("observer", no_class,
&observer_mode_1, _("\
diff --git a/gdb/thread.c b/gdb/thread.c
index 97f283c..d361dd8 100644
--- a/gdb/thread.c
+++ b/gdb/thread.c
@@ -1439,7 +1439,8 @@ update_thread_list (void)
no thread is selected, or no threads exist. */

static struct value *
-thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
{
struct thread_info *tp = find_thread_ptid (inferior_ptid);

@@ -1450,6 +1451,15 @@ thread_id_make_value (struct gdbarch *gdbarch, struct internalvar *var)
/* Commands with a prefix of `thread'. */
struct cmd_list_element *thread_cmd_list = NULL;

+/* Implementation of `thread' variable. */
+
+static const struct internalvar_funcs thread_funcs =
+{
+ thread_id_make_value,
+ NULL,
+ NULL
+};
+
void
_initialize_thread (void)
{
@@ -1495,5 +1505,5 @@ Show printing of thread events (such as thread start and exit)."), NULL,
show_print_thread_events,
&setprintlist, &showprintlist);

- create_internalvar_type_lazy ("_thread", thread_id_make_value);
+ create_internalvar_type_lazy ("_thread", &thread_funcs, NULL);
}
diff --git a/gdb/tracepoint.c b/gdb/tracepoint.c
index 86b6cfa..c213374 100644
--- a/gdb/tracepoint.c
+++ b/gdb/tracepoint.c
@@ -4944,7 +4944,8 @@ info_static_tracepoint_markers_command (char *arg, int from_tty)
available. */

static struct value *
-sdata_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+sdata_make_value (struct gdbarch *gdbarch, struct internalvar *var,
+ void *ignore)
{
LONGEST size;
gdb_byte *buf;
@@ -5123,6 +5124,15 @@ traceframe_available_memory (VEC(mem_range_s) **result,
return 0;
}

+/* Implementation of `sdata' variable. */
+
+static const struct internalvar_funcs sdata_funcs =
+{
+ sdata_make_value,
+ NULL,
+ NULL
+};
+
/* module initialization */
void
_initialize_tracepoint (void)
@@ -5133,7 +5143,7 @@ _initialize_tracepoint (void)
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_sdata", sdata_make_value);
+ create_internalvar_type_lazy ("_sdata", &sdata_funcs, NULL);

traceframe_number = -1;
tracepoint_number = -1;
diff --git a/gdb/value.c b/gdb/value.c
index eae3e2d..d498289 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -1629,7 +1629,14 @@ struct internalvar
struct value *value;

/* The call-back routine used with INTERNALVAR_MAKE_VALUE. */
- internalvar_make_value make_value;
+ struct
+ {
+ /* The functions to call. */
+ const struct internalvar_funcs *functions;
+
+ /* The function's user-data. */
+ void *data;
+ } make_value;

/* The internal function used with INTERNALVAR_FUNCTION. */
struct
@@ -1728,18 +1735,39 @@ create_internalvar (const char *name)
/* Create an internal variable with name NAME and register FUN as the
function that value_of_internalvar uses to create a value whenever
this variable is referenced. NAME should not normally include a
- dollar sign. */
+ dollar sign. DATA is passed uninterpreted to FUN when it is
+ called. CLEANUP, if not NULL, is called when the internal variable
+ is destroyed. It is passed DATA as its only argument. */

struct internalvar *
-create_internalvar_type_lazy (char *name, internalvar_make_value fun)
+create_internalvar_type_lazy (const char *name,
+ const struct internalvar_funcs *funcs,
+ void *data)
{
struct internalvar *var = create_internalvar (name);

var->kind = INTERNALVAR_MAKE_VALUE;
- var->u.make_value = fun;
+ var->u.make_value.functions = funcs;
+ var->u.make_value.data = data;
return var;
}

+/* See documentation in value.h. */
+
+int
+compile_internalvar_to_ax (struct internalvar *var,
+ struct agent_expr *expr,
+ struct axs_value *value)
+{
+ if (var->kind != INTERNALVAR_MAKE_VALUE
+ || var->u.make_value.functions->compile_to_ax == NULL)
+ return 0;
+
+ var->u.make_value.functions->compile_to_ax (var, expr, value,
+ var->u.make_value.data);
+ return 1;
+}
+
/* Look up an internal variable with name NAME. NAME should not
normally include a dollar sign.

@@ -1812,7 +1840,8 @@ value_of_internalvar (struct gdbarch *gdbarch, struct internalvar *var)
break;

case INTERNALVAR_MAKE_VALUE:
- val = (*var->u.make_value) (gdbarch, var);
+ val = (*var->u.make_value.functions->make_value) (gdbarch, var,
+ var->u.make_value.data);
break;

default:
@@ -2008,6 +2037,11 @@ clear_internalvar (struct internalvar *var)
xfree (var->u.string);
break;

+ case INTERNALVAR_MAKE_VALUE:
+ if (var->u.make_value.functions->destroy != NULL)
+ var->u.make_value.functions->destroy (var->u.make_value.data);
+ break;
+
default:
break;
}
diff --git a/gdb/value.h b/gdb/value.h
index 03aa5fd..76c8e85 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -764,10 +764,52 @@ extern struct internalvar *lookup_only_internalvar (const char *name);

extern struct internalvar *create_internalvar (const char *name);

-typedef struct value * (*internalvar_make_value) (struct gdbarch *,
- struct internalvar *);
+/* An internalvar can be dynamically computed by supplying a vector of
+ function pointers to perform various operations. */
+
+struct internalvar_funcs
+{
+ /* Compute the value of the variable. The DATA argument passed to
+ the function is the same argument that was passed to
+ `create_internalvar_type_lazy'. */
+
+ struct value *(*make_value) (struct gdbarch *arch,
+ struct internalvar *var,
+ void *data);
+
+ /* Update the agent expression EXPR with bytecode to compute the
+ value. VALUE is the agent value we are updating. The DATA
+ argument passed to this function is the same argument that was
+ passed to `create_internalvar_type_lazy'. If this pointer is
+ NULL, then the internalvar cannot be compiled to an agent
+ expression. */
+
+ void (*compile_to_ax) (struct internalvar *var,
+ struct agent_expr *expr,
+ struct axs_value *value,
+ void *data);
+
+ /* If non-NULL, this is called to destroy DATA. The DATA argument
+ passed to this function is the same argument that was passed to
+ `create_internalvar_type_lazy'. */
+
+ void (*destroy) (void *data);
+};
+
extern struct internalvar *
- create_internalvar_type_lazy (char *name, internalvar_make_value fun);
+create_internalvar_type_lazy (const char *name,
+ const struct internalvar_funcs *funcs,
+ void *data);
+
+/* Compile an internal variable to an agent expression. VAR is the
+ variable to compile; EXPR and VALUE are the agent expression we are
+ updating. This will return 0 if there is no known way to compile
+ VAR, and 1 if VAR was successfully compiled. It may also throw an
+ exception on error. */
+
+extern int compile_internalvar_to_ax (struct internalvar *var,
+ struct agent_expr *expr,
+ struct axs_value *value);

extern struct internalvar *lookup_internalvar (const char *name);

diff --git a/gdb/windows-tdep.c b/gdb/windows-tdep.c
index 6b84eff..a704599 100644
--- a/gdb/windows-tdep.c
+++ b/gdb/windows-tdep.c
@@ -268,7 +268,7 @@ static const struct lval_funcs tlb_value_funcs =
if there's no object available. */

static struct value *
-tlb_make_value (struct gdbarch *gdbarch, struct internalvar *var)
+tlb_make_value (struct gdbarch *gdbarch, struct internalvar *var, void *ignore)
{
if (target_has_stack && !ptid_equal (inferior_ptid, null_ptid))
{
@@ -428,6 +428,15 @@ init_w32_command_list (void)
/* Provide a prototype to silence -Wmissing-prototypes. */
extern initialize_file_ftype _initialize_windows_tdep;

+/* Implementation of `tlb' variable. */
+
+static const struct internalvar_funcs tlb_funcs =
+{
+ tlb_make_value,
+ NULL,
+ NULL
+};
+
void
_initialize_windows_tdep (void)
{
@@ -454,5 +463,5 @@ even if their meaning is unknown."),
value with a void typed value, and when we get here, gdbarch
isn't initialized yet. At this point, we're quite sure there
isn't another convenience variable of the same name. */
- create_internalvar_type_lazy ("_tlb", tlb_make_value);
+ create_internalvar_type_lazy ("_tlb", &tlb_funcs, NULL);
}
--
1.7.7.6

--
Sergio