/* Low level packing and unpacking of values for GDB, the GNU Debugger.
Copyright (C) 1986, 1987, 1988, 1989, 1990, 1991, 1992, 1993, 1994, 1995,
- 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2008
- Free Software Foundation, Inc.
+ 1996, 1997, 1998, 1999, 2000, 2002, 2003, 2004, 2005, 2006, 2007, 2008,
+ 2009 Free Software Foundation, Inc.
This file is part of GDB.
#include "dfp.h"
#include "objfiles.h"
#include "valprint.h"
+#include "cli/cli-decode.h"
#include "python/python.h"
void _initialize_values (void);
+/* Definition of a user function. */
+struct internal_function
+{
+ /* The name of the function. It is a bit odd to have this in the
+ function itself -- the user might use a differently-named
+ convenience variable to hold the function. */
+ char *name;
+
+ /* The handler. */
+ internal_function_fn handler;
+
+ /* User data for the handler. */
+ void *cookie;
+};
+
+static struct cmd_list_element *functionlist;
+
struct value
{
/* Type of value; either not an lval, or one of the various
/* Pointer to internal variable. */
struct internalvar *internalvar;
+
+ /* If lval == lval_computed, this is a set of function pointers
+ to use to access and describe the value, and a closure pointer
+ for them to use. */
+ struct
+ {
+ struct lval_funcs *funcs; /* Functions to call. */
+ void *closure; /* Closure for those functions to use. */
+ } computed;
} location;
/* Describes offset of a value within lval of a structure in bytes.
static struct value_history_chunk *value_history_chain;
static int value_history_count; /* Abs number of last entry stored */
+
+/* The type of internal functions. */
+
+static struct type *internal_fn_type;
\f
/* List of all value objects currently allocated
(except for those released by calls to release_value)
}
}
+struct value *
+allocate_computed_value (struct type *type,
+ struct lval_funcs *funcs,
+ void *closure)
+{
+ struct value *v = allocate_value (type);
+ VALUE_LVAL (v) = lval_computed;
+ v->location.computed.funcs = funcs;
+ v->location.computed.closure = closure;
+ set_value_lazy (v, 1);
+
+ return v;
+}
+
/* Accessor methods. */
struct value *
value->pointed_to_offset = val;
}
+struct lval_funcs *
+value_computed_funcs (struct value *v)
+{
+ gdb_assert (VALUE_LVAL (v) == lval_computed);
+
+ return v->location.computed.funcs;
+}
+
+void *
+value_computed_closure (struct value *v)
+{
+ gdb_assert (VALUE_LVAL (v) == lval_computed);
+
+ return v->location.computed.closure;
+}
+
enum lval_type *
deprecated_value_lval_hack (struct value *value)
{
value_free (struct value *val)
{
if (val)
- xfree (val->contents);
+ {
+ if (VALUE_LVAL (val) == lval_computed)
+ {
+ struct lval_funcs *funcs = val->location.computed.funcs;
+
+ if (funcs->free_closure)
+ funcs->free_closure (val);
+ }
+
+ xfree (val->contents);
+ }
xfree (val);
}
TYPE_LENGTH (value_enclosing_type (arg)));
}
+ if (VALUE_LVAL (val) == lval_computed)
+ {
+ struct lval_funcs *funcs = val->location.computed.funcs;
+
+ if (funcs->copy_closure)
+ val->location.computed.closure = funcs->copy_closure (val);
+ }
return val;
}
+
+void
+set_value_component_location (struct value *component, struct value *whole)
+{
+ if (VALUE_LVAL (whole) == lval_internalvar)
+ VALUE_LVAL (component) = lval_internalvar_component;
+ else
+ VALUE_LVAL (component) = VALUE_LVAL (whole);
+
+ component->location = whole->location;
+ if (VALUE_LVAL (whole) == lval_computed)
+ {
+ struct lval_funcs *funcs = whole->location.computed.funcs;
+
+ if (funcs->copy_closure)
+ component->location.computed.closure = funcs->copy_closure (whole);
+ }
+}
+
\f
/* Access to the value history. */
the return value is NULL. */
struct internalvar *
-lookup_only_internalvar (char *name)
+lookup_only_internalvar (const char *name)
{
struct internalvar *var;
NAME should not normally include a dollar sign. */
struct internalvar *
-create_internalvar (char *name)
+create_internalvar (const char *name)
{
struct internalvar *var;
var = (struct internalvar *) xmalloc (sizeof (struct internalvar));
var->name = concat (name, (char *)NULL);
var->value = allocate_value (builtin_type_void);
var->endian = gdbarch_byte_order (current_gdbarch);
+ var->make_value = NULL;
+ var->canonical = 0;
release_value (var->value);
var->next = internalvars;
internalvars = var;
return var;
}
+/* 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. */
+
+struct internalvar *
+create_internalvar_type_lazy (char *name, internalvar_make_value fun)
+{
+ struct internalvar *var;
+ var = (struct internalvar *) xmalloc (sizeof (struct internalvar));
+ var->name = concat (name, (char *)NULL);
+ var->value = NULL;
+ var->make_value = fun;
+ var->endian = gdbarch_byte_order (current_gdbarch);
+ var->next = internalvars;
+ internalvars = var;
+ return var;
+}
/* Look up an internal variable with name NAME. NAME should not
normally include a dollar sign.
one is created, with a void value. */
struct internalvar *
-lookup_internalvar (char *name)
+lookup_internalvar (const char *name)
{
struct internalvar *var;
int i, j;
gdb_byte temp;
- val = value_copy (var->value);
- if (value_lazy (val))
- value_fetch_lazy (val);
- VALUE_LVAL (val) = lval_internalvar;
- VALUE_INTERNALVAR (val) = var;
+ if (var->make_value != NULL)
+ val = (*var->make_value) (var);
+ else
+ {
+ val = value_copy (var->value);
+ if (value_lazy (val))
+ value_fetch_lazy (val);
+
+ /* If the variable's value is a computed lvalue, we want
+ references to it to produce another computed lvalue, where
+ referencces and assignments actually operate through the
+ computed value's functions.
+
+ This means that internal variables with computed values
+ behave a little differently from other internal variables:
+ assignments to them don't just replace the previous value
+ altogether. At the moment, this seems like the behavior we
+ want. */
+ if (var->value->lval == lval_computed)
+ VALUE_LVAL (val) = lval_computed;
+ else
+ {
+ VALUE_LVAL (val) = lval_internalvar;
+ VALUE_INTERNALVAR (val) = var;
+ }
+ }
/* Values are always stored in the target's byte order. When connected to a
target this will most likely always be correct, so there's normally no
{
struct value *newval;
+ if (var->canonical)
+ error (_("Cannot overwrite convenience function %s"), var->name);
+
newval = value_copy (val);
newval->modifiable = 1;
/* Begin code which must not call error(). If var->value points to
something free'd, an error() obviously leaves a dangling pointer.
- But we also get a danling pointer if var->value points to
+ But we also get a dangling pointer if var->value points to
something in the value chain (i.e., before release_value is
called), because after the error free_all_values will get called before
long. */
- xfree (var->value);
+ value_free (var->value);
var->value = newval;
var->endian = gdbarch_byte_order (current_gdbarch);
release_value (newval);
return var->name;
}
+static struct value *
+value_create_internal_function (const char *name,
+ internal_function_fn handler,
+ void *cookie)
+{
+ struct value *result = allocate_value (internal_fn_type);
+ gdb_byte *addr = value_contents_writeable (result);
+ struct internal_function **fnp = (struct internal_function **) addr;
+ struct internal_function *ifn = XNEW (struct internal_function);
+ ifn->name = xstrdup (name);
+ ifn->handler = handler;
+ ifn->cookie = cookie;
+ *fnp = ifn;
+ return result;
+}
+
+char *
+value_internal_function_name (struct value *val)
+{
+ gdb_byte *addr = value_contents_writeable (val);
+ struct internal_function *ifn = * (struct internal_function **) addr;
+ return ifn->name;
+}
+
+struct value *
+call_internal_function (struct value *func, int argc, struct value **argv)
+{
+ gdb_byte *addr = value_contents_writeable (func);
+ struct internal_function *ifn = * (struct internal_function **) addr;
+ return (*ifn->handler) (ifn->cookie, argc, argv);
+}
+
+/* The 'function' command. This does nothing -- it is just a
+ placeholder to let "help function NAME" work. This is also used as
+ the implementation of the sub-command that is created when
+ registering an internal function. */
+static void
+function_command (char *command, int from_tty)
+{
+ /* Do nothing. */
+}
+
+/* Clean up if an internal function's command is destroyed. */
+static void
+function_destroyer (struct cmd_list_element *self, void *ignore)
+{
+ xfree (self->name);
+ xfree (self->doc);
+}
+
+/* Add a new internal function. NAME is the name of the function; DOC
+ is a documentation string describing the function. HANDLER is
+ called when the function is invoked. COOKIE is an arbitrary
+ pointer which is passed to HANDLER and is intended for "user
+ data". */
+void
+add_internal_function (const char *name, const char *doc,
+ internal_function_fn handler, void *cookie)
+{
+ struct cmd_list_element *cmd;
+ struct internalvar *var = lookup_internalvar (name);
+ struct value *fnval = value_create_internal_function (name, handler, cookie);
+ set_internalvar (var, fnval);
+ var->canonical = 1;
+
+ cmd = add_cmd (xstrdup (name), no_class, function_command, (char *) doc,
+ &functionlist);
+ cmd->destroyer = function_destroyer;
+}
+
/* Update VALUE before discarding OBJFILE. COPIED_TYPES is used to
prevent cycles / duplicates. */
preserve_one_value (cur->values[i], objfile, copied_types);
for (var = internalvars; var; var = var->next)
- preserve_one_value (var->value, objfile, copied_types);
+ if (var->value)
+ preserve_one_value (var->value, objfile, copied_types);
for (val = values_in_python; val; val = val->next)
preserve_one_value (val, objfile, copied_types);
v->offset = (value_offset (arg1) + offset
+ value_embedded_offset (arg1));
}
- VALUE_LVAL (v) = VALUE_LVAL (arg1);
- if (VALUE_LVAL (arg1) == lval_internalvar)
- VALUE_LVAL (v) = lval_internalvar_component;
- v->location = arg1->location;
+ set_value_component_location (v, arg1);
VALUE_REGNUM (v) = VALUE_REGNUM (arg1);
VALUE_FRAME_ID (v) = VALUE_FRAME_ID (arg1);
return v;
else
memcpy (value_contents_raw (v), valaddr, TYPE_LENGTH (type));
VALUE_ADDRESS (v) = address;
- if (address != 0)
- VALUE_LVAL (v) = lval_memory;
+ VALUE_LVAL (v) = lval_memory;
return v;
}
Set an internal VARIABLE to the result of the EXPRESSION if it does not\n\
exist or does not contain a value. The EXPRESSION is not evaluated if the\n\
VARIABLE is already initialized."));
+
+ add_prefix_cmd ("function", no_class, function_command, _("\
+Placeholder command for showing help on convenience functions."),
+ &functionlist, "function ", 0, &cmdlist);
+
+ internal_fn_type = alloc_type (NULL);
+ TYPE_CODE (internal_fn_type) = TYPE_CODE_INTERNAL_FUNCTION;
+ TYPE_LENGTH (internal_fn_type) = sizeof (struct internal_function *);
+ TYPE_NAME (internal_fn_type) = "<internal function>";
}