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.
This commit is contained in:
parent
117de6a924
commit
5f5233d48e
@ -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.
|
||||
|
@ -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 */
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
||||
|
12
gdb/valops.c
12
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 (¤t_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."));
|
||||
}
|
||||
|
85
gdb/value.c
85
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
|
||||
|
54
gdb/value.h
54
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.
|
||||
|
Loading…
Reference in New Issue
Block a user