From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: (qmail 22118 invoked by alias); 6 Feb 2009 23:31:57 -0000 Received: (qmail 22108 invoked by uid 22791); 6 Feb 2009 23:31:56 -0000 X-SWARE-Spam-Status: No, hits=-2.4 required=5.0 tests=AWL,BAYES_00,SPF_PASS X-Spam-Check-By: sourceware.org Received: from mail.codesourcery.com (HELO mail.codesourcery.com) (65.74.133.4) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Fri, 06 Feb 2009 23:31:51 +0000 Received: (qmail 21820 invoked from network); 6 Feb 2009 23:31:48 -0000 Received: from unknown (HELO orlando) (pedro@127.0.0.2) by mail.codesourcery.com with ESMTPA; 6 Feb 2009 23:31:48 -0000 From: Pedro Alves To: gdb-patches@sourceware.org, Eli Zaretskii Subject: Re: [1/2] Inspect extra signal information Date: Fri, 06 Feb 2009 23:31:00 -0000 User-Agent: KMail/1.9.10 References: <200901121846.51709.pedro@codesourcery.com> <200902050114.05103.pedro@codesourcery.com> In-Reply-To: MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit Content-Disposition: inline Message-Id: <200902062332.01141.pedro@codesourcery.com> X-IsSubscribed: yes Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org X-SW-Source: 2009-02/txt/msg00164.txt.bz2 On Thursday 05 February 2009 20:30:36, Eli Zaretskii wrote: > > From: Pedro Alves > > Date: Thu, 5 Feb 2009 01:14:04 +0000 > > > > Does it look OK? > > Yes, but I have a couple of nits: [...] Thanks a lot Eli. I've fixed the nits, and checked this in. -- Pedro Alves gdb/ 2009-02-06 Jim Blandy Daniel Jacobowitz Vladimir Prus Pedro Alves * 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 * gdbint.texinfo (Values): New chapter. --- gdb/defs.h | 5 ++ gdb/doc/gdbint.texinfo | 96 +++++++++++++++++++++++++++++++++++++++++++++++++ gdb/valops.c | 12 +++++- gdb/value.c | 85 +++++++++++++++++++++++++++++++++++++++++-- gdb/value.h | 54 +++++++++++++++++++++++++++ 5 files changed, 247 insertions(+), 5 deletions(-) Index: src/gdb/defs.h =================================================================== --- src.orig/gdb/defs.h 2009-02-06 20:31:15.000000000 +0000 +++ src/gdb/defs.h 2009-02-06 20:40:16.000000000 +0000 @@ -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: src/gdb/value.h =================================================================== --- src.orig/gdb/value.h 2009-02-06 20:39:43.000000000 +0000 +++ src/gdb/value.h 2009-02-06 20:40:16.000000000 +0000 @@ -142,6 +142,60 @@ extern void set_value_pointed_to_offset 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. Index: src/gdb/value.c =================================================================== --- src.orig/gdb/value.c 2009-02-06 20:39:43.000000000 +0000 +++ src/gdb/value.c 2009-02-06 20:40:16.000000000 +0000 @@ -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 **h } } +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 valu 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 val 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 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: src/gdb/valops.c =================================================================== --- src.orig/gdb/valops.c 2009-02-06 20:39:43.000000000 +0000 +++ src/gdb/valops.c 2009-02-06 20:40:16.000000000 +0000 @@ -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, struc 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.")); } Index: src/gdb/doc/gdbint.texinfo =================================================================== --- src.orig/gdb/doc/gdbint.texinfo 2009-02-06 20:39:45.000000000 +0000 +++ src/gdb/doc/gdbint.texinfo 2009-02-06 20:40:16.000000000 +0000 @@ -73,6 +73,7 @@ as the mechanisms that adapt @value{GDBN * Algorithms:: * User Interface:: * libgdb:: +* Values:: * Stack Frames:: * Symbol Handling:: * Language Support:: @@ -1831,6 +1832,101 @@ the query interface. Each function is p 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