summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorPedro Alves <pedro@codesourcery.com>2009-02-06 22:50:51 +0000
committerPedro Alves <pedro@codesourcery.com>2009-02-06 22:50:51 +0000
commitd0168fb4e09bde9f40830c1a98f47cef3d48980e (patch)
tree43763e416e3f970b00e408b881ee02f64e974923
parentd45fdd4ff235fe067ce5c42291612faf446c7e65 (diff)
downloadgdb-d0168fb4e09bde9f40830c1a98f47cef3d48980e.tar.gz
gdb/
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.
-rw-r--r--gdb/ChangeLog27
-rw-r--r--gdb/defs.h5
-rw-r--r--gdb/doc/ChangeLog4
-rw-r--r--gdb/doc/gdbint.texinfo96
-rw-r--r--gdb/valops.c12
-rw-r--r--gdb/value.c85
-rw-r--r--gdb/value.h54
7 files changed, 278 insertions, 5 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index aab098d3f36..01e4156ecd3 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -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.
diff --git a/gdb/defs.h b/gdb/defs.h
index 209b11d38dd..845b3203f4a 100644
--- a/gdb/defs.h
+++ b/gdb/defs.h
@@ -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 */
diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog
index 98502db39c1..473c6e35890 100644
--- a/gdb/doc/ChangeLog
+++ b/gdb/doc/ChangeLog
@@ -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.
diff --git a/gdb/doc/gdbint.texinfo b/gdb/doc/gdbint.texinfo
index 849b1168b0b..28a223f2ce6 100644
--- a/gdb/doc/gdbint.texinfo
+++ b/gdb/doc/gdbint.texinfo
@@ -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
diff --git a/gdb/valops.c b/gdb/valops.c
index 09be6ddbb5b..9810f2b84a9 100644
--- a/gdb/valops.c
+++ b/gdb/valops.c
@@ -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."));
}
diff --git a/gdb/value.c b/gdb/value.c
index 808d37b8065..6a9ac5ff544 100644
--- a/gdb/value.c
+++ b/gdb/value.c
@@ -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);
+ }
}
@@ -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
diff --git a/gdb/value.h b/gdb/value.h
index 9a11190957b..0c8522382d9 100644
--- a/gdb/value.h
+++ b/gdb/value.h
@@ -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.