gdb
[deliverable/binutils-gdb.git] / gdb / value.c
index 39df98ec918ec1c55d0b342b9b1d962f12926079..9c08a4124f9e79186b88d1c9823546851053c853 100644 (file)
@@ -37,6 +37,7 @@
 #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
@@ -63,6 +81,15 @@ struct value
 
     /* 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.
@@ -194,6 +221,10 @@ struct value_history_chunk
 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)
@@ -296,6 +327,20 @@ value_remove_from_list (struct value **head, struct value *val)
       }
 }
 
+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 *
@@ -458,6 +503,22 @@ set_value_pointed_to_offset (struct value *value, int val)
   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)
 {
@@ -512,7 +573,17 @@ void
 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);
 }
 
@@ -625,8 +696,34 @@ value_copy (struct value *arg)
              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.  */
 
@@ -803,7 +900,7 @@ init_if_undefined_command (char* args, int from_tty)
    the return value is NULL.  */
 
 struct internalvar *
-lookup_only_internalvar (char *name)
+lookup_only_internalvar (const char *name)
 {
   struct internalvar *var;
 
@@ -819,19 +916,39 @@ lookup_only_internalvar (char *name)
    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.
@@ -840,7 +957,7 @@ create_internalvar (char *name)
    one is created, with a void value.  */
 
 struct internalvar *
-lookup_internalvar (char *name)
+lookup_internalvar (const char *name)
 {
   struct internalvar *var;
 
@@ -858,11 +975,32 @@ value_of_internalvar (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
@@ -916,6 +1054,9 @@ set_internalvar (struct internalvar *var, struct value *val)
 {
   struct value *newval;
 
+  if (var->canonical)
+    error (_("Cannot overwrite convenience function %s"), var->name);
+
   newval = value_copy (val);
   newval->modifiable = 1;
 
@@ -927,11 +1068,11 @@ set_internalvar (struct internalvar *var, struct value *val)
 
   /* 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);
@@ -944,6 +1085,76 @@ internalvar_name (struct internalvar *var)
   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.  */
 
@@ -985,7 +1196,8 @@ preserve_values (struct objfile *objfile)
        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);
@@ -1426,10 +1638,7 @@ value_primitive_field (struct value *arg1, int offset,
       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;
@@ -1704,8 +1913,7 @@ value_from_contents_and_address (struct type *type,
   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;
 }
 
@@ -1832,4 +2040,13 @@ init-if-undefined VARIABLE = EXPRESSION\n\
 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>";
 }
This page took 0.039965 seconds and 4 git commands to generate.