This is the mail archive of the gdb@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Multi-piece values and GDB values


At the moment, GDB doesn't fully support accessing variables whose
values are scattered among several different locations.  Modern
versions of GCC produce such variables more frequently than they used
to, so this has become a problem.  I'd like to talk about a possible
approach for dealing with it.


Background:

Modern versions of GCC may spread the value of a single variable
across several different registers and memory slots.  GCC has located
'long long' variables to pairs of consecutive registers for years, but
now it produces more complicated arrangements.  For example, a 64-bit
variable's first 32 bits might be in a register, while its next 32
bits might be stored in the stack frame.  This arrangement is more
common for variables with struct or class types.

DWARF allows GCC to describe such variables using the DW_OP_piece
operator, which strings together ordinary location expressions, each
describing the location of one piece of the value, into a composite
location expression that describes the entire value.

GDB supports DW_OP_piece in only a limited way.  When asked to produce
the value of a variable whose location is made of several pieces,
dwarf2_evaluate_loc_desc will read each location immediately, and
string the bytes together into a complete value.  However, the
resulting value is not an lvalue, so the user cannot assign new values
to such variables.

There is one special multi-piece case that GDB could support without
much trouble: variables allocated to consecutive registers (in GDB's
register numbering).  GDB register lvalues simply refer to the value's
starting offset in the register cache; if the value's type is larger
than the register, later bytes simply refer to the next register.
This accomodated GCC's long-standing treatment of 'long long' values
described above.  dwarf2_evaluate_loc_desc could recognize this case.
But this is still not a general solution.


Computed lvalues:

At CodeSourcery, we've been experimenting with a new kind of lvalue
which uses callback functions to provide the value's bits when they
are needed, and to assign the value new contents.  Our new
declarations in value.h look like this:


/* 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);

  /* Write an English description of the location of VALUE to STREAM.  */
  void (*describe) (struct value *v, struct ui_file *stream);

  /* 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.
   FIXME: users of this should be private to value.c.  */
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);


Aside from simply writing the new code, implementing this entailed
finding the points in GDB where we created new values that were parts
of old values, and calling the 'copy_closure' function there, as
needed; finding the points where we disposed of values, to call the
'free_closure' function; and finding places where the code assumed
that all lazy values are in memory.  (For the last concern, I think
there's more to be done.)

So, I'd like to suggest that GDB handle DW_OP_piece by representing
the resulting values with lval_computed, using a 'read' function that
gathers up the individual pieces, and a 'write' function that splits
the value back into its original pieces.

I also think it might be nice to re-implement lval_internalvar and
lval_internalvar_component in terms of lval_computed, and removed them
from 'enum lval_type' altogether.  It should be possible for the
callback functions to recognize when a value represents a component of
an internal value, and retain the distinct behaviors currently in
value_assign.

Re-implementing lval_memory and lval_register in terms of
lval_computed would be more involved; especially in the case of
lval_memory, I think it wouldn't actually simplify things much in the
long run.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]