gdb/
authorPedro Alves <palves@redhat.com>
Fri, 6 Feb 2009 22:50:52 +0000 (22:50 +0000)
committerPedro Alves <palves@redhat.com>
Fri, 6 Feb 2009 22:50:52 +0000 (22:50 +0000)
2009-02-06  Jim Blandy  <jimb@codesourcery.com>
    Daniel Jacobowitz  <dan@codesourcery.com>
    Vladimir Prus  <vladimir@codesourcery.com>
    Pedro Alves  <pedro@codesourcery.com>

* defs.h (enum lval_type): New value: lval_computed.
* value.h (struct lval_funcs): New type.
(allocate_computed_value, value_computed_funcs)
(value_computed_closure): New declarations.
* value.c (struct value): Add a structure to the location union
for computed lvalues, containing 'funcs' and 'closure' members.
(allocate_computed_value, value_computed_funcs)
(value_computed_closure): New functions.
(value_free): For computed lvalues, call the closure's
'free_closure' function before freeing the value itself.
(value_copy): If we're copying an lval_computed value, call the
closure's 'copy_closure' function.
(set_value_component_location): If the original value is a
computed lvalue, then call the closure's 'copy_closure' function.
(value_of_internalvar): If an internal variable's value is a
computed lvalue, make retrieving its value produce an equivalent
computed lvalue.
* valops.c (value_fetch_lazy): Unlazy computed lvalues by calling
their read function.
(value_assign): Assign to computed lvalues by calling their write
function.

gdb/doc/
2009-02-06  Pedro Alves  <pedro@codesourcery.com>

* gdbint.texinfo (Values): New chapter.

gdb/ChangeLog
gdb/defs.h
gdb/doc/ChangeLog
gdb/doc/gdbint.texinfo
gdb/valops.c
gdb/value.c
gdb/value.h

index aab098d..01e4156 100644 (file)
@@ -1,3 +1,30 @@
+2009-02-06  Jim Blandy  <jimb@codesourcery.com>
+           Daniel Jacobowitz  <dan@codesourcery.com>
+           Vladimir Prus  <vladimir@codesourcery.com>
+           Pedro Alves  <pedro@codesourcery.com>
+
+       * defs.h (enum lval_type): New value: lval_computed.
+       * value.h (struct lval_funcs): New type.
+       (allocate_computed_value, value_computed_funcs)
+       (value_computed_closure): New declarations.
+       * value.c (struct value): Add a structure to the location union
+       for computed lvalues, containing 'funcs' and 'closure' members.
+       (allocate_computed_value, value_computed_funcs)
+       (value_computed_closure): New functions.
+       (value_free): For computed lvalues, call the closure's
+       'free_closure' function before freeing the value itself.
+       (value_copy): If we're copying an lval_computed value, call the
+       closure's 'copy_closure' function.
+       (set_value_component_location): If the original value is a
+       computed lvalue, then call the closure's 'copy_closure' function.
+       (value_of_internalvar): If an internal variable's value is a
+       computed lvalue, make retrieving its value produce an equivalent
+       computed lvalue.
+       * valops.c (value_fetch_lazy): Unlazy computed lvalues by calling
+       their read function.
+       (value_assign): Assign to computed lvalues by calling their write
+       function.
+
 2009-02-06  Pedro Alves  <pedro@codesourcery.com>
 
        * linux-nat.c (linux_nat_wait): Adjust.
index 209b11d..845b320 100644 (file)
@@ -652,7 +652,10 @@ enum lval_type
     /* In a gdb internal variable.  */
     lval_internalvar,
     /* Part of a gdb internal variable (structure field).  */
-    lval_internalvar_component
+    lval_internalvar_component,
+    /* Value's bits are fetched and stored using functions provided by
+       its creator.  */
+    lval_computed
   };
 
 /* Control types for commands */
index 98502db..473c6e3 100644 (file)
@@ -1,3 +1,7 @@
+2009-02-06  Pedro Alves  <pedro@codesourcery.com>
+
+       * gdbint.texinfo (Values): New chapter.
+
 2009-02-06  Tom Tromey  <tromey@redhat.com>
 
        * gdb.texinfo (Python API): Add entry for Commands In Python.
index 849b116..28a223f 100644 (file)
@@ -73,6 +73,7 @@ as the mechanisms that adapt @value{GDBN} to specific hosts and targets.
 * Algorithms::
 * User Interface::
 * libgdb::
+* Values::
 * Stack Frames::
 * Symbol Handling::
 * Language Support::
@@ -1831,6 +1832,101 @@ the query interface.  Each function is parameterized by a @code{ui-out}
 builder.  The result of the query is constructed using that builder
 before the query function returns.
 
+@node Values
+@chapter Values
+@section Values
+
+@cindex values
+@cindex @code{value} structure
+@value{GDBN} uses @code{struct value}, or @dfn{values}, as an internal
+abstraction for the representation of a variety of inferior objects
+and @value{GDBN} convenience objects.
+
+Values have an associated @code{struct type}, that describes a virtual
+view of the raw data or object stored in or accessed through the
+value.
+
+A value is in addition discriminated by its lvalue-ness, given its
+@code{enum lval_type} enumeration type:
+
+@cindex @code{lval_type} enumeration, for values.
+@table @code
+@item @code{not_lval}
+This value is not an lval.  It can't be assigned to.
+
+@item @code{lval_memory}
+This value represents an object in memory.
+
+@item @code{lval_register}
+This value represents an object that lives in a register.
+
+@item @code{lval_internalvar}
+Represents the value of an internal variable.
+
+@item @code{lval_internalvar_component}
+Represents part of a @value{GDBN} internal variable.  E.g., a
+structure field.
+
+@cindex computed values
+@item @code{lval_computed}
+These are ``computed'' values.  They allow creating specialized value
+objects for specific purposes, all abstracted away from the core value
+support code.  The creator of such a value writes specialized
+functions to handle the reading and writing to/from the value's
+backend data, and optionally, a ``copy operator'' and a
+``destructor''.
+
+Pointers to these functions are stored in a @code{struct lval_funcs}
+instance (declared in @file{value.h}), and passed to the
+@code{allocate_computed_value} function, as in the example below.
+
+@smallexample
+static void
+nil_value_read (struct value *v)
+@{
+  /* This callback reads data from some backend, and stores it in V.
+     In this case, we always read null data.  You'll want to fill in
+     something more interesting.  */
+
+  memset (value_contents_all_raw (v),
+          value_offset (v),
+          TYPE_LENGTH (value_type (v)));
+@}
+
+static void
+nil_value_write (struct value *v, struct value *fromval)
+@{
+  /* Takes the data from FROMVAL and stores it in the backend of V.  */
+
+  to_oblivion (value_contents_all_raw (fromval),
+               value_offset (v),
+               TYPE_LENGTH (value_type (fromval)));
+@}
+
+static struct lval_funcs nil_value_funcs =
+  @{
+    nil_value_read,
+    nil_value_write
+  @};
+
+struct value *
+make_nil_value (void)
+@{
+   struct type *type;
+   struct value *v;
+
+   type = make_nils_type ();
+   v = allocate_computed_value (type, &nil_value_funcs, NULL);
+
+   return v;
+@}
+@end smallexample
+
+See the implementation of the @code{$_siginfo} convenience variable in
+@file{infrun.c} as a real example use of lval_computed.
+
+@end table
+
 @node Stack Frames
 @chapter Stack Frames
 
index 09be6dd..9810f2b 100644 (file)
@@ -727,6 +727,8 @@ value_fetch_lazy (struct value *val)
         watchpoints from trying to watch the saved frame pointer.  */
       value_free_to_mark (mark);
     }
+  else if (VALUE_LVAL (val) == lval_computed)
+    value_computed_funcs (val)->read (val);
   else
     internal_error (__FILE__, __LINE__, "Unexpected lazy value type.");
 
@@ -895,7 +897,15 @@ value_assign (struct value *toval, struct value *fromval)
        observer_notify_target_changed (&current_target);
        break;
       }
-      
+
+    case lval_computed:
+      {
+       struct lval_funcs *funcs = value_computed_funcs (toval);
+
+       funcs->write (toval, fromval);
+      }
+      break;
+
     default:
       error (_("Left operand of assignment is not an lvalue."));
     }
index 808d37b..6a9ac5f 100644 (file)
@@ -63,6 +63,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.
@@ -296,6 +305,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 +481,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 +551,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,6 +674,13 @@ 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;
 }
 
@@ -635,7 +691,15 @@ set_value_component_location (struct value *component, struct value *whole)
     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
@@ -872,8 +936,23 @@ value_of_internalvar (struct internalvar *var)
   val = value_copy (var->value);
   if (value_lazy (val))
     value_fetch_lazy (val);
-  VALUE_LVAL (val) = lval_internalvar;
-  VALUE_INTERNALVAR (val) = var;
+
+  /* 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
index 9a11190..0c85223 100644 (file)
@@ -142,6 +142,60 @@ extern void set_value_pointed_to_offset (struct value *value, int val);
 extern int value_embedded_offset (struct value *value);
 extern void set_value_embedded_offset (struct value *value, int val);
 
+/* For lval_computed values, this structure holds functions used to
+   retrieve and set the value (or portions of the value).
+
+   For each function, 'V' is the 'this' pointer: an lval_funcs
+   function F may always assume that the V it receives is an
+   lval_computed value, and has F in the appropriate slot of its
+   lval_funcs structure.  */
+
+struct lval_funcs
+{
+  /* Fill in VALUE's contents.  This is used to "un-lazy" values.  If
+     a problem arises in obtaining VALUE's bits, this function should
+     call 'error'.  */
+  void (*read) (struct value *v);
+
+  /* Handle an assignment TOVAL = FROMVAL by writing the value of
+     FROMVAL to TOVAL's location.  The contents of TOVAL have not yet
+     been updated.  If a problem arises in doing so, this function
+     should call 'error'.  */
+  void (*write) (struct value *toval, struct value *fromval);
+
+  /* Return a duplicate of VALUE's closure, for use in a new value.
+     This may simply return the same closure, if VALUE's is
+     reference-counted or statically allocated.
+
+     This may be NULL, in which case VALUE's closure is re-used in the
+     new value.  */
+  void *(*copy_closure) (struct value *v);
+
+  /* Drop VALUE's reference to its closure.  Maybe this frees the
+     closure; maybe this decrements a reference count; maybe the
+     closure is statically allocated and this does nothing.
+
+     This may be NULL, in which case no action is taken to free
+     VALUE's closure.  */
+  void (*free_closure) (struct value *v);
+};
+
+/* Create a computed lvalue, with type TYPE, function pointers FUNCS,
+   and closure CLOSURE.  */
+
+extern struct value *allocate_computed_value (struct type *type,
+                                              struct lval_funcs *funcs,
+                                              void *closure);
+
+/* If VALUE is lval_computed, return its lval_funcs structure.  */
+
+extern struct lval_funcs *value_computed_funcs (struct value *value);
+
+/* If VALUE is lval_computed, return its closure.  The meaning of the
+   returned value depends on the functions VALUE uses.  */
+
+extern void *value_computed_closure (struct value *value);
+
 /* If zero, contents of this value are in the contents field.  If
    nonzero, contents are in inferior.  If the lval field is lval_memory,
    the contents are in inferior memory at location.address plus offset.