#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
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)
val->type = type;
val->enclosing_type = type;
VALUE_LVAL (val) = not_lval;
- VALUE_ADDRESS (val) = 0;
+ val->location.address = 0;
VALUE_FRAME_ID (val) = null_frame_id;
val->offset = 0;
val->bitpos = 0;
return &value->lval;
}
-CORE_ADDR *
-deprecated_value_address_hack (struct value *value)
+CORE_ADDR
+value_address (struct value *value)
+{
+ if (value->lval == lval_internalvar
+ || value->lval == lval_internalvar_component)
+ return 0;
+ return value->location.address + value->offset;
+}
+
+CORE_ADDR
+value_raw_address (struct value *value)
+{
+ if (value->lval == lval_internalvar
+ || value->lval == lval_internalvar_component)
+ return 0;
+ return value->location.address;
+}
+
+void
+set_value_address (struct value *value, CORE_ADDR addr)
{
- return &value->location.address;
+ gdb_assert (value->lval != lval_internalvar
+ && value->lval != lval_internalvar_component);
+ value->location.address = addr;
}
struct internalvar **
The user refers to them with a '$' prefix
that does not appear in the variable names stored internally. */
+struct internalvar
+{
+ struct internalvar *next;
+ char *name;
+ struct type *type;
+
+ /* True if this internalvar is the canonical name for a convenience
+ function. */
+ int canonical;
+
+ /* If this function is non-NULL, it is used to compute a fresh value
+ on every access to the internalvar. */
+ internalvar_make_value make_value;
+
+ /* To reduce dependencies on target properties (like byte order) that
+ may change during the lifetime of an internal variable, we store
+ simple scalar values as host objects. */
+ union internalvar_data
+ {
+ struct value *v;
+ struct internal_function *f;
+ LONGEST l;
+ CORE_ADDR a;
+ } u;
+};
+
static struct internalvar *internalvars;
/* If the variable does not already exist create it and give it the value given.
/* Only evaluate the expression if the lvalue is void.
This may still fail if the expresssion is invalid. */
- if (TYPE_CODE (value_type (intvar->value)) == TYPE_CODE_VOID)
+ if (TYPE_CODE (intvar->type) == TYPE_CODE_VOID)
evaluate_expression (expr);
do_cleanups (old_chain);
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);
- release_value (var->value);
+ var->type = builtin_type_void;
+ var->make_value = NULL;
+ var->canonical = 0;
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 = create_internalvar (name);
+ var->make_value = fun;
+ 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;
value_of_internalvar (struct internalvar *var)
{
struct value *val;
- int i, j;
- gdb_byte temp;
-
- 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;
+ if (var->make_value != NULL)
+ val = (*var->make_value) (var);
else
{
- VALUE_LVAL (val) = lval_internalvar;
- VALUE_INTERNALVAR (val) = var;
- }
+ switch (TYPE_CODE (var->type))
+ {
+ case TYPE_CODE_VOID:
+ case TYPE_CODE_INTERNAL_FUNCTION:
+ val = allocate_value (var->type);
+ break;
+
+ case TYPE_CODE_INT:
+ val = value_from_longest (var->type, var->u.l);
+ break;
- /* 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
- need to worry about it.
+ case TYPE_CODE_PTR:
+ val = value_from_pointer (var->type, var->u.a);
+ break;
+
+ default:
+ val = value_copy (var->u.v);
+ break;
+ }
- However, internal variables can be set up before the target endian is
- known and so may become out of date. Fix it up before anybody sees.
+ if (value_lazy (val))
+ value_fetch_lazy (val);
- Internal variables usually hold simple scalar values, and we can
- correct those. More complex values (e.g. structures and floating
- point types) are left alone, because they would be too complicated
- to correct. */
+ /* 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.
- if (var->endian != gdbarch_byte_order (current_gdbarch))
- {
- gdb_byte *array = value_contents_raw (val);
- struct type *type = check_typedef (value_enclosing_type (val));
- switch (TYPE_CODE (type))
+ 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 (val->lval != lval_computed)
{
- case TYPE_CODE_INT:
- case TYPE_CODE_PTR:
- /* Reverse the bytes. */
- for (i = 0, j = TYPE_LENGTH (type) - 1; i < j; i++, j--)
- {
- temp = array[j];
- array[j] = array[i];
- array[i] = temp;
- }
- break;
+ VALUE_LVAL (val) = lval_internalvar;
+ VALUE_INTERNALVAR (val) = var;
}
}
return val;
}
+int
+get_internalvar_integer (struct internalvar *var, LONGEST *result)
+{
+ switch (TYPE_CODE (var->type))
+ {
+ case TYPE_CODE_INT:
+ *result = var->u.l;
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
+static int
+get_internalvar_function (struct internalvar *var,
+ struct internal_function **result)
+{
+ switch (TYPE_CODE (var->type))
+ {
+ case TYPE_CODE_INTERNAL_FUNCTION:
+ *result = var->u.f;
+ return 1;
+
+ default:
+ return 0;
+ }
+}
+
void
set_internalvar_component (struct internalvar *var, int offset, int bitpos,
int bitsize, struct value *newval)
{
- gdb_byte *addr = value_contents_writeable (var->value) + offset;
+ gdb_byte *addr;
- if (bitsize)
- modify_field (addr, value_as_long (newval),
- bitpos, bitsize);
- else
- memcpy (addr, value_contents (newval), TYPE_LENGTH (value_type (newval)));
+ switch (TYPE_CODE (var->type))
+ {
+ case TYPE_CODE_VOID:
+ case TYPE_CODE_INTERNAL_FUNCTION:
+ case TYPE_CODE_INT:
+ case TYPE_CODE_PTR:
+ /* We can never get a component of a basic type. */
+ internal_error (__FILE__, __LINE__, "set_internalvar_component");
+
+ default:
+ addr = value_contents_writeable (var->u.v);
+
+ if (bitsize)
+ modify_field (addr + offset,
+ value_as_long (newval), bitpos, bitsize);
+ else
+ memcpy (addr + offset, value_contents (newval),
+ TYPE_LENGTH (value_type (newval)));
+ break;
+ }
}
void
set_internalvar (struct internalvar *var, struct value *val)
{
- struct value *newval;
-
- newval = value_copy (val);
- newval->modifiable = 1;
-
- /* Force the value to be fetched from the target now, to avoid problems
- later when this internalvar is referenced and the target is gone or
- has changed. */
- if (value_lazy (newval))
- value_fetch_lazy (newval);
-
- /* 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
- something in the value chain (i.e., before release_value is
- called), because after the error free_all_values will get called before
- long. */
- value_free (var->value);
- var->value = newval;
- var->endian = gdbarch_byte_order (current_gdbarch);
- release_value (newval);
+ struct type *new_type = check_typedef (value_type (val));
+ union internalvar_data new_data = { 0 };
+
+ if (var->canonical)
+ error (_("Cannot overwrite convenience function %s"), var->name);
+
+ /* Prepare new contents. */
+ switch (TYPE_CODE (new_type))
+ {
+ case TYPE_CODE_VOID:
+ break;
+
+ case TYPE_CODE_INTERNAL_FUNCTION:
+ gdb_assert (VALUE_LVAL (val) == lval_internalvar);
+ get_internalvar_function (VALUE_INTERNALVAR (val), &new_data.f);
+ break;
+
+ case TYPE_CODE_INT:
+ new_data.l = value_as_long (val);
+ break;
+
+ case TYPE_CODE_PTR:
+ new_data.a = value_as_address (val);
+ break;
+
+ default:
+ new_data.v = value_copy (val);
+ new_data.v->modifiable = 1;
+
+ /* Force the value to be fetched from the target now, to avoid problems
+ later when this internalvar is referenced and the target is gone or
+ has changed. */
+ if (value_lazy (new_data.v))
+ value_fetch_lazy (new_data.v);
+
+ /* Release the value from the value chain to prevent it from being
+ deleted by free_all_values. From here on this function should not
+ call error () until new_data is installed into the var->u to avoid
+ leaking memory. */
+ release_value (new_data.v);
+ break;
+ }
+
+ /* Clean up old contents. */
+ clear_internalvar (var);
+
+ /* Switch over. */
+ var->type = new_type;
+ var->u = new_data;
/* End code which must not call error(). */
}
+void
+set_internalvar_integer (struct internalvar *var, LONGEST l)
+{
+ /* Clean up old contents. */
+ clear_internalvar (var);
+
+ /* Use a platform-independent 32-bit integer type. */
+ var->type = builtin_type_int32;
+ var->u.l = l;
+}
+
+static void
+set_internalvar_function (struct internalvar *var, struct internal_function *f)
+{
+ /* Clean up old contents. */
+ clear_internalvar (var);
+
+ var->type = internal_fn_type;
+ var->u.f = f;
+}
+
+void
+clear_internalvar (struct internalvar *var)
+{
+ /* Clean up old contents. */
+ switch (TYPE_CODE (var->type))
+ {
+ case TYPE_CODE_VOID:
+ case TYPE_CODE_INTERNAL_FUNCTION:
+ case TYPE_CODE_INT:
+ case TYPE_CODE_PTR:
+ break;
+
+ default:
+ value_free (var->u.v);
+ break;
+ }
+
+ /* Set to void type. */
+ var->type = builtin_type_void;
+}
+
char *
internalvar_name (struct internalvar *var)
{
return var->name;
}
+static struct internal_function *
+create_internal_function (const char *name,
+ internal_function_fn handler, void *cookie)
+{
+ struct internal_function *ifn = XNEW (struct internal_function);
+ ifn->name = xstrdup (name);
+ ifn->handler = handler;
+ ifn->cookie = cookie;
+ return ifn;
+}
+
+char *
+value_internal_function_name (struct value *val)
+{
+ struct internal_function *ifn;
+ int result;
+
+ gdb_assert (VALUE_LVAL (val) == lval_internalvar);
+ result = get_internalvar_function (VALUE_INTERNALVAR (val), &ifn);
+ gdb_assert (result);
+
+ return ifn->name;
+}
+
+struct value *
+call_internal_function (struct value *func, int argc, struct value **argv)
+{
+ struct internal_function *ifn;
+ int result;
+
+ gdb_assert (VALUE_LVAL (func) == lval_internalvar);
+ result = get_internalvar_function (VALUE_INTERNALVAR (func), &ifn);
+ gdb_assert (result);
+
+ 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 internal_function *ifn;
+ struct internalvar *var = lookup_internalvar (name);
+
+ ifn = create_internal_function (name, handler, cookie);
+ set_internalvar_function (var, ifn);
+ 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 (TYPE_OBJFILE (var->type) == objfile)
+ var->type = copy_type_recursive (objfile, var->type, copied_types);
+
+ switch (TYPE_CODE (var->type))
+ {
+ case TYPE_CODE_VOID:
+ case TYPE_CODE_INTERNAL_FUNCTION:
+ case TYPE_CODE_INT:
+ case TYPE_CODE_PTR:
+ break;
+
+ default:
+ preserve_one_value (var->u.v, objfile, copied_types);
+ break;
+ }
+ }
for (val = values_in_python; val; val = val->next)
preserve_one_value (val, objfile, copied_types);
Upon entry to this function, if VAL is a value of type `function'
(that is, TYPE_CODE (VALUE_TYPE (val)) == TYPE_CODE_FUNC), then
- VALUE_ADDRESS (val) is the address of the function. This is what
+ value_address (val) is the address of the function. This is what
you'll get if you evaluate an expression like `main'. The call
to COERCE_ARRAY below actually does all the usual unary
conversions, which includes converting values of type `function'
function, just return its address directly. */
if (TYPE_CODE (value_type (val)) == TYPE_CODE_FUNC
|| TYPE_CODE (value_type (val)) == TYPE_CODE_METHOD)
- return VALUE_ADDRESS (val);
+ return value_address (val);
val = coerce_array (val);
}
if (retval && VALUE_LVAL (retval) == lval_memory)
SET_FIELD_PHYSADDR (TYPE_FIELD (type, fieldno),
- VALUE_ADDRESS (retval));
+ value_address (retval));
}
return retval;
}
v = allocate_value (ftype);
if (sym)
{
- VALUE_ADDRESS (v) = BLOCK_START (SYMBOL_BLOCK_VALUE (sym));
+ set_value_address (v, BLOCK_START (SYMBOL_BLOCK_VALUE (sym)));
}
else
{
struct objfile *objfile = msymbol_objfile (msym);
struct gdbarch *gdbarch = get_objfile_arch (objfile);
- VALUE_ADDRESS (v)
- = gdbarch_convert_from_func_ptr_addr
- (gdbarch, SYMBOL_VALUE_ADDRESS (msym), ¤t_target);
+ set_value_address (v,
+ gdbarch_convert_from_func_ptr_addr
+ (gdbarch, SYMBOL_VALUE_ADDRESS (msym), ¤t_target));
}
if (arg1p)
set_value_lazy (v, 1);
else
memcpy (value_contents_raw (v), valaddr, TYPE_LENGTH (type));
- VALUE_ADDRESS (v) = address;
+ set_value_address (v, address);
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_NAME (internal_fn_type) = "<internal function>";
}