* [0/2] Inspect extra signal information
@ 2009-01-12 18:47 Pedro Alves
2009-01-12 18:49 ` Pedro Alves
` (3 more replies)
0 siblings, 4 replies; 53+ messages in thread
From: Pedro Alves @ 2009-01-12 18:47 UTC (permalink / raw)
To: gdb-patches
Hi!
This mini series adds support for inspecting extra signal information.
What this means is, we get a new $_siginfo convenience variable that
is typed to look like the siginfo_t object on unix-ish platforms (but
can be any other type appropriate for the target platform).
E.g., on x86_64-linux,
Program received signal SIGSEGV, Segmentation fault.
0x0000000000400770 in main () at ../../../src/gdb/testsuite/gdb.base/siginfo-obj.c:68
68 *(int *)p = 0;
(gdb) p $_siginfo
$1 = {si_signo = 11, si_errno = 0, si_code = 2, _sifields = {_pad = {-134254592, 32767, 0, 0, 0, 0, 1, 5, 12462832,
0, 4196201, 0, 0, 0, 4196208, 0, 12337488, 0, 12337488, 0, 4196208, 0, 12518720, 0, 12518864, 0, 12518848, 0},
_kill = {si_pid = -134254592, si_uid = 32767}, _timer = {si_tid = -134254592, si_overrun = 32767, si_sigval = {
sival_int = 0, sival_ptr = 0x0}}, _rt = {si_pid = -134254592, si_uid = 32767, si_sigval = {sival_int = 0,
sival_ptr = 0x0}}, _sigchld = {si_pid = -134254592, si_uid = 32767, si_status = 0, si_utime = 0,
si_stime = 4294967296}, _sigfault = {si_addr = 0x7ffff7ff7000}, _sigpoll = {si_band = 140737354100736,
si_fd = 0}}}
(gdb) ptype $_siginfo
type = struct {
int si_signo;
int si_errno;
int si_code;
union {
int _pad[28];
struct {...} _kill;
struct {...} _timer;
struct {...} _rt;
struct {...} _sigchld;
struct {...} _sigfault;
struct {...} _sigpoll;
} _sifields;
}
(gdb) p $_siginfo._sifields._sigfault.si_addr
$2 = (void *) 0x7ffff7ff7000
part 1:
- Adds some infrastracture to be able to register reader and writer
functions that are responsible for reading and writing
a ``struct value'''s value. We called those lval_computed values. We've
been using these kinds of values for other things in our tree for a
couple of years already --- I've piggy-backed on that, so I got to
push it. :-)
This first patch applies on top of this other one:
http://sourceware.org/ml/gdb-patches/2009-01/msg00252.html
part 2:
- Adds a new target object ``TARGET_OBJECT_SIGNAL_INFO'', used to transfer the
siginfo_t data from the target to GDB core.
- Adds a way for a convenience variable's type and value be lazy. This is because
the actual type of the $_siginfo variable may change between archs (across runs, or
across threads).
- Adds a new gdbarch method (get_siginfo_type) whose job is to return a type
suitable to print/inspect a TARGET_OBJECT_SIGNAL_INFO of a given arch.
- Adds the $_siginfo convenience variable, whose type is lval_computed. The read and
writer functions of this lval_computed variable take care of transfering
a TARGET_OBJECT_SIGINFO to/from the target.
- Adds a generic linux implementation of get_siginfo_type, suitable for linux archs
that use the default siginfo_t structure type, and registers it in x86, x86_64
and arm. Other archs that diverge from the default, will need to implement
their own version, which will be very similar to linux_get_siginfo_type.
- Adds linux native target and remote targets implementations of
transfering TARGET_OBJECT_SIGNAL_INFO.
- Adds gdbserver support for same.
- Docs, and,
- New test.
--
Pedro Alves
^ permalink raw reply [flat|nested] 53+ messages in thread* Re: [0/2] Inspect extra signal information 2009-01-12 18:47 [0/2] Inspect extra signal information Pedro Alves @ 2009-01-12 18:49 ` Pedro Alves 2009-01-12 18:52 ` [1/2] " Pedro Alves 2009-01-12 18:50 ` [2/2] " Pedro Alves ` (2 subsequent siblings) 3 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-01-12 18:49 UTC (permalink / raw) To: gdb-patches [-- Attachment #1: Type: text/plain, Size: 591 bytes --] On Monday 12 January 2009 18:46:51, Pedro Alves wrote: > > part 1: > > - Adds some infrastracture to be able to register reader and writer > functions that are responsible for reading and writing > a ``struct value'''s value. We called those lval_computed values. We've > been using these kinds of values for other things in our tree for a > couple of years already --- I've piggy-backed on that, so I got to > push it. :-) > > This first patch applies on top of this other one: > > http://sourceware.org/ml/gdb-patches/2009-01/msg00252.html > -- Pedro Alves [-- Attachment #2: lval_computed.diff --] [-- Type: text/x-diff, Size: 9719 bytes --] 2009-01-12 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/defs.h | 5 ++- gdb/valops.c | 12 +++++++- gdb/value.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- gdb/value.h | 54 +++++++++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 5 deletions(-) Index: gdb/defs.h =================================================================== --- gdb/defs.h.orig 2009-01-11 15:40:11.000000000 +0000 +++ gdb/defs.h 2009-01-12 16:29:28.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: gdb/value.h =================================================================== --- gdb/value.h.orig 2009-01-12 12:40:32.000000000 +0000 +++ gdb/value.h 2009-01-12 16:48:53.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: gdb/value.c =================================================================== --- gdb/value.c.orig 2009-01-12 11:25:23.000000000 +0000 +++ gdb/value.c 2009-01-12 16:48:54.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); + } } \f @@ -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: gdb/valops.c =================================================================== --- gdb/valops.c.orig 2009-01-12 11:25:23.000000000 +0000 +++ gdb/valops.c 2009-01-12 14:21:01.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.")); } ^ permalink raw reply [flat|nested] 53+ messages in thread
* [1/2] Inspect extra signal information 2009-01-12 18:49 ` Pedro Alves @ 2009-01-12 18:52 ` Pedro Alves 2009-01-12 19:40 ` Eli Zaretskii 0 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-01-12 18:52 UTC (permalink / raw) To: gdb-patches [-- Attachment #1: Type: text/plain, Size: 735 bytes --] [ changing the all-mighty subject line this time ... ] On Monday 12 January 2009 18:48:48, Pedro Alves wrote: > On Monday 12 January 2009 18:46:51, Pedro Alves wrote: > > > > part 1: > > > > - Adds some infrastracture to be able to register reader and writer > > functions that are responsible for reading and writing > > a ``struct value'''s value. We called those lval_computed values. We've > > been using these kinds of values for other things in our tree for a > > couple of years already --- I've piggy-backed on that, so I got to > > push it. :-) > > > > This first patch applies on top of this other one: > > > > http://sourceware.org/ml/gdb-patches/2009-01/msg00252.html > > > -- Pedro Alves [-- Attachment #2: lval_computed.diff --] [-- Type: text/x-diff, Size: 9719 bytes --] 2009-01-12 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/defs.h | 5 ++- gdb/valops.c | 12 +++++++- gdb/value.c | 85 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++--- gdb/value.h | 54 +++++++++++++++++++++++++++++++++++++ 4 files changed, 151 insertions(+), 5 deletions(-) Index: gdb/defs.h =================================================================== --- gdb/defs.h.orig 2009-01-11 15:40:11.000000000 +0000 +++ gdb/defs.h 2009-01-12 16:29:28.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: gdb/value.h =================================================================== --- gdb/value.h.orig 2009-01-12 12:40:32.000000000 +0000 +++ gdb/value.h 2009-01-12 16:48:53.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: gdb/value.c =================================================================== --- gdb/value.c.orig 2009-01-12 11:25:23.000000000 +0000 +++ gdb/value.c 2009-01-12 16:48:54.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); + } } \f @@ -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: gdb/valops.c =================================================================== --- gdb/valops.c.orig 2009-01-12 11:25:23.000000000 +0000 +++ gdb/valops.c 2009-01-12 14:21:01.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.")); } ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [1/2] Inspect extra signal information 2009-01-12 18:52 ` [1/2] " Pedro Alves @ 2009-01-12 19:40 ` Eli Zaretskii 2009-02-02 16:51 ` Pedro Alves 0 siblings, 1 reply; 53+ messages in thread From: Eli Zaretskii @ 2009-01-12 19:40 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches > From: Pedro Alves <pedro@codesourcery.com> > Date: Mon, 12 Jan 2009 18:52:06 +0000 > > * 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. I think this introduces a general-purpose infrastructure that must be documented in gdbint.texinfo. ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [1/2] Inspect extra signal information 2009-01-12 19:40 ` Eli Zaretskii @ 2009-02-02 16:51 ` Pedro Alves 2009-02-02 21:04 ` Eli Zaretskii 0 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-02-02 16:51 UTC (permalink / raw) To: gdb-patches, Eli Zaretskii On Monday 12 January 2009 19:39:09, Eli Zaretskii wrote: > > From: Pedro Alves <pedro@codesourcery.com> > > Date: Mon, 12 Jan 2009 18:52:06 +0000 > > > > * 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. > > I think this introduces a general-purpose infrastructure that must be > documented in gdbint.texinfo. > I'm taking a stab at this. I don't see struct value documented in the internals manual though. What kind of detail do you require here? I'm thinking of adding a "Values" section somewhere, don't know where yet. @section Values @value{GDBN} uses @code{struct value}, or simply named a @dfn{value}, 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 data stored in or accessed through the value. A value is in addition descriminated by its lvalue-ness, given its @code{enum lval_type} enumeration: @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 gdb internal variable. E.g., a structure field. @item @code{lval_computed} These are values with arbitrary functions to handle reads and writes, and "copy operators" and "destructors". They allow creating specialized value objects for specific purposes, all abstracted way from the the core value support code. The creator of such a value specifies specialized read, write, copy and release callbacks, described by the @code{struct lval_funcs} struture declared in @file{value.h} to the @code{allocate_computed_value} function. An example use is the implementations of the @code{$_siginfo} convenience variable in @file{infrun.c}. @end table @subsection Lazy values ... -- Pedro Alves ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [1/2] Inspect extra signal information 2009-02-02 16:51 ` Pedro Alves @ 2009-02-02 21:04 ` Eli Zaretskii 2009-02-05 1:14 ` Pedro Alves 0 siblings, 1 reply; 53+ messages in thread From: Eli Zaretskii @ 2009-02-02 21:04 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches > From: Pedro Alves <pedro@codesourcery.com> > Date: Mon, 2 Feb 2009 16:52:27 +0000 > > > I think this introduces a general-purpose infrastructure that must be > > documented in gdbint.texinfo. > > > > I'm taking a stab at this. Thanks! > I don't see struct value documented in > the internals manual though. What kind of detail do you require here? Exactly the kind you described. > I'm thinking of adding a "Values" section somewhere, don't know > where yet. The place doesn't matter much, since the internals manual is "work in progress", and looks more like a car crash than a concise document. > @item @code{lval_computed} > > These are values with arbitrary functions to handle reads and writes, Please lose the empty line between the @item and its description. > and "copy operators" and "destructors". They allow creating Please use ``this kind of quoting'' in Texinfo, not "this kind". > described by the @code{struct lval_funcs} struture declared in ^^^^^^^^ A typo. > @file{value.h} to the @code{allocate_computed_value} function. An What does it mean "declared in value.h to the allocate_computed_value function"? Perhaps add a few words describing `struct lval_funcs', or maybe just showing a simple example would be enough. A couple of index entries for this section will also help. Thanks again for working on this. ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [1/2] Inspect extra signal information 2009-02-02 21:04 ` Eli Zaretskii @ 2009-02-05 1:14 ` Pedro Alves 2009-02-05 20:30 ` Eli Zaretskii 0 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-02-05 1:14 UTC (permalink / raw) To: gdb-patches, Eli Zaretskii [-- Attachment #1: Type: text/plain, Size: 2002 bytes --] On Monday 02 February 2009 21:04:34, Eli Zaretskii wrote: > > From: Pedro Alves <pedro@codesourcery.com> > > I don't see struct value documented in > > the internals manual though. What kind of detail do you require here? > > Exactly the kind you described. Great. > > I'm thinking of adding a "Values" section somewhere, don't know > > where yet. > > The place doesn't matter much, since the internals manual is "work in > progress", and looks more like a car crash than a concise document. > :-) There doesn't seem there's a good way to place it, since values are used for many things, so I made it a new chapter. I placed it even before Stack Frames, because frame handling uses struct value. > > @item @code{lval_computed} > > > > These are values with arbitrary functions to handle reads and writes, > > Please lose the empty line between the @item and its description. > Done. > > and "copy operators" and "destructors". They allow creating > > Please use ``this kind of quoting'' in Texinfo, not "this kind". > Done. ( it shows I didn't write that in emacs :-) ) > > described by the @code{struct lval_funcs} struture declared in > ^^^^^^^^ > A typo. > Fixed. > > @file{value.h} to the @code{allocate_computed_value} function. An > > What does it mean "declared in value.h to the allocate_computed_value > function"? It means I wrote a too long sentence, and lost sense somewhere along the way. :-) "The creator of such a value specifies specialized read (...) callbacks (...) to the @code{allocate_computed_value} function." I've rewriten this. I think it's clearer now. > Perhaps add a few words describing `struct lval_funcs', or maybe just > showing a simple example would be enough. I've added an example. > A couple of index entries for this section will also help. I've added them. > Thanks again for working on this. Thanks for the speedy review. Here's a proper patch. Does it look OK? -- Pedro Alves [-- Attachment #2: lval_computed_docs.diff --] [-- Type: text/x-diff, Size: 3614 bytes --] 2009-02-04 Pedro Alves <pedro@codesourcery.com> * gdbint.texinfo (Values): New chapter. --- gdb/doc/gdbint.texinfo | 95 +++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) Index: src/gdb/doc/gdbint.texinfo =================================================================== --- src.orig/gdb/doc/gdbint.texinfo 2009-02-03 19:20:40.000000000 +0000 +++ src/gdb/doc/gdbint.texinfo 2009-02-05 01:11:31.000000000 +0000 @@ -76,6 +76,7 @@ as the mechanisms that adapt @value{GDBN * Algorithms:: * User Interface:: * libgdb:: +* Values:: * Stack Frames:: * Symbol Handling:: * Language Support:: @@ -1834,6 +1835,100 @@ 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 descriminated 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 gdb 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 way from the 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 ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [1/2] Inspect extra signal information 2009-02-05 1:14 ` Pedro Alves @ 2009-02-05 20:30 ` Eli Zaretskii 2009-02-06 23:31 ` Pedro Alves 0 siblings, 1 reply; 53+ messages in thread From: Eli Zaretskii @ 2009-02-05 20:30 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches > From: Pedro Alves <pedro@codesourcery.com> > Date: Thu, 5 Feb 2009 01:14:04 +0000 > > Here's a proper patch. > > Does it look OK? Yes, but I have a couple of nits: > +A value is in addition descriminated by its lvalue-ness, given its ^^^^^^^^^^^^^ "discriminated" > +Represents part of a gdb internal variable. E.g., a structure field. ^^^ @value{GDBN} > +objects for specific purposes, all abstracted way from the the core ^^^ ^^^^^^^ "way" or "away"? Also, lose the extra "the". Thanks. ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [1/2] Inspect extra signal information 2009-02-05 20:30 ` Eli Zaretskii @ 2009-02-06 23:31 ` Pedro Alves 0 siblings, 0 replies; 53+ messages in thread From: Pedro Alves @ 2009-02-06 23:31 UTC (permalink / raw) To: gdb-patches, Eli Zaretskii On Thursday 05 February 2009 20:30:36, Eli Zaretskii wrote: > > From: Pedro Alves <pedro@codesourcery.com> > > 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 <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/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); + } } \f @@ -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 ^ permalink raw reply [flat|nested] 53+ messages in thread
* [2/2] Inspect extra signal information 2009-01-12 18:47 [0/2] Inspect extra signal information Pedro Alves 2009-01-12 18:49 ` Pedro Alves @ 2009-01-12 18:50 ` Pedro Alves 2009-01-12 19:39 ` Eli Zaretskii 2009-01-12 23:27 ` [0/2] " Mark Kettenis 2009-02-03 15:02 ` Pedro Alves 3 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-01-12 18:50 UTC (permalink / raw) To: gdb-patches [-- Attachment #1: Type: text/plain, Size: 1324 bytes --] On Monday 12 January 2009 18:46:51, Pedro Alves wrote: > part 2: > > - Adds a new target object ``TARGET_OBJECT_SIGNAL_INFO'', used to transfer the > siginfo_t data from the target to GDB core. > > - Adds a way for a convenience variable's type and value be lazy. This is because > the actual type of the $_siginfo variable may change between archs (across runs, or > across threads). > > - Adds a new gdbarch method (get_siginfo_type) whose job is to return a type > suitable to print/inspect a TARGET_OBJECT_SIGNAL_INFO of a given arch. > > - Adds the $_siginfo convenience variable, whose type is lval_computed. The read and > writer functions of this lval_computed variable take care of transfering > a TARGET_OBJECT_SIGINFO to/from the target. > > - Adds a generic linux implementation of get_siginfo_type, suitable for linux archs > that use the default siginfo_t structure type, and registers it in x86, x86_64 > and arm. Other archs that diverge from the default, will need to implement > their own version, which will be very similar to linux_get_siginfo_type. > > - Adds linux native target and remote targets implementations of > transfering TARGET_OBJECT_SIGNAL_INFO. > > - Adds gdbserver support for same. > > - Docs, and, > > - New test. > -- Pedro Alves [-- Attachment #2: siginfo.diff --] [-- Type: text/x-diff, Size: 50997 bytes --] 2009-01-12 Pedro Alves <pedro@codesourcery.com> * target.h (enum target_object): Add new TARGET_OBJECT_SIGNAL_INFO. * infrun.c (siginfo_value_read, siginfo_value_write): New. (siginfo_value_funcs): New. (siginfo_make_value): New. (_initialize_infrun): Create the $_siginfo convenience variable. * gdbtypes.h (append_composite_type_field_aligned): Declare. * gdbtypes.c (append_composite_type_field): Rename to... (append_composite_type_field_aligned): ... this. Add ALIGNMENT argument. Handle it. (append_composite_type_field): Rewrite on top of append_composite_type_field_aligned. * value.h (internalvar_make_value): New typedef. (struct internalvar) <make_value>: New field. (create_internalvar_type_lazy): Declare. * value.c (create_internalvar): Clear make_value. (create_internalvar_type_lazy): New. (value_of_internalvar): If make_value is set use it. (preserve_values): Skip internal variables that don't have a value. * gdbarch.sh (get_siginfo_type): New. * gdbarch.h, gdbarch.c: Regenerate. * linux-tdep.h, linux-tdep.c: New. * amd64-linux-tdep.c: Include "linux-tdep.h". (amd64_linux_init_abi): Register linux_get_siginfo_type and linux_get_siginfo_mapper. * i386-linux-tdep.c: Include "linux-tdep.h". (i386_linux_init_abi): Register linux_get_siginfo_type and linux_get_siginfo_mapper. * arm-linux-tdep.c: Include "linux-tdep.h". (i386_linux_init_abi): Register linux_get_siginfo_type and linux_get_siginfo_mapper. * linux-nat.c (linux_xfer_siginfo): New. (linux_nat_xfer_partial): Handle TARGET_OBJECT_SIGNAL_INFO. * remote.c (PACKET_qXfer_siginfo_read) (PACKET_qXfer_siginfo_write): New. (feature remote_protocol_features): Add "qXfer:siginfo:read" and "qXfer:siginfo:write" features. (remote_xfer_partial): Handle TARGET_OBJECT_SIGNAL_INFO. (_initialize_remote): Add "set/show remote read-siginfo-object" and "set/show remote write-siginfo-object" commands. * Makefile.in (ALL_TARGET_OBS): Add linux-tdep.o. (HFILES_NO_SRCDIR): Add linux-tdep.h. (ALLDEPFILES): Add linux-tdep.c. * configure.tgt (arm*-*-linux* | arm*-*-uclinux*) (i[34567]86-*-linux*, x86_64-*-linux*): Add linux-tdep.o to gdb_target_obs. 2009-01-12 Pedro Alves <pedro@codesourcery.com> gdb/gdbserver/ * server.c (handle_query): Reprot qXfer:siginfo:read and qXfer:siginfo:write as supported and handle them. * target.h (struct target_ops) <qxfer_siginfo>: New field. * linux-low.c (linux_xfer_siginfo): New. (linux_target_ops): Set it. 2009-01-12 Pedro Alves <pedro@codesourcery.com> gdb/doc/ * gdb.texinfo (Signals): Document $_siginfo. (Convenience Variables): Mention $_siginfo. (Remote Configuration): Document qXfer:siginfo:read, qXfer:siginfo:write packets, and the read-siginfo-object, write-siginfo-object commands. 2009-01-12 Pedro Alves <pedro@codesourcery.com> gdb/testsuite/ * gdb.base/siginfo-obj.c, gdb.base/siginfo-obj.exp: New. --- gdb/Makefile.in | 4 gdb/amd64-linux-tdep.c | 3 gdb/arm-linux-tdep.c | 3 gdb/configure.tgt | 6 - gdb/doc/gdb.texinfo | 99 +++++++++++++++++++++++ gdb/gdbarch.c | 33 +++++++ gdb/gdbarch.h | 10 ++ gdb/gdbarch.sh | 5 + gdb/gdbserver/linux-low.c | 39 +++++++++ gdb/gdbserver/server.c | 74 +++++++++++++++++ gdb/gdbserver/target.h | 5 + gdb/gdbtypes.c | 29 +++++- gdb/gdbtypes.h | 4 gdb/i386-linux-tdep.c | 3 gdb/infrun.c | 87 ++++++++++++++++++++ gdb/linux-nat.c | 50 +++++++++++ gdb/linux-tdep.c | 138 +++++++++++++++++++++++++++++++++ gdb/linux-tdep.h | 25 +++++ gdb/remote.c | 25 +++++ gdb/target.h | 5 - gdb/testsuite/gdb.base/siginfo-obj.c | 70 ++++++++++++++++ gdb/testsuite/gdb.base/siginfo-obj.exp | 131 +++++++++++++++++++++++++++++++ gdb/value.c | 62 ++++++++++---- gdb/value.h | 6 + 24 files changed, 887 insertions(+), 29 deletions(-) Index: src/gdb/target.h =================================================================== --- src.orig/gdb/target.h 2009-01-10 14:03:08.000000000 +0000 +++ src/gdb/target.h 2009-01-12 16:30:54.000000000 +0000 @@ -217,7 +217,10 @@ enum target_object TARGET_OBJECT_LIBRARIES, /* Get OS specific data. The ANNEX specifies the type (running processes, etc.). */ - TARGET_OBJECT_OSDATA + TARGET_OBJECT_OSDATA, + /* Extra signal info. Usually the contents of `siginfo_t' on unix + platforms. */ + TARGET_OBJECT_SIGNAL_INFO, /* Possible future objects: TARGET_OBJECT_FILE, ... */ }; Index: src/gdb/infrun.c =================================================================== --- src.orig/gdb/infrun.c 2009-01-10 14:03:08.000000000 +0000 +++ src/gdb/infrun.c 2009-01-12 16:33:32.000000000 +0000 @@ -4764,6 +4764,87 @@ signals_info (char *signum_exp, int from printf_filtered (_("\nUse the \"handle\" command to change these tables.\n")); } + +/* The $_siginfo convenience variable is a bit special. We don't know + for sure the type of the value until we actually have a chance to + fetch the data. The type can change depending on gdbarch, so it it + also dependent on which thread you have selected. + + 1. making $_siginfo be an internalvar that creates a new value on + access. + + 2. making the value of $_siginfo be an lval_computed value. */ + +/* This function implements the lval_computed support for reading a + $_siginfo value. */ + +static void +siginfo_value_read (struct value *v) +{ + LONGEST transferred; + + transferred = + target_read (¤t_target, TARGET_OBJECT_SIGNAL_INFO, + NULL, + value_contents_all_raw (v), + value_offset (v), + TYPE_LENGTH (value_type (v))); + + if (transferred != TYPE_LENGTH (value_type (v))) + error (_("Unable to read siginfo")); +} + +/* This function implements the lval_computed support for writing a + $_siginfo value. */ + +static void +siginfo_value_write (struct value *v, struct value *fromval) +{ + LONGEST transferred; + + transferred = target_write (¤t_target, + TARGET_OBJECT_SIGNAL_INFO, + NULL, + value_contents_all_raw (fromval), + value_offset (v), + TYPE_LENGTH (value_type (fromval))); + + if (transferred != TYPE_LENGTH (value_type (fromval))) + error (_("Unable to write siginfo")); +} + +static struct lval_funcs siginfo_value_funcs = + { + siginfo_value_read, + siginfo_value_write + }; + +/* Return a new value with the correct type for the siginfo object of + the current thread. Return a void value if there's no object + available. */ + +struct value * +siginfo_make_value (struct internalvar *var) +{ + struct type *type; + struct gdbarch *gdbarch; + + if (target_has_stack + && !ptid_equal (inferior_ptid, null_ptid)) + { + gdbarch = get_frame_arch (get_current_frame ()); + + if (gdbarch_get_siginfo_type_p (gdbarch)) + { + type = gdbarch_get_siginfo_type (gdbarch); + + return allocate_computed_value (type, &siginfo_value_funcs, NULL); + } + } + + return allocate_value (builtin_type_void); +} + \f struct inferior_status { @@ -5378,4 +5459,10 @@ Options are 'forward' or 'reverse'."), observer_attach_thread_ptid_changed (infrun_thread_ptid_changed); observer_attach_thread_stop_requested (infrun_thread_stop_requested); + + /* Explicitly create without lookup, since that tries to create a + value with a void typed value, and when we get here, gdbarch + isn't initialized yet. At this point, we're quite sure there + isn't another convenience variable of the same name. */ + create_internalvar_type_lazy ("_siginfo", siginfo_make_value); } Index: src/gdb/gdbtypes.h =================================================================== --- src.orig/gdb/gdbtypes.h 2009-01-10 14:03:08.000000000 +0000 +++ src/gdb/gdbtypes.h 2009-01-12 16:30:54.000000000 +0000 @@ -1112,6 +1112,10 @@ extern struct type *init_type (enum type extern struct type *init_composite_type (char *name, enum type_code code); extern void append_composite_type_field (struct type *t, char *name, struct type *field); +extern void append_composite_type_field_aligned (struct type *t, + char *name, + struct type *field, + int alignment); /* Helper functions to construct a bit flags type. An initially empty type is created using init_flag_type(). Flags are then added using Index: src/gdb/gdbtypes.c =================================================================== --- src.orig/gdb/gdbtypes.c 2009-01-12 11:20:15.000000000 +0000 +++ src/gdb/gdbtypes.c 2009-01-12 16:30:54.000000000 +0000 @@ -1840,8 +1840,8 @@ init_composite_type (char *name, enum ty /* Helper function. Append a field to a composite type. */ void -append_composite_type_field (struct type *t, char *name, - struct type *field) +append_composite_type_field_aligned (struct type *t, char *name, + struct type *field, int alignment) { struct field *f; TYPE_NFIELDS (t) = TYPE_NFIELDS (t) + 1; @@ -1860,12 +1860,31 @@ append_composite_type_field (struct type { TYPE_LENGTH (t) = TYPE_LENGTH (t) + TYPE_LENGTH (field); if (TYPE_NFIELDS (t) > 1) - FIELD_BITPOS (f[0]) = (FIELD_BITPOS (f[-1]) - + (TYPE_LENGTH (FIELD_TYPE (f[-1])) - * TARGET_CHAR_BIT)); + { + FIELD_BITPOS (f[0]) = (FIELD_BITPOS (f[-1]) + + (TYPE_LENGTH (FIELD_TYPE (f[-1])) + * TARGET_CHAR_BIT)); + + if (alignment) + { + int left = FIELD_BITPOS (f[0]) % (alignment * TARGET_CHAR_BIT); + if (left) + { + FIELD_BITPOS (f[0]) += left; + TYPE_LENGTH (t) += left / TARGET_CHAR_BIT; + } + } + } } } +void +append_composite_type_field (struct type *t, char *name, + struct type *field) +{ + append_composite_type_field_aligned (t, name, field, 0); +} + int can_dereference (struct type *t) { Index: src/gdb/value.h =================================================================== --- src.orig/gdb/value.h 2009-01-12 14:28:47.000000000 +0000 +++ src/gdb/value.h 2009-01-12 16:30:54.000000000 +0000 @@ -305,11 +305,14 @@ extern struct value *coerce_array (struc /* Internal variables (variables for convenience of use of debugger) are recorded as a chain of these structures. */ +typedef struct value * (*internalvar_make_value) (struct internalvar *); + struct internalvar { struct internalvar *next; char *name; struct value *value; + internalvar_make_value make_value; int endian; }; @@ -535,6 +538,9 @@ extern struct internalvar *lookup_only_i extern struct internalvar *create_internalvar (char *name); +extern struct internalvar * + create_internalvar_type_lazy (char *name, internalvar_make_value fun); + extern struct internalvar *lookup_internalvar (char *name); extern int value_equal (struct value *arg1, struct value *arg2); Index: src/gdb/value.c =================================================================== --- src.orig/gdb/value.c 2009-01-12 16:29:57.000000000 +0000 +++ src/gdb/value.c 2009-01-12 16:30:54.000000000 +0000 @@ -901,12 +901,31 @@ create_internalvar (char *name) var->name = concat (name, (char *)NULL); var->value = allocate_value (builtin_type_void); var->endian = gdbarch_byte_order (current_gdbarch); + var->make_value = NULL; release_value (var->value); var->next = internalvars; internalvars = var; return var; } +/* Create an internal variable with name NAME and register FUN as the + function that value_of_internalvar uses to create a value whenever + this variable is referenced. NAME should not normally include a + dollar sign. */ + +struct internalvar * +create_internalvar_type_lazy (char *name, internalvar_make_value fun) +{ + struct internalvar *var; + var = (struct internalvar *) xmalloc (sizeof (struct internalvar)); + var->name = concat (name, (char *)NULL); + var->value = NULL; + var->make_value = fun; + var->endian = gdbarch_byte_order (current_gdbarch); + var->next = internalvars; + internalvars = var; + return var; +} /* Look up an internal variable with name NAME. NAME should not normally include a dollar sign. @@ -933,25 +952,31 @@ value_of_internalvar (struct internalvar int i, j; gdb_byte temp; - val = value_copy (var->value); - if (value_lazy (val)) - value_fetch_lazy (val); - - /* 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; + if (var->make_value != NULL) + val = (*var->make_value) (var); else { - VALUE_LVAL (val) = lval_internalvar; - VALUE_INTERNALVAR (val) = var; + val = value_copy (var->value); + if (value_lazy (val)) + value_fetch_lazy (val); + + /* 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 @@ -1075,7 +1100,8 @@ preserve_values (struct objfile *objfile preserve_one_value (cur->values[i], objfile, copied_types); for (var = internalvars; var; var = var->next) - preserve_one_value (var->value, objfile, copied_types); + if (var->value) + preserve_one_value (var->value, objfile, copied_types); for (val = values_in_python; val; val = val->next) preserve_one_value (val, objfile, copied_types); Index: src/gdb/gdbarch.sh =================================================================== --- src.orig/gdb/gdbarch.sh 2009-01-10 14:03:08.000000000 +0000 +++ src/gdb/gdbarch.sh 2009-01-12 16:30:54.000000000 +0000 @@ -705,6 +705,11 @@ m:enum target_signal:target_signal_from_ # signal number. m:int:target_signal_to_host:enum target_signal ts:ts::default_target_signal_to_host::0 +# Extra signal info inspection. +# +# Return a type suitable to inspect extra signal information. +M:struct type *:get_siginfo_type:void: + # Record architecture-specific information from the symbol table. M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym Index: src/gdb/gdbarch.h =================================================================== --- src.orig/gdb/gdbarch.h 2009-01-10 14:03:08.000000000 +0000 +++ src/gdb/gdbarch.h 2009-01-12 16:30:54.000000000 +0000 @@ -803,6 +803,16 @@ typedef int (gdbarch_target_signal_to_ho extern int gdbarch_target_signal_to_host (struct gdbarch *gdbarch, enum target_signal ts); extern void set_gdbarch_target_signal_to_host (struct gdbarch *gdbarch, gdbarch_target_signal_to_host_ftype *target_signal_to_host); +/* Extra signal info inspection. + + Return a type suitable to inspect extra signal information. */ + +extern int gdbarch_get_siginfo_type_p (struct gdbarch *gdbarch); + +typedef struct type * (gdbarch_get_siginfo_type_ftype) (struct gdbarch *gdbarch); +extern struct type * gdbarch_get_siginfo_type (struct gdbarch *gdbarch); +extern void set_gdbarch_get_siginfo_type (struct gdbarch *gdbarch, gdbarch_get_siginfo_type_ftype *get_siginfo_type); + /* Record architecture-specific information from the symbol table. */ extern int gdbarch_record_special_symbol_p (struct gdbarch *gdbarch); Index: src/gdb/gdbarch.c =================================================================== --- src.orig/gdb/gdbarch.c 2009-01-10 14:03:08.000000000 +0000 +++ src/gdb/gdbarch.c 2009-01-12 16:30:54.000000000 +0000 @@ -239,6 +239,7 @@ struct gdbarch int sofun_address_maybe_missing; gdbarch_target_signal_from_host_ftype *target_signal_from_host; gdbarch_target_signal_to_host_ftype *target_signal_to_host; + gdbarch_get_siginfo_type_ftype *get_siginfo_type; gdbarch_record_special_symbol_ftype *record_special_symbol; int has_global_solist; }; @@ -371,6 +372,7 @@ struct gdbarch startup_gdbarch = 0, /* sofun_address_maybe_missing */ default_target_signal_from_host, /* target_signal_from_host */ default_target_signal_to_host, /* target_signal_to_host */ + 0, /* get_siginfo_type */ 0, /* record_special_symbol */ 0, /* has_global_solist */ /* startup_gdbarch() */ @@ -624,6 +626,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of sofun_address_maybe_missing, invalid_p == 0 */ /* Skip verify of target_signal_from_host, invalid_p == 0 */ /* Skip verify of target_signal_to_host, invalid_p == 0 */ + /* Skip verify of get_siginfo_type, has predicate */ /* Skip verify of record_special_symbol, has predicate */ /* Skip verify of has_global_solist, invalid_p == 0 */ buf = ui_file_xstrdup (log, &dummy); @@ -835,6 +838,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s "gdbarch_dump: get_longjmp_target = <%s>\n", host_address_to_string (gdbarch->get_longjmp_target)); fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_get_siginfo_type_p() = %d\n", + gdbarch_get_siginfo_type_p (gdbarch)); + fprintf_unfiltered (file, + "gdbarch_dump: get_siginfo_type = <0x%lx>\n", + (long) gdbarch->get_siginfo_type); + fprintf_unfiltered (file, "gdbarch_dump: has_global_solist = %s\n", plongest (gdbarch->has_global_solist)); fprintf_unfiltered (file, @@ -3220,6 +3229,30 @@ set_gdbarch_target_signal_to_host (struc } int +gdbarch_get_siginfo_type_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->get_siginfo_type != NULL; +} + +struct type * +gdbarch_get_siginfo_type (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->get_siginfo_type != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_get_siginfo_type called\n"); + return gdbarch->get_siginfo_type (gdbarch); +} + +void +set_gdbarch_get_siginfo_type (struct gdbarch *gdbarch, + gdbarch_get_siginfo_type_ftype get_siginfo_type) +{ + gdbarch->get_siginfo_type = get_siginfo_type; +} + +int gdbarch_record_special_symbol_p (struct gdbarch *gdbarch) { gdb_assert (gdbarch != NULL); Index: src/gdb/linux-tdep.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ src/gdb/linux-tdep.h 2009-01-12 16:39:10.000000000 +0000 @@ -0,0 +1,25 @@ +/* Target-dependent code for GNU/Linux, architecture independent. + + Copyright (C) 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef LINUX_TDEP_H +#define LINUX_TDEP_H + +struct type *linux_get_siginfo_type (struct gdbarch *); + +#endif /* linux-tdep.h */ Index: src/gdb/linux-tdep.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ src/gdb/linux-tdep.c 2009-01-12 16:38:44.000000000 +0000 @@ -0,0 +1,138 @@ +/* Target-dependent code for GNU/Linux, architecture independent. + + Copyright (C) 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "defs.h" +#include "gdbtypes.h" + +/* This function is suitable for architectures that don't + extend/override the standard siginfo structure. */ + +struct type * +linux_get_siginfo_type (struct gdbarch *gdbarch) +{ + struct type *int_type, *uint_type, *long_type, *void_ptr_type; + struct type *uid_type, *pid_type; + struct type *sigval_type, *clock_type; + struct type *siginfo_type, *sifields_type; + struct type *type; + + int_type = init_type (TYPE_CODE_INT, + gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT, + 0, "int", NULL); + uint_type = init_type (TYPE_CODE_INT, + gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT, + 0, "unsigned int", NULL); + long_type = init_type (TYPE_CODE_INT, + gdbarch_long_bit (gdbarch) / HOST_CHAR_BIT, + 0, "long", NULL); + void_ptr_type = lookup_pointer_type (builtin_type (gdbarch)->builtin_void); + + /* sival_t */ + sigval_type = init_composite_type (NULL, TYPE_CODE_UNION); + TYPE_NAME (sigval_type) = xstrdup ("sigval_t"); + append_composite_type_field (sigval_type, "sival_int", int_type); + append_composite_type_field (sigval_type, "sival_ptr", void_ptr_type); + + /* __pid_t */ + pid_type = init_type (TYPE_CODE_TYPEDEF, TYPE_LENGTH (int_type), + TYPE_FLAG_TARGET_STUB, NULL, NULL); + TYPE_NAME (pid_type) = xstrdup ("__pid_t"); + TYPE_TARGET_TYPE (pid_type) = int_type; + + /* __uid_t */ + uid_type = init_type (TYPE_CODE_TYPEDEF, TYPE_LENGTH (uint_type), + TYPE_FLAG_TARGET_STUB, NULL, NULL); + TYPE_NAME (uid_type) = xstrdup ("__uid_t"); + TYPE_TARGET_TYPE (uid_type) = uint_type; + + /* __clock_t */ + clock_type = init_type (TYPE_CODE_TYPEDEF, TYPE_LENGTH (long_type), + TYPE_FLAG_TARGET_STUB, NULL, NULL); + TYPE_NAME (clock_type) = xstrdup ("__clock_t"); + TYPE_TARGET_TYPE (clock_type) = long_type; + + /* _sifields */ + sifields_type = init_composite_type (NULL, TYPE_CODE_UNION); + + { + const int si_max_size = 128; + int si_pad_size; + int size_of_int = gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT; + + /* _pad */ + if (gdbarch_ptr_bit (gdbarch) == 64) + si_pad_size = (si_max_size / size_of_int) - 4; + else + si_pad_size = (si_max_size / size_of_int) - 3; + append_composite_type_field (sifields_type, "_pad", + init_vector_type (int_type, si_pad_size)); + } + + /* _kill */ + type = init_composite_type (NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "si_pid", pid_type); + append_composite_type_field (type, "si_uid", uid_type); + append_composite_type_field (sifields_type, "_kill", type); + + /* _timer */ + type = init_composite_type (NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "si_tid", int_type); + append_composite_type_field (type, "si_overrun", int_type); + append_composite_type_field (type, "si_sigval", sigval_type); + append_composite_type_field (sifields_type, "_timer", type); + + /* _rt */ + type = init_composite_type (NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "si_pid", pid_type); + append_composite_type_field (type, "si_uid", uid_type); + append_composite_type_field (type, "si_sigval", sigval_type); + append_composite_type_field (sifields_type, "_rt", type); + + /* _sigchld */ + type = init_composite_type (NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "si_pid", pid_type); + append_composite_type_field (type, "si_uid", uid_type); + append_composite_type_field (type, "si_status", int_type); + append_composite_type_field (type, "si_utime", clock_type); + append_composite_type_field (type, "si_stime", clock_type); + append_composite_type_field (sifields_type, "_sigchld", type); + + /* _sigfault */ + type = init_composite_type (NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "si_addr", void_ptr_type); + append_composite_type_field (sifields_type, "_sigfault", type); + + /* _sigpoll */ + type = init_composite_type (NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "si_band", long_type); + append_composite_type_field (type, "si_fd", int_type); + append_composite_type_field (sifields_type, "_sigpoll", type); + + /* struct siginfo */ + siginfo_type = init_composite_type (NULL, TYPE_CODE_STRUCT); + TYPE_NAME (siginfo_type) = xstrdup ("siginfo"); + append_composite_type_field (siginfo_type, "si_signo", int_type); + append_composite_type_field (siginfo_type, "si_errno", int_type); + append_composite_type_field (siginfo_type, "si_code", int_type); + append_composite_type_field_aligned (siginfo_type, + "_sifields", sifields_type, + TYPE_LENGTH (long_type)); + + return siginfo_type; +} Index: src/gdb/amd64-linux-tdep.c =================================================================== --- src.orig/gdb/amd64-linux-tdep.c 2009-01-10 14:03:08.000000000 +0000 +++ src/gdb/amd64-linux-tdep.c 2009-01-12 16:30:54.000000000 +0000 @@ -28,6 +28,7 @@ #include "gdbtypes.h" #include "reggroups.h" #include "amd64-linux-tdep.h" +#include "linux-tdep.h" #include "gdb_string.h" @@ -286,6 +287,8 @@ amd64_linux_init_abi (struct gdbarch_inf /* Enable TLS support. */ set_gdbarch_fetch_tls_load_module_address (gdbarch, svr4_fetch_objfile_link_map); + + set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type); } \f Index: src/gdb/i386-linux-tdep.c =================================================================== --- src.orig/gdb/i386-linux-tdep.c 2009-01-10 14:03:08.000000000 +0000 +++ src/gdb/i386-linux-tdep.c 2009-01-12 16:30:54.000000000 +0000 @@ -31,6 +31,7 @@ #include "i386-tdep.h" #include "i386-linux-tdep.h" +#include "linux-tdep.h" #include "glibc-tdep.h" #include "solib-svr4.h" #include "symtab.h" @@ -469,6 +470,8 @@ i386_linux_init_abi (struct gdbarch_info simple_displaced_step_free_closure); set_gdbarch_displaced_step_location (gdbarch, displaced_step_at_entry_point); + + set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type); } /* Provide a prototype to silence -Wmissing-prototypes. */ Index: src/gdb/arm-linux-tdep.c =================================================================== --- src.orig/gdb/arm-linux-tdep.c 2009-01-10 14:03:08.000000000 +0000 +++ src/gdb/arm-linux-tdep.c 2009-01-12 16:30:54.000000000 +0000 @@ -36,6 +36,7 @@ #include "arm-tdep.h" #include "arm-linux-tdep.h" +#include "linux-tdep.h" #include "glibc-tdep.h" #include "gdb_string.h" @@ -647,6 +648,8 @@ arm_linux_init_abi (struct gdbarch_info /* Core file support. */ set_gdbarch_regset_from_core_section (gdbarch, arm_linux_regset_from_core_section); + + set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type); } void Index: src/gdb/linux-nat.c =================================================================== --- src.orig/gdb/linux-nat.c 2009-01-10 14:03:08.000000000 +0000 +++ src/gdb/linux-nat.c 2009-01-12 16:30:54.000000000 +0000 @@ -3215,14 +3215,62 @@ linux_nat_mourn_inferior (struct target_ } static LONGEST +linux_xfer_siginfo (struct target_ops *ops, enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, ULONGEST offset, LONGEST len) +{ + struct lwp_info *lp; + LONGEST n; + int pid; + struct siginfo siginfo; + + gdb_assert (object == TARGET_OBJECT_SIGNAL_INFO); + gdb_assert (readbuf || writebuf); + + pid = GET_LWP (inferior_ptid); + if (pid == 0) + pid = GET_PID (inferior_ptid); + + if (offset > sizeof (siginfo)) + return -1; + + errno = 0; + ptrace (PTRACE_GETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo); + if (errno != 0) + return -1; + + if (offset + len > sizeof (siginfo)) + len = sizeof (siginfo) - offset; + + if (readbuf != NULL) + memcpy (readbuf, (char *)&siginfo + offset, len); + else + { + memcpy ((char *)&siginfo + offset, writebuf, len); + errno = 0; + ptrace (PTRACE_SETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo); + if (errno != 0) + return -1; + } + + return len; +} + +static LONGEST linux_nat_xfer_partial (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf, ULONGEST offset, LONGEST len) { - struct cleanup *old_chain = save_inferior_ptid (); + struct cleanup *old_chain; LONGEST xfer; + if (object == TARGET_OBJECT_SIGNAL_INFO) + return linux_xfer_siginfo (ops, object, annex, readbuf, writebuf, + offset, len); + + old_chain = save_inferior_ptid (); + if (is_lwp (inferior_ptid)) inferior_ptid = pid_to_ptid (GET_LWP (inferior_ptid)); Index: src/gdb/remote.c =================================================================== --- src.orig/gdb/remote.c 2009-01-10 14:03:08.000000000 +0000 +++ src/gdb/remote.c 2009-01-12 16:30:54.000000000 +0000 @@ -1001,6 +1001,8 @@ enum { PACKET_vRun, PACKET_QStartNoAckMode, PACKET_vKill, + PACKET_qXfer_siginfo_read, + PACKET_qXfer_siginfo_write, PACKET_MAX }; @@ -2965,6 +2967,10 @@ static struct protocol_feature remote_pr PACKET_QStartNoAckMode }, { "multiprocess", PACKET_DISABLE, remote_multi_process_feature, -1 }, { "QNonStop", PACKET_DISABLE, remote_non_stop_feature, -1 }, + { "qXfer:siginfo:read", PACKET_DISABLE, remote_supported_packet, + PACKET_qXfer_siginfo_read }, + { "qXfer:siginfo:write", PACKET_DISABLE, remote_supported_packet, + PACKET_qXfer_siginfo_write }, }; static void @@ -7300,6 +7306,19 @@ remote_xfer_partial (struct target_ops * [PACKET_qXfer_spu_write]); } + /* Handle extra signal info using qxfer packets. */ + if (object == TARGET_OBJECT_SIGNAL_INFO) + { + if (readbuf) + return remote_read_qxfer (ops, "siginfo", annex, readbuf, offset, len, + &remote_protocol_packets + [PACKET_qXfer_siginfo_read]); + else + return remote_write_qxfer (ops, "siginfo", annex, writebuf, offset, len, + &remote_protocol_packets + [PACKET_qXfer_siginfo_write]); + } + /* Only handle flash writes. */ if (writebuf != NULL) { @@ -9056,6 +9075,12 @@ Show the maximum size of the address (in add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_osdata], "qXfer:osdata:read", "osdata", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_siginfo_read], + "qXfer:siginfo:read", "read-siginfo-object", 0); + + add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_siginfo_write], + "qXfer:siginfo:write", "write-siginfo-object", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTLSAddr], "qGetTLSAddr", "get-thread-local-storage-address", 0); Index: src/gdb/Makefile.in =================================================================== --- src.orig/gdb/Makefile.in 2009-01-12 11:21:46.000000000 +0000 +++ src/gdb/Makefile.in 2009-01-12 16:31:52.000000000 +0000 @@ -481,6 +481,7 @@ ALL_TARGET_OBS = \ i386-sol2-tdep.o i386-tdep.o i387-tdep.o \ i386-dicos-tdep.o \ iq2000-tdep.o \ + linux-tdep.o \ m32c-tdep.o \ m32r-linux-tdep.o m32r-tdep.o \ m68hc11-tdep.o \ @@ -728,7 +729,7 @@ config/sparc/nm-sol2.h config/nm-linux.h config/rs6000/nm-rs6000.h top.h bsd-kvm.h gdb-stabs.h reggroups.h \ annotate.h sim-regno.h dictionary.h dfp.h main.h frame-unwind.h \ remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \ -sentinel-frame.h bcache.h symfile.h windows-tdep.h +sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h # Header files that already have srcdir in them, or which are in objdir. @@ -1299,6 +1300,7 @@ ALLDEPFILES = \ irix5-nat.c \ libunwind-frame.c \ linux-fork.c \ + linux-tdep.c \ m68hc11-tdep.c \ m32r-tdep.c \ m32r-linux-nat.c m32r-linux-tdep.c \ Index: src/gdb/configure.tgt =================================================================== --- src.orig/gdb/configure.tgt 2009-01-12 11:21:47.000000000 +0000 +++ src/gdb/configure.tgt 2009-01-12 16:30:54.000000000 +0000 @@ -75,7 +75,7 @@ arm*-wince-pe | arm*-*-mingw32ce*) arm*-*-linux*) # Target: ARM based machine running GNU/Linux gdb_target_obs="arm-tdep.o arm-linux-tdep.o glibc-tdep.o \ - solib.o solib-svr4.o symfile-mem.o corelow.o" + solib.o solib-svr4.o symfile-mem.o corelow.o linux-tdep.o" build_gdbserver=yes ;; arm*-*-netbsd* | arm*-*-knetbsd*-gnu) @@ -190,7 +190,7 @@ i[34567]86-*-solaris*) i[34567]86-*-linux*) # Target: Intel 386 running GNU/Linux gdb_target_obs="i386-tdep.o i386-linux-tdep.o glibc-tdep.o i387-tdep.o \ - solib.o solib-svr4.o symfile-mem.o corelow.o" + solib.o solib-svr4.o symfile-mem.o corelow.o linux-tdep.o" build_gdbserver=yes ;; i[34567]86-*-gnu*) @@ -513,7 +513,7 @@ x86_64-*-linux*) # Target: GNU/Linux x86-64 gdb_target_obs="amd64-tdep.o amd64-linux-tdep.o i386-tdep.o \ i387-tdep.o i386-linux-tdep.o glibc-tdep.o \ - solib.o solib-svr4.o corelow.o symfile-mem.o" + solib.o solib-svr4.o corelow.o symfile-mem.o linux-tdep.o" build_gdbserver=yes ;; x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) Index: src/gdb/gdbserver/server.c =================================================================== --- src.orig/gdb/gdbserver/server.c 2009-01-10 14:03:08.000000000 +0000 +++ src/gdb/gdbserver/server.c 2009-01-12 16:30:54.000000000 +0000 @@ -800,6 +800,77 @@ handle_query (char *own_buf, int packet_ return; } + if (the_target->qxfer_siginfo != NULL + && strncmp ("qXfer:siginfo:read:", own_buf, 19) == 0) + { + unsigned char *data; + int n; + CORE_ADDR ofs; + unsigned int len; + char *annex; + + require_running (own_buf); + + /* Reject any annex; grab the offset and length. */ + if (decode_xfer_read (own_buf + 19, &annex, &ofs, &len) < 0 + || annex[0] != '\0') + { + strcpy (own_buf, "E00"); + return; + } + + /* Read one extra byte, as an indicator of whether there is + more. */ + if (len > PBUFSIZ - 2) + len = PBUFSIZ - 2; + data = malloc (len + 1); + if (!data) + return; + n = (*the_target->qxfer_siginfo) (annex, data, NULL, ofs, len + 1); + if (n < 0) + write_enn (own_buf); + else if (n > len) + *new_packet_len_p = write_qxfer_response (own_buf, data, len, 1); + else + *new_packet_len_p = write_qxfer_response (own_buf, data, n, 0); + + free (data); + return; + } + + if (the_target->qxfer_siginfo != NULL + && strncmp ("qXfer:siginfo:write:", own_buf, 20) == 0) + { + char *annex; + int n; + unsigned int len; + CORE_ADDR ofs; + unsigned char *data; + + require_running (own_buf); + + strcpy (own_buf, "E00"); + data = malloc (packet_len - 19); + if (!data) + return; + if (decode_xfer_write (own_buf + 20, packet_len - 20, &annex, + &ofs, &len, data) < 0) + { + free (data); + return; + } + + n = (*the_target->qxfer_siginfo) + (annex, NULL, (unsigned const char *)data, ofs, len); + if (n < 0) + write_enn (own_buf); + else + sprintf (own_buf, "%x", n); + + free (data); + return; + } + /* Protocol features query. */ if (strncmp ("qSupported", own_buf, 10) == 0 && (own_buf[10] == ':' || own_buf[10] == '\0')) @@ -816,6 +887,9 @@ handle_query (char *own_buf, int packet_ if (the_target->qxfer_spu != NULL) strcat (own_buf, ";qXfer:spu:read+;qXfer:spu:write+"); + if (the_target->qxfer_siginfo != NULL) + strcat (own_buf, ";qXfer:siginfo:read+;qXfer:siginfo:write+"); + /* We always report qXfer:features:read, as targets may install XML files on a subsequent call to arch_setup. If we reported to GDB on startup that we don't support Index: src/gdb/gdbserver/target.h =================================================================== --- src.orig/gdb/gdbserver/target.h 2009-01-10 14:03:08.000000000 +0000 +++ src/gdb/gdbserver/target.h 2009-01-12 16:30:54.000000000 +0000 @@ -193,6 +193,11 @@ struct target_ops int (*qxfer_osdata) (const char *annex, unsigned char *readbuf, unsigned const char *writebuf, CORE_ADDR offset, int len); + + /* Read/Write extra signal info. */ + int (*qxfer_siginfo) (const char *annex, unsigned char *readbuf, + unsigned const char *writebuf, + CORE_ADDR offset, int len); }; extern struct target_ops *the_target; Index: src/gdb/gdbserver/linux-low.c =================================================================== --- src.orig/gdb/gdbserver/linux-low.c 2009-01-10 14:03:08.000000000 +0000 +++ src/gdb/gdbserver/linux-low.c 2009-01-12 16:30:54.000000000 +0000 @@ -2180,6 +2180,44 @@ linux_qxfer_osdata (const char *annex, return len; } +static int +linux_xfer_siginfo (const char *annex, unsigned char *readbuf, + unsigned const char *writebuf, CORE_ADDR offset, int len) +{ + struct siginfo siginfo; + long pid = -1; + + if (current_inferior == NULL) + return -1; + + pid = pid_of (get_thread_process (current_inferior)); + + if (debug_threads) + fprintf (stderr, "%s siginfo for lwp %ld.\n", + readbuf != NULL ? "Reading" : "Writing", + pid); + + if (offset > sizeof (siginfo)) + return -1; + + if (ptrace (PTRACE_GETSIGINFO, pid, 0, &siginfo) != 0) + return -1; + + if (offset + len > sizeof (siginfo)) + len = sizeof (siginfo) - offset; + + if (readbuf != NULL) + memcpy (readbuf, (char *) &siginfo + offset, len); + else + { + memcpy ((char *) &siginfo + offset, writebuf, len); + if (ptrace (PTRACE_SETSIGINFO, pid, 0, &siginfo) != 0) + return -1; + } + + return len; +} + static struct target_ops linux_target_ops = { linux_create_inferior, linux_attach, @@ -2213,6 +2251,7 @@ static struct target_ops linux_target_op NULL, hostio_last_error_from_errno, linux_qxfer_osdata, + linux_xfer_siginfo, }; static void Index: src/gdb/doc/gdb.texinfo =================================================================== --- src.orig/gdb/doc/gdb.texinfo 2009-01-10 14:03:08.000000000 +0000 +++ src/gdb/doc/gdb.texinfo 2009-01-12 16:30:54.000000000 +0000 @@ -4473,6 +4473,55 @@ a result of the fatal signal once it saw you can continue with @samp{signal 0}. @xref{Signaling, ,Giving your Program a Signal}. +@cindex inspecting extra signal information +@anchor{inspecting extra signal information} + +On some targets, @value{GDBN} can inspect extra signal information +associated with the intercepted signal, before it is actually +delivered to the program being debugged. This information is exported +by the convenience variable @code{$_siginfo}, and consists of data +that is passed by the kernel to the signal handler at the time of the +receipt of a signal. The data type of the information itself is +target dependent. You can see the data type using the @code{ptype +$_siginfo} command. On Unix systems, it typically corresponds to the +standard @code{siginfo_t} type, as defined in the @file{signal.h} +system header. + +Here's an example, on a @sc{gnu}/Linux system, printing the stray +referenced address that raised a segmentation fault. + +@smallexample +@group +(@value{GDBP}) continue +Program received signal SIGSEGV, Segmentation fault. +0x0000000000400766 in main () +69 *(int *)p = 0; +(@value{GDBP}) ptype $_siginfo +type = struct @{ + int si_signo; + int si_errno; + int si_code; + union @{ + int _pad[28]; + struct @{...@} _kill; + struct @{...@} _timer; + struct @{...@} _rt; + struct @{...@} _sigchld; + struct @{...@} _sigfault; + struct @{...@} _sigpoll; + @} _sifields; +@} +(@value{GDBP}) ptype $_siginfo._sifields._sigfault +type = struct @{ + void *si_addr; +@} +(@value{GDBP}) p $_siginfo._sifields._sigfault.si_addr +$1 = (void *) 0x7ffff7ff7000 +@end group +@end smallexample + +Depending on target support, @code{$_siginfo} may also be writable. + @node Thread Stops @section Stopping and Starting Multi-thread Programs @@ -7345,6 +7394,11 @@ to match the format in which the data wa @vindex $_exitcode@r{, convenience variable} The variable @code{$_exitcode} is automatically set to the exit code when the program being debugged terminates. + +@item $_siginfo +@vindex $_siginfo@r{, convenience variable} +The variable @code{$_siginfo} is bound to extra signal information +inspection (@pxref{inspecting extra signal information}). @end table On HP-UX systems, if you refer to a function or variable name that @@ -14303,6 +14357,14 @@ are: @tab @code{qXfer:spu:write} @tab @code{info spu} +@item @code{read-siginfo-object} +@tab @code{qXfer:siginfo:read} +@tab @code{print $_siginfo} + +@item @code{write-siginfo-object} +@tab @code{qXfer:siginfo:write} +@tab @code{set $_siginfo} + @item @code{get-thread-local-@*storage-address} @tab @code{qGetTLSAddr} @tab Displaying @code{__thread} variables @@ -26513,6 +26575,16 @@ These are the currently defined stub fea @tab @samp{-} @tab Yes +@item @samp{qXfer:siginfo:read} +@tab No +@tab @samp{-} +@tab Yes + +@item @samp{qXfer:siginfo:write} +@tab No +@tab @samp{-} +@tab Yes + @item @samp{QNonStop} @tab No @tab @samp{-} @@ -26573,6 +26645,14 @@ The remote stub understands the @samp{qX The remote stub understands the @samp{qXfer:spu:write} packet (@pxref{qXfer spu write}). +@item qXfer:siginfo:read +The remote stub understands the @samp{qXfer:siginfo:read} packet +(@pxref{qXfer spu read}). + +@item qXfer:siginfo:write +The remote stub understands the @samp{qXfer:siginfo:write} packet +(@pxref{qXfer spu write}). + @item QNonStop The remote stub understands the @samp{QNonStop} packet (@pxref{QNonStop}). @@ -26783,6 +26863,7 @@ the stub, or that the object does not su @item qXfer:@var{object}:write:@var{annex}:@var{offset}:@var{data}@dots{} @cindex write data into object, remote request +@anchor{qXfer write} Write uninterpreted bytes into the target's special data area identified by the keyword @var{object}, starting at @var{offset} bytes into the data. @var{data}@dots{} is the binary-encoded data @@ -26805,6 +26886,24 @@ in that context to be accessed. This packet is not probed by default; the remote stub must request it, by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). + +@item qXfer:siginfo:read:@var{annex}:@var{offset},@var{length} +@anchor{qXfer siginfo read} +Read contents of the extra signal information on the target +system. The annex part of the generic @samp{qXfer} packet must be +empty (@pxref{qXfer read}). + +This packet is not probed by default; the remote stub must request it, +by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). + +@item qXfer:@var{siginfo}:write:@var{annex}:@var{offset}:@var{data}@dots{} +@anchor{qXfer siginfo write} +Write @var{data} to the extra signal information on the target system. +The annex part of the generic @samp{qXfer} packet must be +empty (@pxref{qXfer write}). + +This packet is not probed by default; the remote stub must request it, +by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). @end table Reply: Index: src/gdb/testsuite/gdb.base/siginfo-obj.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ src/gdb/testsuite/gdb.base/siginfo-obj.c 2009-01-12 16:30:54.000000000 +0000 @@ -0,0 +1,70 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2004, 2007, 2008 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <unistd.h> + +static void *p; + +static void +handler (int sig, siginfo_t *info, void *context) +{ + /* Copy to local vars, as the test wants to read them, and si_addr, + etc. may be preprocessor defines. */ + int ssi_errno = info->si_errno; + int ssi_signo = info->si_signo; + int ssi_code = info->si_code; + void *ssi_addr = info->si_addr; + + _exit (0); /* set breakpoint here */ +} + +int +main (void) +{ + /* Set up unwritable memory. */ + { + size_t len; + len = sysconf(_SC_PAGESIZE); + p = mmap (0, len, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); + if (p == MAP_FAILED) + { + perror ("mmap"); + return 1; + } + } + /* Set up the signal handler. */ + { + struct sigaction action; + memset (&action, 0, sizeof (action)); + action.sa_sigaction = handler; + action.sa_flags |= SA_SIGINFO; + if (sigaction (SIGSEGV, &action, NULL)) + { + perror ("sigaction"); + return 1; + } + } + /* Trigger SIGSEGV. */ + *(int *)p = 0; + return 0; +} Index: src/gdb/testsuite/gdb.base/siginfo-obj.exp =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ src/gdb/testsuite/gdb.base/siginfo-obj.exp 2009-01-12 16:30:54.000000000 +0000 @@ -0,0 +1,131 @@ +# Copyright 2004, 2007, 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +# The program siginfo-obj.c arranges for a signal handler registered +# using sigaction's sa_sigaction / SA_SIGINFO to be called with +# si_addr filled in. + +# This test confirms that we can inspect signal info using the +# $_siginfo convenience variable. + +if [target_info exists gdb,nosignals] { + verbose "Skipping siginfo-obj.exp because of nosignals." + continue +} + +if { ! [istarget "i?86-*-linux*"] + && ! [istarget "x86_64-*-linux*"] + && ! [istarget "arm*-*-linux*"] } { + verbose "Skipping siginfo-obj.exp because of lack of support." + return +} + +if $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +set testfile siginfo-obj +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile ${srcfile}.c" + return -1 +} + +# get things started +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +# Advance to main +if { ![runto_main] } then { + gdb_suppress_tests; +} + +# Run to the signal. +gdb_test "continue" ".*Program received signal SIGSEGV.*" "continue to signal" + +set ssi_addr "" +set test "Extract si_addr" +gdb_test_multiple "p \$_siginfo" "$test" { + -re "si_addr = ($hex).*$gdb_prompt $" { + set ssi_addr $expect_out(1,string) + pass "$test" + } +} + +set test "Extract si_errno" +gdb_test_multiple "p \$_siginfo" "$test" { + -re "si_errno = (\[0-9\]\+).*$gdb_prompt $" { + set ssi_errno $expect_out(1,string) + pass "$test" + } +} + +set test "Extract si_code" +gdb_test_multiple "p \$_siginfo" "$test" { + -re "si_code = (\[0-9\]\+).*$gdb_prompt $" { + set ssi_code $expect_out(1,string) + pass "$test" + } +} + +set test "Extract si_signo" +gdb_test_multiple "p \$_siginfo" "$test" { + -re "si_signo = (\[0-9\]\+).*$gdb_prompt $" { + set ssi_signo $expect_out(1,string) + pass "$test" + } +} + +set bp_location [gdb_get_line_number "set breakpoint here"] + +gdb_test "break $bp_location" +gdb_test "continue" ".* handler .*" "continue to handler" + +gdb_test "p ssi_addr" " = \\(void \\*\\) $ssi_addr" +gdb_test "p ssi_errno" " = $ssi_errno" +gdb_test "p ssi_code" " = $ssi_code" +gdb_test "p ssi_signo" " = $ssi_signo" + +# Again, but this time, patch si_addr and check that the inferior sees +# the changed value. + +# Advance to main +if { ![runto_main] } then { + gdb_suppress_tests; +} + +# Run to the signal. +gdb_test "continue" ".*Program received signal SIGSEGV.*" "continue to signal" + +set test "Set si_addr" +gdb_test "p \$_siginfo._sifields._sigfault.si_addr = 0x666" " = \\(void \\*\\) 0x666" +gdb_test "p \$_siginfo.si_errno = 666" " = 666" +gdb_test "p \$_siginfo.si_code = 999" " = 999" +gdb_test "p \$_siginfo.si_signo = 11" " = 11" + +gdb_test "break $bp_location" +gdb_test "continue" ".* handler .*" "continue to handler" + +gdb_test "p ssi_addr" " = \\(void \\*\\) 0x666" +gdb_test "p ssi_errno" " = 666" +gdb_test "p ssi_code" " = 999" +gdb_test "p ssi_signo" " = 11" ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [2/2] Inspect extra signal information 2009-01-12 18:50 ` [2/2] " Pedro Alves @ 2009-01-12 19:39 ` Eli Zaretskii 2009-01-13 12:32 ` Pedro Alves 0 siblings, 1 reply; 53+ messages in thread From: Eli Zaretskii @ 2009-01-12 19:39 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches > From: Pedro Alves <pedro@codesourcery.com> > Date: Mon, 12 Jan 2009 18:49:38 +0000 > > gdb/doc/ > * gdb.texinfo (Signals): Document $_siginfo. > (Convenience Variables): Mention $_siginfo. > (Remote Configuration): Document qXfer:siginfo:read, > qXfer:siginfo:write packets, and the read-siginfo-object, > write-siginfo-object commands. Thanks, this part is approved, with the following comments: > +@cindex inspecting extra signal information I think just "extra signal information" is enough. > +@anchor{qXfer siginfo read} You never reference this anchor. > +@anchor{qXfer siginfo write} Nor this one. ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [2/2] Inspect extra signal information 2009-01-12 19:39 ` Eli Zaretskii @ 2009-01-13 12:32 ` Pedro Alves 2009-01-13 18:55 ` Eli Zaretskii 0 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-01-13 12:32 UTC (permalink / raw) To: gdb-patches, Eli Zaretskii [-- Attachment #1: Type: text/plain, Size: 924 bytes --] Thanks Eli, On Monday 12 January 2009 19:37:13, Eli Zaretskii write: > Thanks, this part is approved, with the following comments: > > > +@cindex inspecting extra signal information > > I think just "extra signal information" is enough. I've adjusted it. > > +@anchor{qXfer siginfo read} > > You never reference this anchor. > > > +@anchor{qXfer siginfo write} > > Nor this one. > Ooops, copypasto. I had made references to the wrong anchors. I now also notice that I had placed the 'qXfer siginfo read' bits in the write table... I've now placed the new packets in alphabetical order as well, while I'm at it. I've updated the docs with the attached diff. I also noticed that the write packets have a @var{} around the object name, but the read ones don't: @item qXfer:@var{spu}:write @item qXfer:auxv:read @item qXfer:libraries:read I copied that, but which one is the correct form? -- Pedro Alves [-- Attachment #2: eli_review.diff --] [-- Type: text/x-diff, Size: 4148 bytes --] --- gdb/doc/gdb.texinfo | 48 +++++++++++++++++++++++++----------------------- 1 file changed, 25 insertions(+), 23 deletions(-) Index: src/gdb/doc/gdb.texinfo =================================================================== --- src.orig/gdb/doc/gdb.texinfo 2009-01-13 11:56:10.000000000 +0000 +++ src/gdb/doc/gdb.texinfo 2009-01-13 12:22:00.000000000 +0000 @@ -4473,8 +4473,8 @@ a result of the fatal signal once it saw you can continue with @samp{signal 0}. @xref{Signaling, ,Giving your Program a Signal}. -@cindex inspecting extra signal information -@anchor{inspecting extra signal information} +@cindex extra signal information +@anchor{extra signal information} On some targets, @value{GDBN} can inspect extra signal information associated with the intercepted signal, before it is actually @@ -7398,7 +7398,7 @@ the program being debugged terminates. @item $_siginfo @vindex $_siginfo@r{, convenience variable} The variable @code{$_siginfo} is bound to extra signal information -inspection (@pxref{inspecting extra signal information}). +inspection (@pxref{extra signal information}). @end table On HP-UX systems, if you refer to a function or variable name that @@ -26647,11 +26647,11 @@ The remote stub understands the @samp{qX @item qXfer:siginfo:read The remote stub understands the @samp{qXfer:siginfo:read} packet -(@pxref{qXfer spu read}). +(@pxref{qXfer siginfo read}). @item qXfer:siginfo:write The remote stub understands the @samp{qXfer:siginfo:write} packet -(@pxref{qXfer spu write}). +(@pxref{qXfer siginfo write}). @item QNonStop The remote stub understands the @samp{QNonStop} packet @@ -26811,6 +26811,16 @@ annex part of the generic @samp{qXfer} p This packet is not probed by default; the remote stub must request it, by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). +@item qXfer:siginfo:read::@var{offset},@var{length} +@anchor{qXfer siginfo read} +Read contents of the extra signal information on the target +system. The annex part of the generic @samp{qXfer} packet must be +empty (@pxref{qXfer read}). + +This packet is not probed by default; the remote stub must request it, +by supplying an appropriate @samp{qSupported} response +(@pxref{qSupported}). + @item qXfer:spu:read:@var{annex}:@var{offset},@var{length} @anchor{qXfer spu read} Read contents of an @code{spufs} file on the target system. The @@ -26876,6 +26886,16 @@ Here are the specific requests of this f formats, listed below. @table @samp +@item qXfer:@var{siginfo}:write::@var{offset}:@var{data}@dots{} +@anchor{qXfer siginfo write} +Write @var{data} to the extra signal information on the target system. +The annex part of the generic @samp{qXfer} packet must be +empty (@pxref{qXfer write}). + +This packet is not probed by default; the remote stub must request it, +by supplying an appropriate @samp{qSupported} response +(@pxref{qSupported}). + @item qXfer:@var{spu}:write:@var{annex}:@var{offset}:@var{data}@dots{} @anchor{qXfer spu write} Write @var{data} to an @code{spufs} file on the target system. The @@ -26886,24 +26906,6 @@ in that context to be accessed. This packet is not probed by default; the remote stub must request it, by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). - -@item qXfer:siginfo:read:@var{annex}:@var{offset},@var{length} -@anchor{qXfer siginfo read} -Read contents of the extra signal information on the target -system. The annex part of the generic @samp{qXfer} packet must be -empty (@pxref{qXfer read}). - -This packet is not probed by default; the remote stub must request it, -by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). - -@item qXfer:@var{siginfo}:write:@var{annex}:@var{offset}:@var{data}@dots{} -@anchor{qXfer siginfo write} -Write @var{data} to the extra signal information on the target system. -The annex part of the generic @samp{qXfer} packet must be -empty (@pxref{qXfer write}). - -This packet is not probed by default; the remote stub must request it, -by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). @end table Reply: ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [2/2] Inspect extra signal information 2009-01-13 12:32 ` Pedro Alves @ 2009-01-13 18:55 ` Eli Zaretskii 2009-01-13 19:08 ` Pedro Alves 2009-02-06 23:35 ` Pedro Alves 0 siblings, 2 replies; 53+ messages in thread From: Eli Zaretskii @ 2009-01-13 18:55 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches > From: Pedro Alves <pedro@codesourcery.com> > Date: Tue, 13 Jan 2009 12:31:59 +0000 > > I've updated the docs with the attached diff. Thanks. This version is OK. > I also noticed that the write packets have a @var{} around the > object name, but the read ones don't: > > @item qXfer:@var{spu}:write > > @item qXfer:auxv:read > @item qXfer:libraries:read > > I copied that, but which one is the correct form? @var{spu} is incorrect, since "spu" is a literal string, it does not stand for something else. Please remove those extra @var if you have a moment to spare. ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [2/2] Inspect extra signal information 2009-01-13 18:55 ` Eli Zaretskii @ 2009-01-13 19:08 ` Pedro Alves 2009-01-13 19:15 ` Eli Zaretskii 2009-02-06 23:35 ` Pedro Alves 1 sibling, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-01-13 19:08 UTC (permalink / raw) To: gdb-patches, Eli Zaretskii [-- Attachment #1: Type: text/plain, Size: 265 bytes --] On Tuesday 13 January 2009 18:54:24, Eli Zaretskii wrote: > @var{spu} is incorrect, since "spu" is a literal string, it does not > stand for something else. Please remove those extra @var if you have > a moment to spare. I checked in the below. -- Pedro Alves [-- Attachment #2: spu.diff --] [-- Type: text/x-diff, Size: 1231 bytes --] Index: ChangeLog =================================================================== RCS file: /cvs/src/src/gdb/doc/ChangeLog,v retrieving revision 1.847 diff -u -p -r1.847 ChangeLog --- ChangeLog 7 Jan 2009 21:42:50 -0000 1.847 +++ ChangeLog 13 Jan 2009 19:04:46 -0000 @@ -1,3 +1,8 @@ +2009-01-13 Pedro Alves <pedro@codesourcery.com> + + * gdb.texinfo (General Query Packets): Remove @var{} around the + "spu" literal string. + 2009-01-07 Pedro Alves <pedro@codesourcery.com> * gdb.texinfo (Error in Breakpoints): Delete mention of "The same Index: gdb.texinfo =================================================================== RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v retrieving revision 1.543 diff -u -p -r1.543 gdb.texinfo --- gdb.texinfo 7 Jan 2009 21:42:50 -0000 1.543 +++ gdb.texinfo 13 Jan 2009 19:04:52 -0000 @@ -26795,7 +26795,7 @@ Here are the specific requests of this f formats, listed below. @table @samp -@item qXfer:@var{spu}:write:@var{annex}:@var{offset}:@var{data}@dots{} +@item qXfer:spu:write:@var{annex}:@var{offset}:@var{data}@dots{} @anchor{qXfer spu write} Write @var{data} to an @code{spufs} file on the target system. The annex specifies which file to write; it must be of the form ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [2/2] Inspect extra signal information 2009-01-13 19:08 ` Pedro Alves @ 2009-01-13 19:15 ` Eli Zaretskii 0 siblings, 0 replies; 53+ messages in thread From: Eli Zaretskii @ 2009-01-13 19:15 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches > From: Pedro Alves <pedro@codesourcery.com> > Date: Tue, 13 Jan 2009 19:07:59 +0000 > > On Tuesday 13 January 2009 18:54:24, Eli Zaretskii wrote: > > > @var{spu} is incorrect, since "spu" is a literal string, it does not > > stand for something else. Please remove those extra @var if you have > > a moment to spare. > > I checked in the below. Thank you. ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [2/2] Inspect extra signal information 2009-01-13 18:55 ` Eli Zaretskii 2009-01-13 19:08 ` Pedro Alves @ 2009-02-06 23:35 ` Pedro Alves 2009-02-09 6:23 ` Paul Pluzhnikov 1 sibling, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-02-06 23:35 UTC (permalink / raw) To: gdb-patches Here's the version of this patch that went in. -- Pedro Alves 2009-02-06 Pedro Alves <pedro@codesourcery.com> * target.h (enum target_object): Add new TARGET_OBJECT_SIGNAL_INFO. * infrun.c (siginfo_value_read, siginfo_value_write): New. (siginfo_value_funcs): New. (siginfo_make_value): New. (_initialize_infrun): Create the $_siginfo convenience variable. * gdbtypes.h (append_composite_type_field_aligned): Declare. * gdbtypes.c (append_composite_type_field): Rename to... (append_composite_type_field_aligned): ... this. Add ALIGNMENT argument. Handle it. (append_composite_type_field): Rewrite on top of append_composite_type_field_aligned. * value.h (internalvar_make_value): New typedef. (struct internalvar) <make_value>: New field. (create_internalvar_type_lazy): Declare. * value.c (create_internalvar): Clear make_value. (create_internalvar_type_lazy): New. (value_of_internalvar): If make_value is set use it. (preserve_values): Skip internal variables that don't have a value. * gdbarch.sh (get_siginfo_type): New. * gdbarch.h, gdbarch.c: Regenerate. * linux-tdep.h, linux-tdep.c: New. * amd64-linux-tdep.c: Include "linux-tdep.h". (amd64_linux_init_abi): Register linux_get_siginfo_type and linux_get_siginfo_mapper. * i386-linux-tdep.c: Include "linux-tdep.h". (i386_linux_init_abi): Register linux_get_siginfo_type and linux_get_siginfo_mapper. * arm-linux-tdep.c: Include "linux-tdep.h". (i386_linux_init_abi): Register linux_get_siginfo_type and linux_get_siginfo_mapper. * linux-nat.c (linux_xfer_siginfo): New. (linux_nat_xfer_partial): Handle TARGET_OBJECT_SIGNAL_INFO. * remote.c (PACKET_qXfer_siginfo_read) (PACKET_qXfer_siginfo_write): New. (feature remote_protocol_features): Add "qXfer:siginfo:read" and "qXfer:siginfo:write" features. (remote_xfer_partial): Handle TARGET_OBJECT_SIGNAL_INFO. (_initialize_remote): Add "set/show remote read-siginfo-object" and "set/show remote write-siginfo-object" commands. * Makefile.in (ALL_TARGET_OBS): Add linux-tdep.o. (HFILES_NO_SRCDIR): Add linux-tdep.h. (ALLDEPFILES): Add linux-tdep.c. * configure.tgt (arm*-*-linux* | arm*-*-uclinux*) (i[34567]86-*-linux*, x86_64-*-linux*): Add linux-tdep.o to gdb_target_obs. 2009-02-06 Pedro Alves <pedro@codesourcery.com> gdb/gdbserver/ * server.c (handle_query): Report qXfer:siginfo:read and qXfer:siginfo:write as supported and handle them. * target.h (struct target_ops) <qxfer_siginfo>: New field. * linux-low.c (linux_xfer_siginfo): New. (linux_target_ops): Set it. 2009-02-06 Pedro Alves <pedro@codesourcery.com> gdb/doc/ * gdb.texinfo (Signals): Document $_siginfo. (Convenience Variables): Mention $_siginfo. (Remote Configuration): Document qXfer:siginfo:read, qXfer:siginfo:write packets, and the read-siginfo-object, write-siginfo-object commands. 2009-02-06 Pedro Alves <pedro@codesourcery.com> gdb/testsuite/ * gdb.base/siginfo-obj.c, gdb.base/siginfo-obj.exp: New. --- gdb/Makefile.in | 4 gdb/amd64-linux-tdep.c | 3 gdb/arm-linux-tdep.c | 3 gdb/configure.tgt | 6 - gdb/doc/gdb.texinfo | 101 ++++++++++++++++++++++++ gdb/gdbarch.c | 33 +++++++ gdb/gdbarch.h | 10 ++ gdb/gdbarch.sh | 5 + gdb/gdbserver/linux-low.c | 39 +++++++++ gdb/gdbserver/server.c | 74 +++++++++++++++++ gdb/gdbserver/target.h | 5 + gdb/gdbtypes.c | 29 +++++- gdb/gdbtypes.h | 4 gdb/i386-linux-tdep.c | 3 gdb/infrun.c | 87 ++++++++++++++++++++ gdb/linux-nat.c | 50 +++++++++++ gdb/linux-tdep.c | 138 +++++++++++++++++++++++++++++++++ gdb/linux-tdep.h | 25 +++++ gdb/remote.c | 25 +++++ gdb/target.h | 5 - gdb/testsuite/gdb.base/siginfo-obj.c | 70 ++++++++++++++++ gdb/testsuite/gdb.base/siginfo-obj.exp | 131 +++++++++++++++++++++++++++++++ gdb/value.c | 62 ++++++++++---- gdb/value.h | 6 + 24 files changed, 889 insertions(+), 29 deletions(-) Index: src/gdb/target.h =================================================================== --- src.orig/gdb/target.h 2009-02-06 22:36:44.000000000 +0000 +++ src/gdb/target.h 2009-02-06 22:42:34.000000000 +0000 @@ -221,7 +221,10 @@ enum target_object TARGET_OBJECT_LIBRARIES, /* Get OS specific data. The ANNEX specifies the type (running processes, etc.). */ - TARGET_OBJECT_OSDATA + TARGET_OBJECT_OSDATA, + /* Extra signal info. Usually the contents of `siginfo_t' on unix + platforms. */ + TARGET_OBJECT_SIGNAL_INFO, /* Possible future objects: TARGET_OBJECT_FILE, ... */ }; Index: src/gdb/infrun.c =================================================================== --- src.orig/gdb/infrun.c 2009-02-06 22:28:26.000000000 +0000 +++ src/gdb/infrun.c 2009-02-06 22:42:34.000000000 +0000 @@ -4804,6 +4804,87 @@ signals_info (char *signum_exp, int from printf_filtered (_("\nUse the \"handle\" command to change these tables.\n")); } + +/* The $_siginfo convenience variable is a bit special. We don't know + for sure the type of the value until we actually have a chance to + fetch the data. The type can change depending on gdbarch, so it it + also dependent on which thread you have selected. + + 1. making $_siginfo be an internalvar that creates a new value on + access. + + 2. making the value of $_siginfo be an lval_computed value. */ + +/* This function implements the lval_computed support for reading a + $_siginfo value. */ + +static void +siginfo_value_read (struct value *v) +{ + LONGEST transferred; + + transferred = + target_read (¤t_target, TARGET_OBJECT_SIGNAL_INFO, + NULL, + value_contents_all_raw (v), + value_offset (v), + TYPE_LENGTH (value_type (v))); + + if (transferred != TYPE_LENGTH (value_type (v))) + error (_("Unable to read siginfo")); +} + +/* This function implements the lval_computed support for writing a + $_siginfo value. */ + +static void +siginfo_value_write (struct value *v, struct value *fromval) +{ + LONGEST transferred; + + transferred = target_write (¤t_target, + TARGET_OBJECT_SIGNAL_INFO, + NULL, + value_contents_all_raw (fromval), + value_offset (v), + TYPE_LENGTH (value_type (fromval))); + + if (transferred != TYPE_LENGTH (value_type (fromval))) + error (_("Unable to write siginfo")); +} + +static struct lval_funcs siginfo_value_funcs = + { + siginfo_value_read, + siginfo_value_write + }; + +/* Return a new value with the correct type for the siginfo object of + the current thread. Return a void value if there's no object + available. */ + +struct value * +siginfo_make_value (struct internalvar *var) +{ + struct type *type; + struct gdbarch *gdbarch; + + if (target_has_stack + && !ptid_equal (inferior_ptid, null_ptid)) + { + gdbarch = get_frame_arch (get_current_frame ()); + + if (gdbarch_get_siginfo_type_p (gdbarch)) + { + type = gdbarch_get_siginfo_type (gdbarch); + + return allocate_computed_value (type, &siginfo_value_funcs, NULL); + } + } + + return allocate_value (builtin_type_void); +} + \f /* Inferior thread state. These are details related to the inferior itself, and don't include @@ -5467,4 +5548,10 @@ Options are 'forward' or 'reverse'."), observer_attach_thread_ptid_changed (infrun_thread_ptid_changed); observer_attach_thread_stop_requested (infrun_thread_stop_requested); + + /* Explicitly create without lookup, since that tries to create a + value with a void typed value, and when we get here, gdbarch + isn't initialized yet. At this point, we're quite sure there + isn't another convenience variable of the same name. */ + create_internalvar_type_lazy ("_siginfo", siginfo_make_value); } Index: src/gdb/gdbtypes.h =================================================================== --- src.orig/gdb/gdbtypes.h 2009-02-06 22:28:25.000000000 +0000 +++ src/gdb/gdbtypes.h 2009-02-06 22:42:34.000000000 +0000 @@ -1112,6 +1112,10 @@ extern struct type *init_type (enum type extern struct type *init_composite_type (char *name, enum type_code code); extern void append_composite_type_field (struct type *t, char *name, struct type *field); +extern void append_composite_type_field_aligned (struct type *t, + char *name, + struct type *field, + int alignment); /* Helper functions to construct a bit flags type. An initially empty type is created using init_flag_type(). Flags are then added using Index: src/gdb/gdbtypes.c =================================================================== --- src.orig/gdb/gdbtypes.c 2009-02-06 22:28:25.000000000 +0000 +++ src/gdb/gdbtypes.c 2009-02-06 22:42:34.000000000 +0000 @@ -1822,8 +1822,8 @@ init_composite_type (char *name, enum ty /* Helper function. Append a field to a composite type. */ void -append_composite_type_field (struct type *t, char *name, - struct type *field) +append_composite_type_field_aligned (struct type *t, char *name, + struct type *field, int alignment) { struct field *f; TYPE_NFIELDS (t) = TYPE_NFIELDS (t) + 1; @@ -1842,12 +1842,31 @@ append_composite_type_field (struct type { TYPE_LENGTH (t) = TYPE_LENGTH (t) + TYPE_LENGTH (field); if (TYPE_NFIELDS (t) > 1) - FIELD_BITPOS (f[0]) = (FIELD_BITPOS (f[-1]) - + (TYPE_LENGTH (FIELD_TYPE (f[-1])) - * TARGET_CHAR_BIT)); + { + FIELD_BITPOS (f[0]) = (FIELD_BITPOS (f[-1]) + + (TYPE_LENGTH (FIELD_TYPE (f[-1])) + * TARGET_CHAR_BIT)); + + if (alignment) + { + int left = FIELD_BITPOS (f[0]) % (alignment * TARGET_CHAR_BIT); + if (left) + { + FIELD_BITPOS (f[0]) += left; + TYPE_LENGTH (t) += left / TARGET_CHAR_BIT; + } + } + } } } +void +append_composite_type_field (struct type *t, char *name, + struct type *field) +{ + append_composite_type_field_aligned (t, name, field, 0); +} + int can_dereference (struct type *t) { Index: src/gdb/value.h =================================================================== --- src.orig/gdb/value.h 2009-02-06 22:42:33.000000000 +0000 +++ src/gdb/value.h 2009-02-06 22:42:34.000000000 +0000 @@ -305,11 +305,14 @@ extern struct value *coerce_array (struc /* Internal variables (variables for convenience of use of debugger) are recorded as a chain of these structures. */ +typedef struct value * (*internalvar_make_value) (struct internalvar *); + struct internalvar { struct internalvar *next; char *name; struct value *value; + internalvar_make_value make_value; int endian; }; @@ -534,6 +537,9 @@ extern struct internalvar *lookup_only_i extern struct internalvar *create_internalvar (char *name); +extern struct internalvar * + create_internalvar_type_lazy (char *name, internalvar_make_value fun); + extern struct internalvar *lookup_internalvar (char *name); extern int value_equal (struct value *arg1, struct value *arg2); Index: src/gdb/value.c =================================================================== --- src.orig/gdb/value.c 2009-02-06 22:42:33.000000000 +0000 +++ src/gdb/value.c 2009-02-06 22:42:34.000000000 +0000 @@ -901,12 +901,31 @@ create_internalvar (char *name) var->name = concat (name, (char *)NULL); var->value = allocate_value (builtin_type_void); var->endian = gdbarch_byte_order (current_gdbarch); + var->make_value = NULL; release_value (var->value); var->next = internalvars; internalvars = var; return var; } +/* Create an internal variable with name NAME and register FUN as the + function that value_of_internalvar uses to create a value whenever + this variable is referenced. NAME should not normally include a + dollar sign. */ + +struct internalvar * +create_internalvar_type_lazy (char *name, internalvar_make_value fun) +{ + struct internalvar *var; + var = (struct internalvar *) xmalloc (sizeof (struct internalvar)); + var->name = concat (name, (char *)NULL); + var->value = NULL; + var->make_value = fun; + var->endian = gdbarch_byte_order (current_gdbarch); + var->next = internalvars; + internalvars = var; + return var; +} /* Look up an internal variable with name NAME. NAME should not normally include a dollar sign. @@ -933,25 +952,31 @@ value_of_internalvar (struct internalvar int i, j; gdb_byte temp; - val = value_copy (var->value); - if (value_lazy (val)) - value_fetch_lazy (val); - - /* 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; + if (var->make_value != NULL) + val = (*var->make_value) (var); else { - VALUE_LVAL (val) = lval_internalvar; - VALUE_INTERNALVAR (val) = var; + val = value_copy (var->value); + if (value_lazy (val)) + value_fetch_lazy (val); + + /* 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 @@ -1075,7 +1100,8 @@ preserve_values (struct objfile *objfile preserve_one_value (cur->values[i], objfile, copied_types); for (var = internalvars; var; var = var->next) - preserve_one_value (var->value, objfile, copied_types); + if (var->value) + preserve_one_value (var->value, objfile, copied_types); for (val = values_in_python; val; val = val->next) preserve_one_value (val, objfile, copied_types); Index: src/gdb/gdbarch.sh =================================================================== --- src.orig/gdb/gdbarch.sh 2009-02-06 22:28:25.000000000 +0000 +++ src/gdb/gdbarch.sh 2009-02-06 22:42:34.000000000 +0000 @@ -705,6 +705,11 @@ m:enum target_signal:target_signal_from_ # signal number. m:int:target_signal_to_host:enum target_signal ts:ts::default_target_signal_to_host::0 +# Extra signal info inspection. +# +# Return a type suitable to inspect extra signal information. +M:struct type *:get_siginfo_type:void: + # Record architecture-specific information from the symbol table. M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym Index: src/gdb/gdbarch.h =================================================================== --- src.orig/gdb/gdbarch.h 2009-02-06 22:28:25.000000000 +0000 +++ src/gdb/gdbarch.h 2009-02-06 22:42:34.000000000 +0000 @@ -803,6 +803,16 @@ typedef int (gdbarch_target_signal_to_ho extern int gdbarch_target_signal_to_host (struct gdbarch *gdbarch, enum target_signal ts); extern void set_gdbarch_target_signal_to_host (struct gdbarch *gdbarch, gdbarch_target_signal_to_host_ftype *target_signal_to_host); +/* Extra signal info inspection. + + Return a type suitable to inspect extra signal information. */ + +extern int gdbarch_get_siginfo_type_p (struct gdbarch *gdbarch); + +typedef struct type * (gdbarch_get_siginfo_type_ftype) (struct gdbarch *gdbarch); +extern struct type * gdbarch_get_siginfo_type (struct gdbarch *gdbarch); +extern void set_gdbarch_get_siginfo_type (struct gdbarch *gdbarch, gdbarch_get_siginfo_type_ftype *get_siginfo_type); + /* Record architecture-specific information from the symbol table. */ extern int gdbarch_record_special_symbol_p (struct gdbarch *gdbarch); Index: src/gdb/gdbarch.c =================================================================== --- src.orig/gdb/gdbarch.c 2009-02-06 22:28:25.000000000 +0000 +++ src/gdb/gdbarch.c 2009-02-06 22:42:34.000000000 +0000 @@ -239,6 +239,7 @@ struct gdbarch int sofun_address_maybe_missing; gdbarch_target_signal_from_host_ftype *target_signal_from_host; gdbarch_target_signal_to_host_ftype *target_signal_to_host; + gdbarch_get_siginfo_type_ftype *get_siginfo_type; gdbarch_record_special_symbol_ftype *record_special_symbol; int has_global_solist; }; @@ -371,6 +372,7 @@ struct gdbarch startup_gdbarch = 0, /* sofun_address_maybe_missing */ default_target_signal_from_host, /* target_signal_from_host */ default_target_signal_to_host, /* target_signal_to_host */ + 0, /* get_siginfo_type */ 0, /* record_special_symbol */ 0, /* has_global_solist */ /* startup_gdbarch() */ @@ -624,6 +626,7 @@ verify_gdbarch (struct gdbarch *gdbarch) /* Skip verify of sofun_address_maybe_missing, invalid_p == 0 */ /* Skip verify of target_signal_from_host, invalid_p == 0 */ /* Skip verify of target_signal_to_host, invalid_p == 0 */ + /* Skip verify of get_siginfo_type, has predicate */ /* Skip verify of record_special_symbol, has predicate */ /* Skip verify of has_global_solist, invalid_p == 0 */ buf = ui_file_xstrdup (log, &dummy); @@ -835,6 +838,12 @@ gdbarch_dump (struct gdbarch *gdbarch, s "gdbarch_dump: get_longjmp_target = <%s>\n", host_address_to_string (gdbarch->get_longjmp_target)); fprintf_unfiltered (file, + "gdbarch_dump: gdbarch_get_siginfo_type_p() = %d\n", + gdbarch_get_siginfo_type_p (gdbarch)); + fprintf_unfiltered (file, + "gdbarch_dump: get_siginfo_type = <0x%lx>\n", + (long) gdbarch->get_siginfo_type); + fprintf_unfiltered (file, "gdbarch_dump: has_global_solist = %s\n", plongest (gdbarch->has_global_solist)); fprintf_unfiltered (file, @@ -3220,6 +3229,30 @@ set_gdbarch_target_signal_to_host (struc } int +gdbarch_get_siginfo_type_p (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + return gdbarch->get_siginfo_type != NULL; +} + +struct type * +gdbarch_get_siginfo_type (struct gdbarch *gdbarch) +{ + gdb_assert (gdbarch != NULL); + gdb_assert (gdbarch->get_siginfo_type != NULL); + if (gdbarch_debug >= 2) + fprintf_unfiltered (gdb_stdlog, "gdbarch_get_siginfo_type called\n"); + return gdbarch->get_siginfo_type (gdbarch); +} + +void +set_gdbarch_get_siginfo_type (struct gdbarch *gdbarch, + gdbarch_get_siginfo_type_ftype get_siginfo_type) +{ + gdbarch->get_siginfo_type = get_siginfo_type; +} + +int gdbarch_record_special_symbol_p (struct gdbarch *gdbarch) { gdb_assert (gdbarch != NULL); Index: src/gdb/linux-tdep.h =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ src/gdb/linux-tdep.h 2009-02-06 22:42:35.000000000 +0000 @@ -0,0 +1,25 @@ +/* Target-dependent code for GNU/Linux, architecture independent. + + Copyright (C) 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#ifndef LINUX_TDEP_H +#define LINUX_TDEP_H + +struct type *linux_get_siginfo_type (struct gdbarch *); + +#endif /* linux-tdep.h */ Index: src/gdb/linux-tdep.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ src/gdb/linux-tdep.c 2009-02-06 22:42:35.000000000 +0000 @@ -0,0 +1,138 @@ +/* Target-dependent code for GNU/Linux, architecture independent. + + Copyright (C) 2009 Free Software Foundation, Inc. + + This file is part of GDB. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. */ + +#include "defs.h" +#include "gdbtypes.h" + +/* This function is suitable for architectures that don't + extend/override the standard siginfo structure. */ + +struct type * +linux_get_siginfo_type (struct gdbarch *gdbarch) +{ + struct type *int_type, *uint_type, *long_type, *void_ptr_type; + struct type *uid_type, *pid_type; + struct type *sigval_type, *clock_type; + struct type *siginfo_type, *sifields_type; + struct type *type; + + int_type = init_type (TYPE_CODE_INT, + gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT, + 0, "int", NULL); + uint_type = init_type (TYPE_CODE_INT, + gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT, + 0, "unsigned int", NULL); + long_type = init_type (TYPE_CODE_INT, + gdbarch_long_bit (gdbarch) / HOST_CHAR_BIT, + 0, "long", NULL); + void_ptr_type = lookup_pointer_type (builtin_type (gdbarch)->builtin_void); + + /* sival_t */ + sigval_type = init_composite_type (NULL, TYPE_CODE_UNION); + TYPE_NAME (sigval_type) = xstrdup ("sigval_t"); + append_composite_type_field (sigval_type, "sival_int", int_type); + append_composite_type_field (sigval_type, "sival_ptr", void_ptr_type); + + /* __pid_t */ + pid_type = init_type (TYPE_CODE_TYPEDEF, TYPE_LENGTH (int_type), + TYPE_FLAG_TARGET_STUB, NULL, NULL); + TYPE_NAME (pid_type) = xstrdup ("__pid_t"); + TYPE_TARGET_TYPE (pid_type) = int_type; + + /* __uid_t */ + uid_type = init_type (TYPE_CODE_TYPEDEF, TYPE_LENGTH (uint_type), + TYPE_FLAG_TARGET_STUB, NULL, NULL); + TYPE_NAME (uid_type) = xstrdup ("__uid_t"); + TYPE_TARGET_TYPE (uid_type) = uint_type; + + /* __clock_t */ + clock_type = init_type (TYPE_CODE_TYPEDEF, TYPE_LENGTH (long_type), + TYPE_FLAG_TARGET_STUB, NULL, NULL); + TYPE_NAME (clock_type) = xstrdup ("__clock_t"); + TYPE_TARGET_TYPE (clock_type) = long_type; + + /* _sifields */ + sifields_type = init_composite_type (NULL, TYPE_CODE_UNION); + + { + const int si_max_size = 128; + int si_pad_size; + int size_of_int = gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT; + + /* _pad */ + if (gdbarch_ptr_bit (gdbarch) == 64) + si_pad_size = (si_max_size / size_of_int) - 4; + else + si_pad_size = (si_max_size / size_of_int) - 3; + append_composite_type_field (sifields_type, "_pad", + init_vector_type (int_type, si_pad_size)); + } + + /* _kill */ + type = init_composite_type (NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "si_pid", pid_type); + append_composite_type_field (type, "si_uid", uid_type); + append_composite_type_field (sifields_type, "_kill", type); + + /* _timer */ + type = init_composite_type (NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "si_tid", int_type); + append_composite_type_field (type, "si_overrun", int_type); + append_composite_type_field (type, "si_sigval", sigval_type); + append_composite_type_field (sifields_type, "_timer", type); + + /* _rt */ + type = init_composite_type (NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "si_pid", pid_type); + append_composite_type_field (type, "si_uid", uid_type); + append_composite_type_field (type, "si_sigval", sigval_type); + append_composite_type_field (sifields_type, "_rt", type); + + /* _sigchld */ + type = init_composite_type (NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "si_pid", pid_type); + append_composite_type_field (type, "si_uid", uid_type); + append_composite_type_field (type, "si_status", int_type); + append_composite_type_field (type, "si_utime", clock_type); + append_composite_type_field (type, "si_stime", clock_type); + append_composite_type_field (sifields_type, "_sigchld", type); + + /* _sigfault */ + type = init_composite_type (NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "si_addr", void_ptr_type); + append_composite_type_field (sifields_type, "_sigfault", type); + + /* _sigpoll */ + type = init_composite_type (NULL, TYPE_CODE_STRUCT); + append_composite_type_field (type, "si_band", long_type); + append_composite_type_field (type, "si_fd", int_type); + append_composite_type_field (sifields_type, "_sigpoll", type); + + /* struct siginfo */ + siginfo_type = init_composite_type (NULL, TYPE_CODE_STRUCT); + TYPE_NAME (siginfo_type) = xstrdup ("siginfo"); + append_composite_type_field (siginfo_type, "si_signo", int_type); + append_composite_type_field (siginfo_type, "si_errno", int_type); + append_composite_type_field (siginfo_type, "si_code", int_type); + append_composite_type_field_aligned (siginfo_type, + "_sifields", sifields_type, + TYPE_LENGTH (long_type)); + + return siginfo_type; +} Index: src/gdb/amd64-linux-tdep.c =================================================================== --- src.orig/gdb/amd64-linux-tdep.c 2009-02-06 22:28:26.000000000 +0000 +++ src/gdb/amd64-linux-tdep.c 2009-02-06 22:42:35.000000000 +0000 @@ -29,6 +29,7 @@ #include "gdbtypes.h" #include "reggroups.h" #include "amd64-linux-tdep.h" +#include "linux-tdep.h" #include "gdb_string.h" @@ -296,6 +297,8 @@ amd64_linux_init_abi (struct gdbarch_inf simple_displaced_step_free_closure); set_gdbarch_displaced_step_location (gdbarch, displaced_step_at_entry_point); + + set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type); } \f Index: src/gdb/i386-linux-tdep.c =================================================================== --- src.orig/gdb/i386-linux-tdep.c 2009-02-06 22:28:25.000000000 +0000 +++ src/gdb/i386-linux-tdep.c 2009-02-06 22:42:35.000000000 +0000 @@ -31,6 +31,7 @@ #include "i386-tdep.h" #include "i386-linux-tdep.h" +#include "linux-tdep.h" #include "glibc-tdep.h" #include "solib-svr4.h" #include "symtab.h" @@ -469,6 +470,8 @@ i386_linux_init_abi (struct gdbarch_info simple_displaced_step_free_closure); set_gdbarch_displaced_step_location (gdbarch, displaced_step_at_entry_point); + + set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type); } /* Provide a prototype to silence -Wmissing-prototypes. */ Index: src/gdb/arm-linux-tdep.c =================================================================== --- src.orig/gdb/arm-linux-tdep.c 2009-02-06 22:28:26.000000000 +0000 +++ src/gdb/arm-linux-tdep.c 2009-02-06 22:42:35.000000000 +0000 @@ -36,6 +36,7 @@ #include "arm-tdep.h" #include "arm-linux-tdep.h" +#include "linux-tdep.h" #include "glibc-tdep.h" #include "gdb_string.h" @@ -647,6 +648,8 @@ arm_linux_init_abi (struct gdbarch_info /* Core file support. */ set_gdbarch_regset_from_core_section (gdbarch, arm_linux_regset_from_core_section); + + set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type); } void Index: src/gdb/linux-nat.c =================================================================== --- src.orig/gdb/linux-nat.c 2009-02-06 22:36:43.000000000 +0000 +++ src/gdb/linux-nat.c 2009-02-06 22:42:35.000000000 +0000 @@ -3224,14 +3224,62 @@ linux_nat_mourn_inferior (struct target_ } static LONGEST +linux_xfer_siginfo (struct target_ops *ops, enum target_object object, + const char *annex, gdb_byte *readbuf, + const gdb_byte *writebuf, ULONGEST offset, LONGEST len) +{ + struct lwp_info *lp; + LONGEST n; + int pid; + struct siginfo siginfo; + + gdb_assert (object == TARGET_OBJECT_SIGNAL_INFO); + gdb_assert (readbuf || writebuf); + + pid = GET_LWP (inferior_ptid); + if (pid == 0) + pid = GET_PID (inferior_ptid); + + if (offset > sizeof (siginfo)) + return -1; + + errno = 0; + ptrace (PTRACE_GETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo); + if (errno != 0) + return -1; + + if (offset + len > sizeof (siginfo)) + len = sizeof (siginfo) - offset; + + if (readbuf != NULL) + memcpy (readbuf, (char *)&siginfo + offset, len); + else + { + memcpy ((char *)&siginfo + offset, writebuf, len); + errno = 0; + ptrace (PTRACE_SETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo); + if (errno != 0) + return -1; + } + + return len; +} + +static LONGEST linux_nat_xfer_partial (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, const gdb_byte *writebuf, ULONGEST offset, LONGEST len) { - struct cleanup *old_chain = save_inferior_ptid (); + struct cleanup *old_chain; LONGEST xfer; + if (object == TARGET_OBJECT_SIGNAL_INFO) + return linux_xfer_siginfo (ops, object, annex, readbuf, writebuf, + offset, len); + + old_chain = save_inferior_ptid (); + if (is_lwp (inferior_ptid)) inferior_ptid = pid_to_ptid (GET_LWP (inferior_ptid)); Index: src/gdb/remote.c =================================================================== --- src.orig/gdb/remote.c 2009-02-06 22:36:43.000000000 +0000 +++ src/gdb/remote.c 2009-02-06 22:42:35.000000000 +0000 @@ -998,6 +998,8 @@ enum { PACKET_vRun, PACKET_QStartNoAckMode, PACKET_vKill, + PACKET_qXfer_siginfo_read, + PACKET_qXfer_siginfo_write, PACKET_MAX }; @@ -2962,6 +2964,10 @@ static struct protocol_feature remote_pr PACKET_QStartNoAckMode }, { "multiprocess", PACKET_DISABLE, remote_multi_process_feature, -1 }, { "QNonStop", PACKET_DISABLE, remote_non_stop_feature, -1 }, + { "qXfer:siginfo:read", PACKET_DISABLE, remote_supported_packet, + PACKET_qXfer_siginfo_read }, + { "qXfer:siginfo:write", PACKET_DISABLE, remote_supported_packet, + PACKET_qXfer_siginfo_write }, }; static void @@ -7323,6 +7329,19 @@ remote_xfer_partial (struct target_ops * [PACKET_qXfer_spu_write]); } + /* Handle extra signal info using qxfer packets. */ + if (object == TARGET_OBJECT_SIGNAL_INFO) + { + if (readbuf) + return remote_read_qxfer (ops, "siginfo", annex, readbuf, offset, len, + &remote_protocol_packets + [PACKET_qXfer_siginfo_read]); + else + return remote_write_qxfer (ops, "siginfo", annex, writebuf, offset, len, + &remote_protocol_packets + [PACKET_qXfer_siginfo_write]); + } + /* Only handle flash writes. */ if (writebuf != NULL) { @@ -9070,6 +9089,12 @@ Show the maximum size of the address (in add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_osdata], "qXfer:osdata:read", "osdata", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_siginfo_read], + "qXfer:siginfo:read", "read-siginfo-object", 0); + + add_packet_config_cmd (&remote_protocol_packets[PACKET_qXfer_siginfo_write], + "qXfer:siginfo:write", "write-siginfo-object", 0); + add_packet_config_cmd (&remote_protocol_packets[PACKET_qGetTLSAddr], "qGetTLSAddr", "get-thread-local-storage-address", 0); Index: src/gdb/Makefile.in =================================================================== --- src.orig/gdb/Makefile.in 2009-02-06 22:36:42.000000000 +0000 +++ src/gdb/Makefile.in 2009-02-06 22:42:35.000000000 +0000 @@ -483,6 +483,7 @@ ALL_TARGET_OBS = \ i386-sol2-tdep.o i386-tdep.o i387-tdep.o \ i386-dicos-tdep.o \ iq2000-tdep.o \ + linux-tdep.o \ m32c-tdep.o \ m32r-linux-tdep.o m32r-tdep.o \ m68hc11-tdep.o \ @@ -730,7 +731,7 @@ config/sparc/nm-sol2.h config/nm-linux.h config/rs6000/nm-rs6000.h top.h bsd-kvm.h gdb-stabs.h reggroups.h \ annotate.h sim-regno.h dictionary.h dfp.h main.h frame-unwind.h \ remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \ -sentinel-frame.h bcache.h symfile.h windows-tdep.h +sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h # Header files that already have srcdir in them, or which are in objdir. @@ -1301,6 +1302,7 @@ ALLDEPFILES = \ irix5-nat.c \ libunwind-frame.c \ linux-fork.c \ + linux-tdep.c \ m68hc11-tdep.c \ m32r-tdep.c \ m32r-linux-nat.c m32r-linux-tdep.c \ Index: src/gdb/configure.tgt =================================================================== --- src.orig/gdb/configure.tgt 2009-02-06 22:28:26.000000000 +0000 +++ src/gdb/configure.tgt 2009-02-06 22:42:35.000000000 +0000 @@ -75,7 +75,7 @@ arm*-wince-pe | arm*-*-mingw32ce*) arm*-*-linux*) # Target: ARM based machine running GNU/Linux gdb_target_obs="arm-tdep.o arm-linux-tdep.o glibc-tdep.o \ - solib.o solib-svr4.o symfile-mem.o corelow.o" + solib.o solib-svr4.o symfile-mem.o corelow.o linux-tdep.o" build_gdbserver=yes ;; arm*-*-netbsd* | arm*-*-knetbsd*-gnu) @@ -190,7 +190,7 @@ i[34567]86-*-solaris*) i[34567]86-*-linux*) # Target: Intel 386 running GNU/Linux gdb_target_obs="i386-tdep.o i386-linux-tdep.o glibc-tdep.o i387-tdep.o \ - solib.o solib-svr4.o symfile-mem.o corelow.o" + solib.o solib-svr4.o symfile-mem.o corelow.o linux-tdep.o" build_gdbserver=yes ;; i[34567]86-*-gnu*) @@ -513,7 +513,7 @@ x86_64-*-linux*) # Target: GNU/Linux x86-64 gdb_target_obs="amd64-tdep.o amd64-linux-tdep.o i386-tdep.o \ i387-tdep.o i386-linux-tdep.o glibc-tdep.o \ - solib.o solib-svr4.o corelow.o symfile-mem.o" + solib.o solib-svr4.o corelow.o symfile-mem.o linux-tdep.o" build_gdbserver=yes ;; x86_64-*-freebsd* | x86_64-*-kfreebsd*-gnu) Index: src/gdb/gdbserver/server.c =================================================================== --- src.orig/gdb/gdbserver/server.c 2009-02-06 22:28:25.000000000 +0000 +++ src/gdb/gdbserver/server.c 2009-02-06 22:42:35.000000000 +0000 @@ -810,6 +810,77 @@ handle_query (char *own_buf, int packet_ return; } + if (the_target->qxfer_siginfo != NULL + && strncmp ("qXfer:siginfo:read:", own_buf, 19) == 0) + { + unsigned char *data; + int n; + CORE_ADDR ofs; + unsigned int len; + char *annex; + + require_running (own_buf); + + /* Reject any annex; grab the offset and length. */ + if (decode_xfer_read (own_buf + 19, &annex, &ofs, &len) < 0 + || annex[0] != '\0') + { + strcpy (own_buf, "E00"); + return; + } + + /* Read one extra byte, as an indicator of whether there is + more. */ + if (len > PBUFSIZ - 2) + len = PBUFSIZ - 2; + data = malloc (len + 1); + if (!data) + return; + n = (*the_target->qxfer_siginfo) (annex, data, NULL, ofs, len + 1); + if (n < 0) + write_enn (own_buf); + else if (n > len) + *new_packet_len_p = write_qxfer_response (own_buf, data, len, 1); + else + *new_packet_len_p = write_qxfer_response (own_buf, data, n, 0); + + free (data); + return; + } + + if (the_target->qxfer_siginfo != NULL + && strncmp ("qXfer:siginfo:write:", own_buf, 20) == 0) + { + char *annex; + int n; + unsigned int len; + CORE_ADDR ofs; + unsigned char *data; + + require_running (own_buf); + + strcpy (own_buf, "E00"); + data = malloc (packet_len - 19); + if (!data) + return; + if (decode_xfer_write (own_buf + 20, packet_len - 20, &annex, + &ofs, &len, data) < 0) + { + free (data); + return; + } + + n = (*the_target->qxfer_siginfo) + (annex, NULL, (unsigned const char *)data, ofs, len); + if (n < 0) + write_enn (own_buf); + else + sprintf (own_buf, "%x", n); + + free (data); + return; + } + /* Protocol features query. */ if (strncmp ("qSupported", own_buf, 10) == 0 && (own_buf[10] == ':' || own_buf[10] == '\0')) @@ -826,6 +897,9 @@ handle_query (char *own_buf, int packet_ if (the_target->qxfer_spu != NULL) strcat (own_buf, ";qXfer:spu:read+;qXfer:spu:write+"); + if (the_target->qxfer_siginfo != NULL) + strcat (own_buf, ";qXfer:siginfo:read+;qXfer:siginfo:write+"); + /* We always report qXfer:features:read, as targets may install XML files on a subsequent call to arch_setup. If we reported to GDB on startup that we don't support Index: src/gdb/gdbserver/target.h =================================================================== --- src.orig/gdb/gdbserver/target.h 2009-02-06 22:28:25.000000000 +0000 +++ src/gdb/gdbserver/target.h 2009-02-06 22:42:35.000000000 +0000 @@ -193,6 +193,11 @@ struct target_ops int (*qxfer_osdata) (const char *annex, unsigned char *readbuf, unsigned const char *writebuf, CORE_ADDR offset, int len); + + /* Read/Write extra signal info. */ + int (*qxfer_siginfo) (const char *annex, unsigned char *readbuf, + unsigned const char *writebuf, + CORE_ADDR offset, int len); }; extern struct target_ops *the_target; Index: src/gdb/gdbserver/linux-low.c =================================================================== --- src.orig/gdb/gdbserver/linux-low.c 2009-02-06 22:28:25.000000000 +0000 +++ src/gdb/gdbserver/linux-low.c 2009-02-06 22:42:35.000000000 +0000 @@ -2180,6 +2180,44 @@ linux_qxfer_osdata (const char *annex, return len; } +static int +linux_xfer_siginfo (const char *annex, unsigned char *readbuf, + unsigned const char *writebuf, CORE_ADDR offset, int len) +{ + struct siginfo siginfo; + long pid = -1; + + if (current_inferior == NULL) + return -1; + + pid = pid_of (get_thread_process (current_inferior)); + + if (debug_threads) + fprintf (stderr, "%s siginfo for lwp %ld.\n", + readbuf != NULL ? "Reading" : "Writing", + pid); + + if (offset > sizeof (siginfo)) + return -1; + + if (ptrace (PTRACE_GETSIGINFO, pid, 0, &siginfo) != 0) + return -1; + + if (offset + len > sizeof (siginfo)) + len = sizeof (siginfo) - offset; + + if (readbuf != NULL) + memcpy (readbuf, (char *) &siginfo + offset, len); + else + { + memcpy ((char *) &siginfo + offset, writebuf, len); + if (ptrace (PTRACE_SETSIGINFO, pid, 0, &siginfo) != 0) + return -1; + } + + return len; +} + static struct target_ops linux_target_ops = { linux_create_inferior, linux_attach, @@ -2213,6 +2251,7 @@ static struct target_ops linux_target_op NULL, hostio_last_error_from_errno, linux_qxfer_osdata, + linux_xfer_siginfo, }; static void Index: src/gdb/doc/gdb.texinfo =================================================================== --- src.orig/gdb/doc/gdb.texinfo 2009-02-06 22:36:45.000000000 +0000 +++ src/gdb/doc/gdb.texinfo 2009-02-06 22:42:35.000000000 +0000 @@ -4472,6 +4472,55 @@ a result of the fatal signal once it saw you can continue with @samp{signal 0}. @xref{Signaling, ,Giving your Program a Signal}. +@cindex extra signal information +@anchor{extra signal information} + +On some targets, @value{GDBN} can inspect extra signal information +associated with the intercepted signal, before it is actually +delivered to the program being debugged. This information is exported +by the convenience variable @code{$_siginfo}, and consists of data +that is passed by the kernel to the signal handler at the time of the +receipt of a signal. The data type of the information itself is +target dependent. You can see the data type using the @code{ptype +$_siginfo} command. On Unix systems, it typically corresponds to the +standard @code{siginfo_t} type, as defined in the @file{signal.h} +system header. + +Here's an example, on a @sc{gnu}/Linux system, printing the stray +referenced address that raised a segmentation fault. + +@smallexample +@group +(@value{GDBP}) continue +Program received signal SIGSEGV, Segmentation fault. +0x0000000000400766 in main () +69 *(int *)p = 0; +(@value{GDBP}) ptype $_siginfo +type = struct @{ + int si_signo; + int si_errno; + int si_code; + union @{ + int _pad[28]; + struct @{...@} _kill; + struct @{...@} _timer; + struct @{...@} _rt; + struct @{...@} _sigchld; + struct @{...@} _sigfault; + struct @{...@} _sigpoll; + @} _sifields; +@} +(@value{GDBP}) ptype $_siginfo._sifields._sigfault +type = struct @{ + void *si_addr; +@} +(@value{GDBP}) p $_siginfo._sifields._sigfault.si_addr +$1 = (void *) 0x7ffff7ff7000 +@end group +@end smallexample + +Depending on target support, @code{$_siginfo} may also be writable. + @node Thread Stops @section Stopping and Starting Multi-thread Programs @@ -7348,6 +7397,11 @@ to match the format in which the data wa @vindex $_exitcode@r{, convenience variable} The variable @code{$_exitcode} is automatically set to the exit code when the program being debugged terminates. + +@item $_siginfo +@vindex $_siginfo@r{, convenience variable} +The variable @code{$_siginfo} is bound to extra signal information +inspection (@pxref{extra signal information}). @end table On HP-UX systems, if you refer to a function or variable name that @@ -14307,6 +14361,14 @@ are: @tab @code{qXfer:spu:write} @tab @code{info spu} +@item @code{read-siginfo-object} +@tab @code{qXfer:siginfo:read} +@tab @code{print $_siginfo} + +@item @code{write-siginfo-object} +@tab @code{qXfer:siginfo:write} +@tab @code{set $_siginfo} + @item @code{get-thread-local-@*storage-address} @tab @code{qGetTLSAddr} @tab Displaying @code{__thread} variables @@ -26879,6 +26941,16 @@ These are the currently defined stub fea @tab @samp{-} @tab Yes +@item @samp{qXfer:siginfo:read} +@tab No +@tab @samp{-} +@tab Yes + +@item @samp{qXfer:siginfo:write} +@tab No +@tab @samp{-} +@tab Yes + @item @samp{QNonStop} @tab No @tab @samp{-} @@ -26939,6 +27011,14 @@ The remote stub understands the @samp{qX The remote stub understands the @samp{qXfer:spu:write} packet (@pxref{qXfer spu write}). +@item qXfer:siginfo:read +The remote stub understands the @samp{qXfer:siginfo:read} packet +(@pxref{qXfer siginfo read}). + +@item qXfer:siginfo:write +The remote stub understands the @samp{qXfer:siginfo:write} packet +(@pxref{qXfer siginfo write}). + @item QNonStop The remote stub understands the @samp{QNonStop} packet (@pxref{QNonStop}). @@ -27097,6 +27177,16 @@ annex part of the generic @samp{qXfer} p This packet is not probed by default; the remote stub must request it, by supplying an appropriate @samp{qSupported} response (@pxref{qSupported}). +@item qXfer:siginfo:read::@var{offset},@var{length} +@anchor{qXfer siginfo read} +Read contents of the extra signal information on the target +system. The annex part of the generic @samp{qXfer} packet must be +empty (@pxref{qXfer read}). + +This packet is not probed by default; the remote stub must request it, +by supplying an appropriate @samp{qSupported} response +(@pxref{qSupported}). + @item qXfer:spu:read:@var{annex}:@var{offset},@var{length} @anchor{qXfer spu read} Read contents of an @code{spufs} file on the target system. The @@ -27149,6 +27239,7 @@ the stub, or that the object does not su @item qXfer:@var{object}:write:@var{annex}:@var{offset}:@var{data}@dots{} @cindex write data into object, remote request +@anchor{qXfer write} Write uninterpreted bytes into the target's special data area identified by the keyword @var{object}, starting at @var{offset} bytes into the data. @var{data}@dots{} is the binary-encoded data @@ -27161,6 +27252,16 @@ Here are the specific requests of this f formats, listed below. @table @samp +@item qXfer:siginfo:write::@var{offset}:@var{data}@dots{} +@anchor{qXfer siginfo write} +Write @var{data} to the extra signal information on the target system. +The annex part of the generic @samp{qXfer} packet must be +empty (@pxref{qXfer write}). + +This packet is not probed by default; the remote stub must request it, +by supplying an appropriate @samp{qSupported} response +(@pxref{qSupported}). + @item qXfer:spu:write:@var{annex}:@var{offset}:@var{data}@dots{} @anchor{qXfer spu write} Write @var{data} to an @code{spufs} file on the target system. The Index: src/gdb/testsuite/gdb.base/siginfo-obj.c =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ src/gdb/testsuite/gdb.base/siginfo-obj.c 2009-02-06 22:42:35.000000000 +0000 @@ -0,0 +1,70 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2004, 2007, 2008 Free Software Foundation, Inc. + + This program is free software; you can redistribute it and/or modify + it under the terms of the GNU General Public License as published by + the Free Software Foundation; either version 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + GNU General Public License for more details. + + You should have received a copy of the GNU General Public License + along with this program. If not, see <http://www.gnu.org/licenses/>. + +*/ + +#include <signal.h> +#include <stdlib.h> +#include <string.h> +#include <sys/mman.h> +#include <unistd.h> + +static void *p; + +static void +handler (int sig, siginfo_t *info, void *context) +{ + /* Copy to local vars, as the test wants to read them, and si_addr, + etc. may be preprocessor defines. */ + int ssi_errno = info->si_errno; + int ssi_signo = info->si_signo; + int ssi_code = info->si_code; + void *ssi_addr = info->si_addr; + + _exit (0); /* set breakpoint here */ +} + +int +main (void) +{ + /* Set up unwritable memory. */ + { + size_t len; + len = sysconf(_SC_PAGESIZE); + p = mmap (0, len, PROT_NONE, MAP_ANON|MAP_PRIVATE, -1, 0); + if (p == MAP_FAILED) + { + perror ("mmap"); + return 1; + } + } + /* Set up the signal handler. */ + { + struct sigaction action; + memset (&action, 0, sizeof (action)); + action.sa_sigaction = handler; + action.sa_flags |= SA_SIGINFO; + if (sigaction (SIGSEGV, &action, NULL)) + { + perror ("sigaction"); + return 1; + } + } + /* Trigger SIGSEGV. */ + *(int *)p = 0; + return 0; +} Index: src/gdb/testsuite/gdb.base/siginfo-obj.exp =================================================================== --- /dev/null 1970-01-01 00:00:00.000000000 +0000 +++ src/gdb/testsuite/gdb.base/siginfo-obj.exp 2009-02-06 22:42:35.000000000 +0000 @@ -0,0 +1,131 @@ +# Copyright 2004, 2007, 2008 Free Software Foundation, Inc. + +# This program is free software; you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation; either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see <http://www.gnu.org/licenses/>. + + +# The program siginfo-obj.c arranges for a signal handler registered +# using sigaction's sa_sigaction / SA_SIGINFO to be called with +# si_addr filled in. + +# This test confirms that we can inspect signal info using the +# $_siginfo convenience variable. + +if [target_info exists gdb,nosignals] { + verbose "Skipping siginfo-obj.exp because of nosignals." + continue +} + +if { ! [istarget "i?86-*-linux*"] + && ! [istarget "x86_64-*-linux*"] + && ! [istarget "arm*-*-linux*"] } { + verbose "Skipping siginfo-obj.exp because of lack of support." + return +} + +if $tracelevel then { + strace $tracelevel +} + +set prms_id 0 +set bug_id 0 + +set testfile siginfo-obj +set srcfile ${testfile}.c +set binfile ${objdir}/${subdir}/${testfile} +if { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } { + untested "Couldn't compile ${srcfile}.c" + return -1 +} + +# get things started +gdb_exit +gdb_start +gdb_reinitialize_dir $srcdir/$subdir +gdb_load ${binfile} + +# Advance to main +if { ![runto_main] } then { + gdb_suppress_tests; +} + +# Run to the signal. +gdb_test "continue" ".*Program received signal SIGSEGV.*" "continue to signal" + +set ssi_addr "" +set test "Extract si_addr" +gdb_test_multiple "p \$_siginfo" "$test" { + -re "si_addr = ($hex).*$gdb_prompt $" { + set ssi_addr $expect_out(1,string) + pass "$test" + } +} + +set test "Extract si_errno" +gdb_test_multiple "p \$_siginfo" "$test" { + -re "si_errno = (\[0-9\]\+).*$gdb_prompt $" { + set ssi_errno $expect_out(1,string) + pass "$test" + } +} + +set test "Extract si_code" +gdb_test_multiple "p \$_siginfo" "$test" { + -re "si_code = (\[0-9\]\+).*$gdb_prompt $" { + set ssi_code $expect_out(1,string) + pass "$test" + } +} + +set test "Extract si_signo" +gdb_test_multiple "p \$_siginfo" "$test" { + -re "si_signo = (\[0-9\]\+).*$gdb_prompt $" { + set ssi_signo $expect_out(1,string) + pass "$test" + } +} + +set bp_location [gdb_get_line_number "set breakpoint here"] + +gdb_test "break $bp_location" +gdb_test "continue" ".* handler .*" "continue to handler" + +gdb_test "p ssi_addr" " = \\(void \\*\\) $ssi_addr" +gdb_test "p ssi_errno" " = $ssi_errno" +gdb_test "p ssi_code" " = $ssi_code" +gdb_test "p ssi_signo" " = $ssi_signo" + +# Again, but this time, patch si_addr and check that the inferior sees +# the changed value. + +# Advance to main +if { ![runto_main] } then { + gdb_suppress_tests; +} + +# Run to the signal. +gdb_test "continue" ".*Program received signal SIGSEGV.*" "continue to signal" + +set test "Set si_addr" +gdb_test "p \$_siginfo._sifields._sigfault.si_addr = 0x666" " = \\(void \\*\\) 0x666" +gdb_test "p \$_siginfo.si_errno = 666" " = 666" +gdb_test "p \$_siginfo.si_code = 999" " = 999" +gdb_test "p \$_siginfo.si_signo = 11" " = 11" + +gdb_test "break $bp_location" +gdb_test "continue" ".* handler .*" "continue to handler" + +gdb_test "p ssi_addr" " = \\(void \\*\\) 0x666" +gdb_test "p ssi_errno" " = 666" +gdb_test "p ssi_code" " = 999" +gdb_test "p ssi_signo" " = 11" ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [2/2] Inspect extra signal information 2009-02-06 23:35 ` Pedro Alves @ 2009-02-09 6:23 ` Paul Pluzhnikov 2009-02-09 22:17 ` Pedro Alves 0 siblings, 1 reply; 53+ messages in thread From: Paul Pluzhnikov @ 2009-02-09 6:23 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches On Fri, Feb 6, 2009 at 3:35 PM, Pedro Alves <pedro@codesourcery.com> wrote: > Here's the version of this patch that went in. AFAICT, this broke 'gdb.base/default.exp' show convenience, which expects "No debugger convenience variables ..." Instead, it gets: $ ./gdb -nx GNU gdb (GDB) 6.8.50.20090207-cvs ... This GDB was configured as "x86_64-unknown-linux-gnu". For bug reporting instructions, please see: <http://www.gnu.org/software/gdb/bugs/>. (gdb) show convenience $_siginfo = void (gdb) I find it weird to have a "void" $_siginfo ... -- Paul Pluzhnikov ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [2/2] Inspect extra signal information 2009-02-09 6:23 ` Paul Pluzhnikov @ 2009-02-09 22:17 ` Pedro Alves 2009-04-06 19:00 ` Paul Pluzhnikov 0 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-02-09 22:17 UTC (permalink / raw) To: Paul Pluzhnikov; +Cc: gdb-patches On Monday 09 February 2009 06:23:36, Paul Pluzhnikov wrote: > On Fri, Feb 6, 2009 at 3:35 PM, Pedro Alves <pedro@codesourcery.com> wrote: > > Here's the version of this patch that went in. > > AFAICT, this broke 'gdb.base/default.exp' show convenience, > which expects "No debugger convenience variables ..." > Sigh. I don't know how, but I somehow missed this one all along. I suspect I was comparing testresults with a log that already had the problem. I'll try to make sure it doesn't happen again. > Instead, it gets: > > $ ./gdb -nx > GNU gdb (GDB) 6.8.50.20090207-cvs > ... > This GDB was configured as "x86_64-unknown-linux-gnu". > For bug reporting instructions, please see: > <http://www.gnu.org/software/gdb/bugs/>. > (gdb) show convenience > $_siginfo = void > (gdb) > > I find it weird to have a "void" $_siginfo ... > That's what you get for all other convenience variables when they are empty: E.g.: >gdb-6.8 (gdb) p $_siginfo $1 = void Or: >gdb-6.8 (gdb) p $randomvar $1 = void (gdb) show convenience $randomvar = void I'm not 100% sure if we want to fix this, or if we want to adjust the testsuite instead, and making clear in the docs that the variable can be empty. We could try delaying creating the convenience variable a bit, but, how much? First stop? --- there's targets that could in principle show extra signal information without a stop (opening a core, or, opening a remote-ish target (ignore start_remote, please)). First target push (not the exec target though) ? --- sounds like a bit of a hack. Grumble. -- Pedro Alves ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [2/2] Inspect extra signal information 2009-02-09 22:17 ` Pedro Alves @ 2009-04-06 19:00 ` Paul Pluzhnikov 2009-04-06 19:18 ` relying on testsuite results Thiago Jung Bauermann 2009-04-07 14:57 ` [2/2] Inspect extra signal information Pedro Alves 0 siblings, 2 replies; 53+ messages in thread From: Paul Pluzhnikov @ 2009-04-06 19:00 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches [-- Attachment #1: Type: text/plain, Size: 619 bytes --] On Mon, Feb 9, 2009 at 3:16 PM, Pedro Alves <pedro@codesourcery.com> wrote: > I'm not 100% sure if we want to fix this, or if we want to > adjust the testsuite instead, and making clear in the docs > that the variable can be empty. Meanwhile the test continues to fail :-( Attached is a proposed cleanup. Thanks, -- Paul Pluzhnikov testsuite/ChangeLog 2009-04-06 Paul Pluzhnikov <ppluzhnikov@google.com> * gdb.base/default.exp: Fix "show convenience". doc/ChangeLog 2009-04-06 Paul Pluzhnikov <ppluzhnikov@google.com> * gdb.texinfo (convenince variables): Mention $_siginfo could be empty. [-- Attachment #2: gdb-convenience.20090406.txt --] [-- Type: text/plain, Size: 1796 bytes --] Index: testsuite/gdb.base/default.exp =================================================================== RCS file: /cvs/src/src/gdb/testsuite/gdb.base/default.exp,v retrieving revision 1.29 diff -u -p -u -r1.29 default.exp --- testsuite/gdb.base/default.exp 3 Jan 2009 05:58:03 -0000 1.29 +++ testsuite/gdb.base/default.exp 6 Apr 2009 18:43:46 -0000 @@ -598,7 +598,7 @@ gdb_test "show complaints" "Max number o #test show confirm gdb_test "show confirm" "Whether to confirm potentially dangerous operations is o\[a-z\]*." "show confirm" #test show convenience -gdb_test "show convenience" "No debugger convenience variables now defined.(\[^\r\n\]*\[\r\n\])+Convenience variables have names starting with \".\";(\[^\r\n\]*\[\r\n\])+use \"set\" as in \"set .foo = 5\" to define them." "show convenience" +gdb_test "show convenience" "\\\$_siginfo = void" "show convenience" #test show directories gdb_test "show directories" "Source directories searched: .cdir\[:;\].cwd" "show directories" #test show editing Index: doc/gdb.texinfo =================================================================== RCS file: /cvs/src/src/gdb/doc/gdb.texinfo,v retrieving revision 1.578 diff -u -p -u -r1.578 gdb.texinfo --- doc/gdb.texinfo 2 Apr 2009 15:56:08 -0000 1.578 +++ doc/gdb.texinfo 6 Apr 2009 18:43:47 -0000 @@ -7445,7 +7448,9 @@ the program being debugged terminates. @item $_siginfo @vindex $_siginfo@r{, convenience variable} The variable @code{$_siginfo} is bound to extra signal information -inspection (@pxref{extra signal information}). +inspection (@pxref{extra signal information}). Note that @code{$_siginfo} +could be empty. For example, it will be empty before you execute the +@code{run} command. @end table On HP-UX systems, if you refer to a function or variable name that ^ permalink raw reply [flat|nested] 53+ messages in thread
* relying on testsuite results 2009-04-06 19:00 ` Paul Pluzhnikov @ 2009-04-06 19:18 ` Thiago Jung Bauermann 2009-04-06 19:33 ` Paul Pluzhnikov 2009-04-06 19:51 ` Tom Tromey 2009-04-07 14:57 ` [2/2] Inspect extra signal information Pedro Alves 1 sibling, 2 replies; 53+ messages in thread From: Thiago Jung Bauermann @ 2009-04-06 19:18 UTC (permalink / raw) To: Paul Pluzhnikov; +Cc: gdb-patches Hi Paul, [ Hijacking thread, changing subject. ] El lun, 06-04-2009 a las 11:59 -0700, Paul Pluzhnikov escribió: > On Mon, Feb 9, 2009 at 3:16 PM, Pedro Alves <pedro@codesourcery.com> wrote: > > > I'm not 100% sure if we want to fix this, or if we want to > > adjust the testsuite instead, and making clear in the docs > > that the variable can be empty. > > Meanwhile the test continues to fail :-( I'm sincerely curious about why this bothers you to the point of remembering this discussion from one month ago and fixing it. I'd love to rely on testsuite results like this, but unfortunately there are too many "non-deterministic testcases" (as I call them) and they add a great deal of noise. So the most use I get from the testsuite is to run regression tests on each patch I submit, and tediously eyeball the diff looking to see if any of the PASS<->FAIL flips actuallly mean something. Do you have a way out of this except going through each of the unreliable tests and staring at them long enough to see why they flip (and that can be tricky)? -- []'s Thiago Jung Bauermann IBM Linux Technology Center ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: relying on testsuite results 2009-04-06 19:18 ` relying on testsuite results Thiago Jung Bauermann @ 2009-04-06 19:33 ` Paul Pluzhnikov 2009-04-06 19:57 ` Daniel Jacobowitz 2009-04-06 19:51 ` Tom Tromey 1 sibling, 1 reply; 53+ messages in thread From: Paul Pluzhnikov @ 2009-04-06 19:33 UTC (permalink / raw) To: Thiago Jung Bauermann; +Cc: gdb-patches On Mon, Apr 6, 2009 at 12:18 PM, Thiago Jung Bauermann <bauerman@br.ibm.com> wrote: >> Meanwhile the test continues to fail :-( > > I'm sincerely curious about why this bothers you to the point of > remembering this discussion from one month ago and fixing it. My previous experience maintaining a product with extensive test suite on multiple platforms has taught me that there are really only two states: "no failures" and "some failures". Once you enter "some failures" state, it tends to deteriorate to the point where you get new bug reports, check your testsuite, and discover that they are already catching the failure :-( > I'd love to rely on testsuite results like this, but unfortunately there > are too many "non-deterministic testcases" (as I call them) and they add > a great deal of noise. Yes, they do. I think we should have a "fixit day", when everybody cleans them up. > So the most use I get from the testsuite is to run regression tests on > each patch I submit, and tediously eyeball the diff looking to see if > any of the PASS<->FAIL flips actuallly mean something. Yes, I do the same. But I don't maintain/test the "before" tree. Instead I compare with gdb.sum-20090309, and so this failure continues to "stick out". > Do you have a way out of this except going through each of the > unreliable tests and staring at them long enough to see why they flip > (and that can be tricky)? No, I don't :-( -- Paul Pluzhnikov ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: relying on testsuite results 2009-04-06 19:33 ` Paul Pluzhnikov @ 2009-04-06 19:57 ` Daniel Jacobowitz 0 siblings, 0 replies; 53+ messages in thread From: Daniel Jacobowitz @ 2009-04-06 19:57 UTC (permalink / raw) To: Paul Pluzhnikov; +Cc: Thiago Jung Bauermann, gdb-patches On Mon, Apr 06, 2009 at 12:32:51PM -0700, Paul Pluzhnikov wrote: > > I'd love to rely on testsuite results like this, but unfortunately there > > are too many "non-deterministic testcases" (as I call them) and they add > > a great deal of noise. > > Yes, they do. > I think we should have a "fixit day", when everybody cleans them up. I used to regularly do this, but it's basically impossible to keep up. There are too many configurations and the testsuite is too disorganized. I encourage other folks to try though... The non-deterministic testcases can often be throttled down to the point where they are reasonably likely to pass. I've fixed some of the worst offenders. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: relying on testsuite results 2009-04-06 19:18 ` relying on testsuite results Thiago Jung Bauermann 2009-04-06 19:33 ` Paul Pluzhnikov @ 2009-04-06 19:51 ` Tom Tromey 2009-04-06 20:22 ` Mark Kettenis 1 sibling, 1 reply; 53+ messages in thread From: Tom Tromey @ 2009-04-06 19:51 UTC (permalink / raw) To: Thiago Jung Bauermann; +Cc: Paul Pluzhnikov, gdb-patches >>>>> "Thiago" == Thiago Jung Bauermann <bauerman@br.ibm.com> writes: Thiago> So the most use I get from the testsuite is to run regression Thiago> tests on each patch I submit, and tediously eyeball the diff Thiago> looking to see if any of the PASS<->FAIL flips actuallly mean Thiago> something. Yeah, me too. These non-deterministic tests may add something, in one scenario: if they start failing consistently, and somebody notices that, then they may provide information about a real regression. I'm sure I won't notice if they start failing consistently, though. I already ignore them. I generally do full regression tests for each patch. ("Generally" because I occasionally forget, or something goes wrong and I don't notice.) This is nice, although slow, and unfortunately also open to some kinds of major failure (e.g., a change of compiler negatively affecting baseline results). Tom ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: relying on testsuite results 2009-04-06 19:51 ` Tom Tromey @ 2009-04-06 20:22 ` Mark Kettenis 0 siblings, 0 replies; 53+ messages in thread From: Mark Kettenis @ 2009-04-06 20:22 UTC (permalink / raw) To: tromey; +Cc: bauerman, ppluzhnikov, gdb-patches > From: Tom Tromey <tromey@redhat.com> > Reply-To: tromey@redhat.com > > I generally do full regression tests for each patch. ("Generally" > because I occasionally forget, or something goes wrong and I don't > notice.) This is nice, although slow, and unfortunately also open to > some kinds of major failure (e.g., a change of compiler negatively > affecting baseline results). And there you touch upon an important reason why it is so hard to make all tests PASS. In many cases our testsuite isn't just testing GDB in isolation, but also the compiler, kernel or threads library. Unfortunately the developers of those components don't run the GDB testsuite as part of their regression testing. So things are sometimes broken and take a while to get fixed again. That said, on my preferred platform (OpenBSD) the testsuite produces fairly consistent results. We use a stable toolchain (GCC 3.3.5, binutils 2.15) which helps. And a fair number of the threads-related tests FAIL because of some Linuxisms that crept, which means they often dom't even get to the racy bits. But it is also because in the past I spent time on actually fixing broken tests. ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [2/2] Inspect extra signal information 2009-04-06 19:00 ` Paul Pluzhnikov 2009-04-06 19:18 ` relying on testsuite results Thiago Jung Bauermann @ 2009-04-07 14:57 ` Pedro Alves 1 sibling, 0 replies; 53+ messages in thread From: Pedro Alves @ 2009-04-07 14:57 UTC (permalink / raw) To: Paul Pluzhnikov; +Cc: gdb-patches On Monday 06 April 2009 19:59:49, Paul Pluzhnikov wrote: > testsuite/ChangeLog > 2009-04-06 Paul Pluzhnikov <ppluzhnikov@google.com> > > * gdb.base/default.exp: Fix "show convenience". If nobody yells, this part is OK with me. Thank you. -- Pedro Alves ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-01-12 18:47 [0/2] Inspect extra signal information Pedro Alves 2009-01-12 18:49 ` Pedro Alves 2009-01-12 18:50 ` [2/2] " Pedro Alves @ 2009-01-12 23:27 ` Mark Kettenis 2009-01-13 11:05 ` Pedro Alves 2009-02-03 15:02 ` Pedro Alves 3 siblings, 1 reply; 53+ messages in thread From: Mark Kettenis @ 2009-01-12 23:27 UTC (permalink / raw) To: pedro; +Cc: gdb-patches > From: Pedro Alves <pedro@codesourcery.com> > Date: Mon, 12 Jan 2009 18:46:51 +0000 > > Hi! > > This mini series adds support for inspecting extra signal information. > > What this means is, we get a new $_siginfo convenience variable that > is typed to look like the siginfo_t object on unix-ish platforms (but > can be any other type appropriate for the target platform). This looks pretty cool. I've often wished I had this information available. And I've also wondered about a resonable way to present it to the user. Your approach seems very reasonable to me. I can't really comment on the infrastructure to build these "computed values". But the target-sepcific support stuff seems reasonable to me. One thing I wonder about is whether it really is a good idea to is the obfuscated typenames like __uid_t instead of a straight uid_t. I realize that is the way the type is defined in headers, but in GDB we don't really have to worry about namespace pollution. The other thing I worry about is padding for these structure types that may be necessary on some platforms. Does your code handle that? ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-01-12 23:27 ` [0/2] " Mark Kettenis @ 2009-01-13 11:05 ` Pedro Alves 2009-01-13 18:42 ` Eli Zaretskii 0 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-01-13 11:05 UTC (permalink / raw) To: gdb-patches; +Cc: Mark Kettenis Hi Mark, Thanks for taking a look, and for your comments. On Monday 12 January 2009 23:24:16, Mark Kettenis wrote: > One thing I wonder about is whether it really is a good idea to is the > obfuscated typenames like __uid_t instead of a straight uid_t. I > realize that is the way the type is defined in headers, but in GDB we > don't really have to worry about namespace pollution. I don't really have much of an opinion here. I didn't think of a reason to be different, so I just cloned the types from glibc's headers. I can change that if you think it's important. > The other thing I worry about is padding for these structure types > that may be necessary on some platforms. Does your code handle that? I think so. That is handled on the synthesized type itself. There's this in linux_get_siginfo_type: + { + const int si_max_size = 128; + int si_pad_size; + int size_of_int = gdbarch_int_bit (gdbarch) / HOST_CHAR_BIT; + + /* _pad */ + if (gdbarch_ptr_bit (gdbarch) == 64) + si_pad_size = (si_max_size / size_of_int) - 4; + else + si_pad_size = (si_max_size / size_of_int) - 3; + append_composite_type_field (sifields_type, "_pad", + init_vector_type (int_type, si_pad_size)); + } Which mimics this, in glibc's headers: # define __SI_MAX_SIZE 128 # if __WORDSIZE == 64 # define __SI_PAD_SIZE ((__SI_MAX_SIZE / sizeof (int)) - 4) # else # define __SI_PAD_SIZE ((__SI_MAX_SIZE / sizeof (int)) - 3) # endif struct siginfo { int si_signo; int si_errno; int si_code; union { int _pad[__SI_PAD_SIZE]; <<< There's also this change, that allows us to add a field to a struct with enforced alignment > 0: void -append_composite_type_field (struct type *t, char *name, - struct type *field) +append_composite_type_field_aligned (struct type *t, char *name, + struct type *field, int alignment) { struct field *f; TYPE_NFIELDS (t) = TYPE_NFIELDS (t) + 1; @@ -1860,12 +1860,31 @@ append_composite_type_field (struct type { TYPE_LENGTH (t) = TYPE_LENGTH (t) + TYPE_LENGTH (field); if (TYPE_NFIELDS (t) > 1) - FIELD_BITPOS (f[0]) = (FIELD_BITPOS (f[-1]) - + (TYPE_LENGTH (FIELD_TYPE (f[-1])) - * TARGET_CHAR_BIT)); + { + FIELD_BITPOS (f[0]) = (FIELD_BITPOS (f[-1]) + + (TYPE_LENGTH (FIELD_TYPE (f[-1])) + * TARGET_CHAR_BIT)); + + if (alignment) + { + int left = FIELD_BITPOS (f[0]) % (alignment * TARGET_CHAR_BIT); + if (left) + { + FIELD_BITPOS (f[0]) += left; + TYPE_LENGTH (t) += left / TARGET_CHAR_BIT; + } + } + } } } It is used to add the _sifields field to ``struct siginfo'' aligned to ``TYPE_LENGTH (long_type)'', with: + append_composite_type_field_aligned (siginfo_type, + "_sifields", sifields_type, + TYPE_LENGTH (long_type)); -- Pedro Alves ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-01-13 11:05 ` Pedro Alves @ 2009-01-13 18:42 ` Eli Zaretskii 2009-01-13 18:50 ` Pedro Alves 0 siblings, 1 reply; 53+ messages in thread From: Eli Zaretskii @ 2009-01-13 18:42 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches, mark.kettenis > From: Pedro Alves <pedro@codesourcery.com> > Date: Tue, 13 Jan 2009 11:05:34 +0000 > Cc: Mark Kettenis <mark.kettenis@xs4all.nl> > > On Monday 12 January 2009 23:24:16, Mark Kettenis wrote: > > > One thing I wonder about is whether it really is a good idea to is the > > obfuscated typenames like __uid_t instead of a straight uid_t. I > > realize that is the way the type is defined in headers, but in GDB we > > don't really have to worry about namespace pollution. > > I don't really have much of an opinion here. I didn't think of a reason > to be different, so I just cloned the types from glibc's headers. I > can change that if you think it's important. I happen to agree with Mark. Not only we don't need to use symbols with leading underscores, it's actually forbidden by the C Standard (AFAIK). Such names are "reserved for the implementation" of the C language, which we aren't. ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-01-13 18:42 ` Eli Zaretskii @ 2009-01-13 18:50 ` Pedro Alves 2009-01-13 19:19 ` Eli Zaretskii 0 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-01-13 18:50 UTC (permalink / raw) To: gdb-patches, Eli Zaretskii; +Cc: mark.kettenis On Tuesday 13 January 2009 18:41:28, Eli Zaretskii wrote: > > From: Pedro Alves <pedro@codesourcery.com> > > Date: Tue, 13 Jan 2009 11:05:34 +0000 > > Cc: Mark Kettenis <mark.kettenis@xs4all.nl> > > > > On Monday 12 January 2009 23:24:16, Mark Kettenis wrote: > > > > > One thing I wonder about is whether it really is a good idea to is the > > > obfuscated typenames like __uid_t instead of a straight uid_t. I > > > realize that is the way the type is defined in headers, but in GDB we > > > don't really have to worry about namespace pollution. > > > > I don't really have much of an opinion here. I didn't think of a reason > > to be different, so I just cloned the types from glibc's headers. I > > can change that if you think it's important. > > I happen to agree with Mark. Not only we don't need to use symbols > with leading underscores, it's actually forbidden by the C Standard > (AFAIK). Such names are "reserved for the implementation" of the C > language, which we aren't. > I don't think that argument fits this case, because, well, this is really a kernel data type, which can use it's own rules. There's no way for this $_siginfo type to collide with anything in the user code. Also, these are also the types you'd see if I wasn't synthesizing it, but using the debug info instead, in case it is available --- I was actually doing that in a previous version of the patch, and synthesized the type only as a fallback, but, then considered that if we're synthesizing sometimes, might as well make it simpler and always synthesize -- less cases, less bugs, less maintenance. Do you not agree in the light of this perpective? I can change it, but I just want to make sure we're seeing the whole picture. -- Pedro Alves ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-01-13 18:50 ` Pedro Alves @ 2009-01-13 19:19 ` Eli Zaretskii 2009-01-13 19:37 ` Pedro Alves 0 siblings, 1 reply; 53+ messages in thread From: Eli Zaretskii @ 2009-01-13 19:19 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches, mark.kettenis > From: Pedro Alves <pedro@codesourcery.com> > Date: Tue, 13 Jan 2009 18:50:01 +0000 > Cc: mark.kettenis@xs4all.nl > > > I happen to agree with Mark. Not only we don't need to use symbols > > with leading underscores, it's actually forbidden by the C Standard > > (AFAIK). Such names are "reserved for the implementation" of the C > > language, which we aren't. > > > > I don't think that argument fits this case, because, well, this > is really a kernel data type, which can use it's own rules. There's no > way for this $_siginfo type to collide with anything in the user code. The problem is not to clash with GDB code elsewhere, the problem is the possibility of a clash with the library. A library implementation is free to change the symbol it uses for this any time, and use the __uid_t one for something utterly incompatible. Since the name begins with 2 underscores, the library implementation doesn't need to bother being back-compatible, because such names are off-limits for user code. > Also, these are also the types you'd see if I wasn't synthesizing > it, but using the debug info instead, in case it is available --- I > was actually doing that in a previous version of the patch, and > synthesized the type only as a fallback, but, then considered that > if we're synthesizing sometimes, might as well make it simpler and > always synthesize -- less cases, less bugs, less maintenance. Sorry, I don't follow: what do you mean by ``synthesizing''? ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-01-13 19:19 ` Eli Zaretskii @ 2009-01-13 19:37 ` Pedro Alves 2009-01-13 19:47 ` Pedro Alves 0 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-01-13 19:37 UTC (permalink / raw) To: gdb-patches, Eli Zaretskii; +Cc: mark.kettenis On Tuesday 13 January 2009 19:18:05, Eli Zaretskii wrote: > The problem is not to clash with GDB code elsewhere, the problem is > the possibility of a clash with the library. A library implementation When I meant user code, I didn't mean *GDB* code, which of course it can't collide with, because I wrote literal strings, not identifiers. I meant code that isn't part of the C (library) implementation. > is free to change the symbol it uses for this any time, and use the > __uid_t one for something utterly incompatible. Since the name begins > with 2 underscores, the library implementation doesn't need to bother > being back-compatible, because such names are off-limits for user code. No, it is allowed to assume that the type name will not collide with any user defined type. It's only about namespace, that's all. Things will surelly break if the type changes to something else incompatible. In any case, user code will want to be using the si_pid, si_uid, si_status, si_addr, etc, X/Open macros. I'm *really exposing* C library internals. > > > Also, these are also the types you'd see if I wasn't synthesizing > > it, but using the debug info instead, in case it is available --- I > > was actually doing that in a previous version of the patch, and > > synthesized the type only as a fallback, but, then considered that > > if we're synthesizing sometimes, might as well make it simpler and > > always synthesize -- less cases, less bugs, less maintenance. > > Sorry, I don't follow: what do you mean by ``synthesizing''? It means that I'm building the ``struct type'' that represents this siginfo_t type "manually", instead of relying on debug info for it being available. What I was aiming for, is to see the same you see when you do this (this is from the already in tree siginfo-addr.exp BTW): static void handler (int sig, siginfo_t *info, void *context) { if (info->si_addr == p) printf ("Correct si_addr value.\n"); else printf ("Got si_addr = %p, expected %p.\n", info->si_addr, p); _exit (0); } static void *p; int main (void) { (...) /* Trigger SIGSEGV. */ *(int *)p = 0; return 0; } (gdb) b handler Breakpoint 1 at 0x40070b: file ../../../src/gdb/testsuite/gdb.base/siginfo-addr.c, line 32. (gdb) r Starting program: /home/pedro/gdb/siginfo/build/gdb/testsuite/gdb.base/siginfo-addr Program received signal SIGSEGV, Segmentation fault. 0x000000000040081b in main () at ../../../src/gdb/testsuite/gdb.base/siginfo-addr.c:66 66 *(int *)p = 0; (gdb) c Continuing. Breakpoint 1, handler (sig=11, info=0x7fffffffe130, context=0x7fffffffe000) at ../../../src/gdb/testsuite/gdb.base/siginfo-addr.c:32 32 if (info->si_addr == p) (gdb) (gdb) ptype info->_sifields type = union { int _pad[28]; struct { __pid_t si_pid; __uid_t si_uid; } _kill; struct { int si_tid; int si_overrun; sigval_t si_sigval; } _timer; struct { __pid_t si_pid; __uid_t si_uid; sigval_t si_sigval; } _rt; struct { __pid_t si_pid; __uid_t si_uid; int si_status; __clock_t si_utime; __clock_t si_stime; } _sigchld; struct { void *si_addr; } _sigfault; struct { long int si_band; int si_fd; } _sigpoll; } (gdb) Notice that these types came from debug info (but only because I siginfo_t, which will not be the common case). Versus the synthesized: (gdb) r Starting program: /home/pedro/gdb/siginfo/build/gdb/testsuite/gdb.base/siginfo-addr During symbol reading, DW_AT_name missing from DW_TAG_base_type. Program received signal SIGSEGV, Segmentation fault. 0x000000000040081b in main () at ../../../src/gdb/testsuite/gdb.base/siginfo-addr.c:66 66 *(int *)p = 0; (gdb) ptype $_siginfo._sifields type = union { int _pad[28]; struct { __pid_t si_pid; __uid_t si_uid; } _kill; struct { int si_tid; int si_overrun; sigval_t si_sigval; } _timer; struct { __pid_t si_pid; __uid_t si_uid; sigval_t si_sigval; } _rt; struct { __pid_t si_pid; __uid_t si_uid; int si_status; __clock_t si_utime; __clock_t si_stime; } _sigchld; struct { void *si_addr; } _sigfault; struct { long si_band; int si_fd; } _sigpoll; } -- Pedro Alves ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-01-13 19:37 ` Pedro Alves @ 2009-01-13 19:47 ` Pedro Alves 2009-02-02 14:40 ` Pedro Alves 0 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-01-13 19:47 UTC (permalink / raw) To: gdb-patches; +Cc: Eli Zaretskii, mark.kettenis On Tuesday 13 January 2009 19:37:25, Pedro Alves wrote: > > is free to change the symbol it uses for this any time, and use the > > __uid_t one for something utterly incompatible. Since the name begins > > with 2 underscores, the library implementation doesn't need to bother > > being back-compatible, because such names are off-limits for user code. > > No, it is allowed to assume that the type name will not collide with > any user defined type. It's only about namespace, that's all. Things will > surelly break if the type changes to something else incompatible. Oh well, I think I said the same thing you did anyway. :-) -- Pedro Alves ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-01-13 19:47 ` Pedro Alves @ 2009-02-02 14:40 ` Pedro Alves 2009-02-02 20:49 ` Mark Kettenis 0 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-02-02 14:40 UTC (permalink / raw) To: gdb-patches; +Cc: Eli Zaretskii, mark.kettenis Hi guys, I'm looking at this again. Given the argument that with this patch, the siginfo_t type before the signal is delivered is the the same as what is seen on the signal handler, when the signal is delivered to the inferior inferior, do you still think I should change the type, or are you OK with how things are? Is there anything else I should do to make this good to go? Thanks, -- Pedro Alves ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-02-02 14:40 ` Pedro Alves @ 2009-02-02 20:49 ` Mark Kettenis 0 siblings, 0 replies; 53+ messages in thread From: Mark Kettenis @ 2009-02-02 20:49 UTC (permalink / raw) To: pedro; +Cc: gdb-patches, eliz, mark.kettenis > From: Pedro Alves <pedro@codesourcery.com> > Date: Mon, 2 Feb 2009 14:42:00 +0000 > > Hi guys, I'm looking at this again. > > Given the argument that with this patch, the siginfo_t type before the signal > is delivered is the the same as what is seen on the signal handler, when > the signal is delivered to the inferior inferior, do you still think I > should change the type, or are you OK with how things are? I have no real issues with using the obfuscated type names. Just thought it was a bit ugly and thought users might prefer the unobfuscated names. But since I don't use Linux all that much, I don't really care. ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-01-12 18:47 [0/2] Inspect extra signal information Pedro Alves ` (2 preceding siblings ...) 2009-01-12 23:27 ` [0/2] " Mark Kettenis @ 2009-02-03 15:02 ` Pedro Alves 2009-02-03 16:42 ` Ulrich Weigand 3 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-02-03 15:02 UTC (permalink / raw) To: gdb-patches On Monday 12 January 2009 18:46:51, Pedro Alves wrote: > - Adds a new gdbarch method (get_siginfo_type) whose job is to return a type > suitable to print/inspect a TARGET_OBJECT_SIGNAL_INFO of a given arch. Boo, turns out that I had tested on x86-64: - 64-bit gdb x 64-bit inferior, 64-bit kernel siginfo comes out with the 64-bit layout. - 32-bit gdb x 32-bit inferior, 64-bit kernel siginfo comes out with the 32-bit layout. But, I thought I had, but I clearly didn't test before: - 64-bit gdb x 32-bit inferior, 64-bit kernel siginfo comes out with the 64-bit layout. ^^^^^^ The current patch assumed that PTRACE_GETSIGINFO would return an object with the layout of the 32-bit inferior, but, we actually get a 64-bit object. In sum, the data/type returned by PTRACE_GETSIGINFO is dependent on the arch of the *superior* (gdb). The current patch was using the gdbarch of the current frame, but, it is clear now that that is not the gdbarch we want. I was looking at target_gdbarch, and it doesn't seem to fit the bill either. E.g., a biarch ppc64 gdbserver returns a 32-bit target_arch if the inferior is 32-bit. (now that I'm looking at it, can't an inferior that started out as 32-bit call 64-bit code? If so, it seems that gdbserver and target_gdbarch does not cope with that.) The options I'm seeing are either: - come up with a new target/host *interface* gdbarch, and pass that along in the target description. Use that gdbarch to build up the siginfo type, on the gdb side. - extend the xml type description support to be rich enough to describe the siginfo_t type (structs, typedefs, etc), and pass that along in the target description. Any suggestions? Other alternatives? -- Pedro Alves ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-02-03 15:02 ` Pedro Alves @ 2009-02-03 16:42 ` Ulrich Weigand 2009-02-03 18:06 ` Daniel Jacobowitz 2009-02-03 18:23 ` [0/2] Inspect extra signal information Pedro Alves 0 siblings, 2 replies; 53+ messages in thread From: Ulrich Weigand @ 2009-02-03 16:42 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches Pedro Alves wrote: > Boo, turns out that I had tested on x86-64: > > - 64-bit gdb x 64-bit inferior, 64-bit kernel > > siginfo comes out with the 64-bit layout. > > - 32-bit gdb x 32-bit inferior, 64-bit kernel > > siginfo comes out with the 32-bit layout. > > > But, I thought I had, but I clearly didn't test before: > > - 64-bit gdb x 32-bit inferior, 64-bit kernel > > siginfo comes out with the 64-bit layout. > ^^^^^^ Huh. With bi-arch setups, I understand everything is currently supposed to be set up so that debugging a 32-bit program with a 64-bit GDB looks just the same as debugging it with a 32-bit GDB. The above would break that assumption: you see different types of siginfo depending on your host GDB. I'm not sure if that is really what we want ... On the other hand, it's going to be difficult to avoid. One way would be for the Linux native target to always return the 32-bit layout when debugging a 32-bit inferior; if necessary it would have to convert the data in-place before returning it (similar to how the native target today converts register contents to 32 bit even though the ptrace interface returns 64 bit values). > I was looking at target_gdbarch, and it doesn't seem to fit the > bill either. E.g., a biarch ppc64 gdbserver returns a 32-bit > target_arch if the inferior is 32-bit. That's actually an interesting question. The idea behind "target_gdbarch" is "the architecture implemented by the target debugger interface". In a bi-arch setup, the target today emulates a 32-bit target interface when debugging a 32-bit inferior, even when GDB itself is 64-bit. This is done by explicit conversion in the native target (see above). Before real multi-architecture support, there really was to other way to do it. However, once we get to full multi-arch, it might in fact be a more natural fit to model the bi-arch setup by having "target_gdbarch" indicate the actual bitness of the ptrace interface (i.e. 64-bit), while still setting the per-frame architecture of all frames to the appropriate 32-bit architecture ... This might allow us to get rid of some of the bi-arch special hacks in native target code. Bye, Ulrich -- Dr. Ulrich Weigand GNU Toolchain for Linux on System z and Cell BE Ulrich.Weigand@de.ibm.com ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-02-03 16:42 ` Ulrich Weigand @ 2009-02-03 18:06 ` Daniel Jacobowitz 2009-02-03 18:24 ` Pedro Alves 2009-02-03 18:23 ` [0/2] Inspect extra signal information Pedro Alves 1 sibling, 1 reply; 53+ messages in thread From: Daniel Jacobowitz @ 2009-02-03 18:06 UTC (permalink / raw) To: Ulrich Weigand; +Cc: Pedro Alves, gdb-patches On Tue, Feb 03, 2009 at 05:42:21PM +0100, Ulrich Weigand wrote: > On the other hand, it's going to be difficult to avoid. One > way would be for the Linux native target to always return > the 32-bit layout when debugging a 32-bit inferior; if necessary > it would have to convert the data in-place before returning it > (similar to how the native target today converts register contents > to 32 bit even though the ptrace interface returns 64 bit values). I like this idea. We'd just need a "native siginfo to gdb siginfo" routine, which could probably live in one common native-only file. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-02-03 18:06 ` Daniel Jacobowitz @ 2009-02-03 18:24 ` Pedro Alves 2009-02-03 19:04 ` Daniel Jacobowitz 0 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-02-03 18:24 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: Ulrich Weigand, gdb-patches On Tuesday 03 February 2009 18:06:17, Daniel Jacobowitz wrote: > I like this idea. We'd just need a "native siginfo to gdb siginfo" > routine, which could probably live in one common native-only file. Hmmm, what do you mean exactly by "gdb siginfo" here? -- Pedro Alves ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-02-03 18:24 ` Pedro Alves @ 2009-02-03 19:04 ` Daniel Jacobowitz 2009-02-03 19:51 ` Pedro Alves 0 siblings, 1 reply; 53+ messages in thread From: Daniel Jacobowitz @ 2009-02-03 19:04 UTC (permalink / raw) To: Pedro Alves; +Cc: Ulrich Weigand, gdb-patches On Tue, Feb 03, 2009 at 06:24:21PM +0000, Pedro Alves wrote: > On Tuesday 03 February 2009 18:06:17, Daniel Jacobowitz wrote: > > I like this idea. Â We'd just need a "native siginfo to gdb siginfo" > > routine, which could probably live in one common native-only file. > > Hmmm, what do you mean exactly by "gdb siginfo" here? Whatever type you've constructed via the gdbarch. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-02-03 19:04 ` Daniel Jacobowitz @ 2009-02-03 19:51 ` Pedro Alves 2009-02-03 23:18 ` Doug Evans 2009-02-04 0:24 ` Daniel Jacobowitz 0 siblings, 2 replies; 53+ messages in thread From: Pedro Alves @ 2009-02-03 19:51 UTC (permalink / raw) To: Daniel Jacobowitz; +Cc: Ulrich Weigand, gdb-patches On Tuesday 03 February 2009 19:04:32, Daniel Jacobowitz wrote: > On Tue, Feb 03, 2009 at 06:24:21PM +0000, Pedro Alves wrote: > > On Tuesday 03 February 2009 18:06:17, Daniel Jacobowitz wrote: > > > I like this idea. We'd just need a "native siginfo to gdb siginfo" > > > routine, which could probably live in one common native-only file. > > > > Hmmm, what do you mean exactly by "gdb siginfo" here? > > Whatever type you've constructed via the gdbarch. > There are two points of information here. First, the raw data of the siginfo_t object, passed around with TARGET_OBJECT_SIGNAL_INFO, which is implemented by both native linux target, and gdbserver. This transfers a block of raw data. Then, there's the the gdbarch built type, which is used to interpret the data. So, we're talking about making sure the TARGET_OBJECT_SIGNAL_INFO object is converted to a a 32-bit layout before reaching the core of gdb, to match what the type contructed by gdbarch will expect. I'd like to come up with something that works equally well and is simple, in both native gdb and gdbserver implementation sides. I hacked the below into linux-nat.c, which works OK for i386/amd64 just to see it work. The siginfo layout is different depending on the architecture, so although this layout works for some archs, it doesn't for others, e.g, mips, has this: typedef struct siginfo { int si_signo; /* Signal number. */ int si_code; /* Signal code. */ int si_errno; /* If non-zero, an errno value associated with this signal, as defined in <errno.h>. */ int __pad0[__SI_MAX_SIZE / sizeof (int) - __SI_PAD_SIZE - 3]; ^^^^^^ union { I was thinking on doing this in the arch specific native files, e.g, gdb/amd64-linux-nat.c, gdb/ppc-linux-nat.c, etc., and something similar in gdbserver too. Just to make sure, where you perhaps thinking of something entirely different? I don't see how to make this in a common native file. --- src.orig/gdb/linux-nat.c 2009-02-03 19:20:49.000000000 +0000 +++ src/gdb/linux-nat.c 2009-02-03 19:26:33.000000000 +0000 @@ -3214,6 +3214,26 @@ linux_nat_mourn_inferior (struct target_ linux_fork_mourn_inferior (); } +struct gdb_siginfo32 + { + int si_signo; + int si_errno; + int si_code; + + union + { + int _pad[29]; + struct + { + int _si_pid; + unsigned int _si_uid; + int _si_status; + int _si_utime; + int _si_stime; + } _sigchld; + } _sifields; + }; + static LONGEST linux_xfer_siginfo (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, @@ -3239,6 +3259,25 @@ linux_xfer_siginfo (struct target_ops *o if (errno != 0) return -1; + if (gdbarch_addr_bit (current_gdbarch) == 32) + { + struct gdb_siginfo32 siginfo32; + struct siginfo sigi; + + gdb_assert (sizeof (siginfo32) == sizeof (siginfo)); + + siginfo32.si_signo = siginfo.si_signo; + siginfo32.si_errno = siginfo.si_errno; + siginfo32.si_code = siginfo.si_code; + siginfo32._sifields._sigchld._si_pid = siginfo.si_pid; + siginfo32._sifields._sigchld._si_uid = siginfo.si_uid; + siginfo32._sifields._sigchld._si_status = siginfo.si_status; + siginfo32._sifields._sigchld._si_utime = siginfo.si_utime; + siginfo32._sifields._sigchld._si_stime = siginfo.si_stime; + + memcpy (&siginfo, &siginfo32, sizeof (siginfo)); + } + -- Pedro Alves ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-02-03 19:51 ` Pedro Alves @ 2009-02-03 23:18 ` Doug Evans 2009-02-03 23:50 ` Pedro Alves 2009-02-04 0:24 ` Daniel Jacobowitz 1 sibling, 1 reply; 53+ messages in thread From: Doug Evans @ 2009-02-03 23:18 UTC (permalink / raw) To: Pedro Alves; +Cc: Daniel Jacobowitz, Ulrich Weigand, gdb-patches On Tue, Feb 3, 2009 at 11:51 AM, Pedro Alves <pedro@codesourcery.com> wrote: > On Tuesday 03 February 2009 19:04:32, Daniel Jacobowitz wrote: >> On Tue, Feb 03, 2009 at 06:24:21PM +0000, Pedro Alves wrote: >> > On Tuesday 03 February 2009 18:06:17, Daniel Jacobowitz wrote: >> > > I like this idea. We'd just need a "native siginfo to gdb siginfo" >> > > routine, which could probably live in one common native-only file. >> > >> > Hmmm, what do you mean exactly by "gdb siginfo" here? >> >> Whatever type you've constructed via the gdbarch. >> > > There are two points of information here. First, the raw data of > the siginfo_t object, passed around with TARGET_OBJECT_SIGNAL_INFO, > which is implemented by both native linux target, and gdbserver. > This transfers a block of raw data. Then, there's the the gdbarch > built type, which is used to interpret the data. So, we're talking about > making sure the TARGET_OBJECT_SIGNAL_INFO object is converted to a > a 32-bit layout before reaching the core of gdb, to match what the type > contructed by gdbarch will expect. > > I'd like to come up with something that works equally well and > is simple, in both native gdb and gdbserver implementation sides. > > I hacked the below into linux-nat.c, which works OK for i386/amd64 > just to see it work. > > The siginfo layout is different depending on the architecture, so > although this layout works for some archs, it doesn't for others, > e.g, mips, has this: > > typedef struct siginfo > { > int si_signo; /* Signal number. */ > int si_code; /* Signal code. */ > int si_errno; /* If non-zero, an errno value associated with > this signal, as defined in <errno.h>. */ > int __pad0[__SI_MAX_SIZE / sizeof (int) - __SI_PAD_SIZE - 3]; > > ^^^^^^ > union > { > > > I was thinking on doing this in the arch specific native files, e.g, > gdb/amd64-linux-nat.c, gdb/ppc-linux-nat.c, etc., and something similar in > gdbserver too. > > Just to make sure, where you perhaps thinking of something > entirely different? I don't see how to make this in a common native > file. > > --- src.orig/gdb/linux-nat.c 2009-02-03 19:20:49.000000000 +0000 > +++ src/gdb/linux-nat.c 2009-02-03 19:26:33.000000000 +0000 > @@ -3214,6 +3214,26 @@ linux_nat_mourn_inferior (struct target_ > linux_fork_mourn_inferior (); > } > > +struct gdb_siginfo32 > + { > + int si_signo; > + int si_errno; > + int si_code; > + > + union > + { > + int _pad[29]; > + struct > + { > + int _si_pid; > + unsigned int _si_uid; > + int _si_status; > + int _si_utime; > + int _si_stime; > + } _sigchld; > + } _sifields; > + }; > + > > static LONGEST > linux_xfer_siginfo (struct target_ops *ops, enum target_object object, > const char *annex, gdb_byte *readbuf, > @@ -3239,6 +3259,25 @@ linux_xfer_siginfo (struct target_ops *o > if (errno != 0) > return -1; > > + if (gdbarch_addr_bit (current_gdbarch) == 32) > + { > + struct gdb_siginfo32 siginfo32; > + struct siginfo sigi; > + > + gdb_assert (sizeof (siginfo32) == sizeof (siginfo)); > + > + siginfo32.si_signo = siginfo.si_signo; > + siginfo32.si_errno = siginfo.si_errno; > + siginfo32.si_code = siginfo.si_code; > + siginfo32._sifields._sigchld._si_pid = siginfo.si_pid; > + siginfo32._sifields._sigchld._si_uid = siginfo.si_uid; > + siginfo32._sifields._sigchld._si_status = siginfo.si_status; > + siginfo32._sifields._sigchld._si_utime = siginfo.si_utime; > + siginfo32._sifields._sigchld._si_stime = siginfo.si_stime; > + > + memcpy (&siginfo, &siginfo32, sizeof (siginfo)); > + } > + One can either read the struct info buffer returned by ptrace directly (as in the above "mumble = siginfo.si_signo;") or one can use a constructed gdbarch siginfo type that maps directly to a struct siginfo buffer returned by ptrace and use that to access it. Then one could write a routine that given either of those (pick one), and a pointer to the desired siginfo type, and returns a new value in the desired type. With this gdbserver can continue to just pass the raw buffer back to gdb. Otherwise I guess you'd have to switch to passing back a semi-formatted buffer of values from gdbserver that gdb can then parse. Does that make sense? ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-02-03 23:18 ` Doug Evans @ 2009-02-03 23:50 ` Pedro Alves 2009-02-04 0:17 ` Doug Evans 0 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-02-03 23:50 UTC (permalink / raw) To: Doug Evans; +Cc: Daniel Jacobowitz, Ulrich Weigand, gdb-patches On Tuesday 03 February 2009 23:18:40, Doug Evans wrote: > One can either read the struct info buffer returned by ptrace directly > (as in the above "mumble = siginfo.si_signo;") Right, this is something similar to what the kernel does in its conversion routines for 32-bit userspace support. > or one can use a > constructed gdbarch siginfo type that maps directly to a struct > siginfo buffer returned by ptrace and use that to access it. Then one > could write a routine that given either of those (pick one), and a > pointer to the desired siginfo type, and returns a new value in the > desired type. When connected to a 64-bit gdbserver that is debugging a 32-bit inferior, how would gdb know that the binary blob that is coming out of TARGET_OBJECT_SIGNAL_INFO has the 64-bit layout, and that it needs to be converted? All gdbarchs that we have accessible tell us about the inferior arch, which is 32-bit. gdb has no idea that the gdbserver is running a 64-bit ptrace. > > With this gdbserver can continue to just pass the raw buffer back to > gdb. I don't see how given that missing link. > Otherwise I guess you'd have to switch to passing back a > semi-formatted buffer of values from gdbserver that gdb can then > parse. > > > Does that make sense? -- Pedro Alves ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-02-03 23:50 ` Pedro Alves @ 2009-02-04 0:17 ` Doug Evans 0 siblings, 0 replies; 53+ messages in thread From: Doug Evans @ 2009-02-04 0:17 UTC (permalink / raw) To: Pedro Alves; +Cc: Daniel Jacobowitz, Ulrich Weigand, gdb-patches On Tue, Feb 3, 2009 at 3:50 PM, Pedro Alves <pedro@codesourcery.com> wrote: > When connected to a 64-bit gdbserver that is debugging a 32-bit > inferior, how would gdb know that the binary blob that is coming out > of TARGET_OBJECT_SIGNAL_INFO has the 64-bit layout, and that it > needs to be converted? All gdbarchs that we have accessible tell us > about the inferior arch, which is 32-bit. gdb has no idea that the > gdbserver is running a 64-bit ptrace. Hmmm, I'd forgotten the "using gdb compiled for amd64 talking to a gdbserver compiled for i386" case. Blech. GDB could send a query request for the necessary info. OOC, are there other reasons why gdb would want to know which host gdbserver was compiled for? ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-02-03 19:51 ` Pedro Alves 2009-02-03 23:18 ` Doug Evans @ 2009-02-04 0:24 ` Daniel Jacobowitz 2009-02-04 0:49 ` Pedro Alves 1 sibling, 1 reply; 53+ messages in thread From: Daniel Jacobowitz @ 2009-02-04 0:24 UTC (permalink / raw) To: Pedro Alves; +Cc: Ulrich Weigand, gdb-patches On Tue, Feb 03, 2009 at 07:51:44PM +0000, Pedro Alves wrote: > I was thinking on doing this in the arch specific native files, e.g, > gdb/amd64-linux-nat.c, gdb/ppc-linux-nat.c, etc., and something similar in > gdbserver too. > > Just to make sure, where you perhaps thinking of something > entirely different? I don't see how to make this in a common native > file. What Doug described is pretty similar to what I had in mind; it does not fix the issue for gdbserver, but does for gdb. Read each field of the ptrace buffer, then use gdbarch to retrieve the type this would be expected to have in the inferior. Use gdb's type/value machinery to store the raw fields into the new value. Pass that value's contents back through the target layer to gdb, which will see the right values because it uses the same gdbarch to interpret them. Now, whether those hoops are worth it is another question. If we have to do this in gdbserver anyway, we could use the same method in gdb. I vaguely remember having to do something similar for Solaris's procfs. Only biarch platforms would have this problem, and fortunately there aren't too many. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-02-04 0:24 ` Daniel Jacobowitz @ 2009-02-04 0:49 ` Pedro Alves 2009-02-04 21:02 ` [3/2] Inspect extra signal information, handle amd64 bi-arch gdb Pedro Alves 0 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-02-04 0:49 UTC (permalink / raw) To: gdb-patches; +Cc: Daniel Jacobowitz, Ulrich Weigand On Wednesday 04 February 2009 00:24:38, Daniel Jacobowitz wrote: > What Doug described is pretty similar to what I had in mind; it does > not fix the issue for gdbserver, but does for gdb. Read each field of > the ptrace buffer, then use gdbarch to retrieve the type this would be > expected to have in the inferior. Use gdb's type/value machinery to > store the raw fields into the new value. Pass that value's contents > back through the target layer to gdb, which will see the right values > because it uses the same gdbarch to interpret them. A few emails ago I mentioned "if I make use of struct type/struct value if may not be bad, but, gdbserver can't use those..." :-), and I was also thinking of something similar, but simpler. I was thinking of building up a value with the 64-bit type (gdb knows how to build it already), and pass it the raw 64-bit data. Then build a new value with the 32-bit data, and iterate simulatenously in both values through each field and copy/convert each field to the 32-bit value, as appropriate. But as you say below, I don't like having two ways to do the same thing, given that something has to be done on the gdbserver side. > Now, whether those hoops are worth it is another question. If we have > to do this in gdbserver anyway, we could use the same method in gdb. That's my thinking too. I'm half through, let's see what comes out... > I vaguely remember having to do something similar for Solaris's > procfs. Yep. I remember that. It was related to that fact that auxv data in procfs is presented with a 64-bit layout to a 64-bit gdb, even if the inferior is 32-bit. If I'm not mistaken: 2008-05-04 Vladimir Prus ... * target.h (struct target_ops): New field to_auxv_parse. * auxv.c (default_auxv_parse): New, renamed from previous target_auxv_parse. (target_auxv_parse): Try to call target method. Fallback to default_auxv_parse if not found. * procfs.c (procfs_auxv_parse): New. (init_procfs_ops): On Solaris, in 64-bit mode, install procfs_auxv_parse. > Only biarch platforms would have this problem, and fortunately there > aren't too many. -- Pedro Alves ^ permalink raw reply [flat|nested] 53+ messages in thread
* [3/2] Inspect extra signal information, handle amd64 bi-arch gdb 2009-02-04 0:49 ` Pedro Alves @ 2009-02-04 21:02 ` Pedro Alves 2009-02-04 21:17 ` Daniel Jacobowitz 2009-02-04 22:07 ` Doug Evans 0 siblings, 2 replies; 53+ messages in thread From: Pedro Alves @ 2009-02-04 21:02 UTC (permalink / raw) To: gdb-patches; +Cc: Daniel Jacobowitz, Ulrich Weigand [-- Attachment #1: Type: text/plain, Size: 706 bytes --] Here's a patch that applies on top of the other two. I think it's easy to read it split out from the other patches. This handles the layout conversion for x86/amd64, near the PTRACE_[G|S]ETSIGINFO calls, like we discussed yesterday. I'm not adjusting gdbserver here yet, since the original series added $_siginfo support for ARM, and x86/amd64 only, and, gdbserver on x86/amd64 isn't biarch aware yet. We can handle doing something like this there when we add $_siginfo gdbarch type support for ppc, or when we add biarch support for x86/amd64. What do you think? I've tried to make it as pretty as I could. :-) Please, don't hesitate pointing me at anything bogus I may be doing. -- Pedro Alves [-- Attachment #2: siginfo_convrt.diff --] [-- Type: text/x-diff, Size: 11864 bytes --] 2009-02-04 Pedro Alves <pedro@codesourcery.com> * amd64-linux-nat.c (compat_int_t, compat_uptr_t, compat_time_t) (compat_timer_t, compat_clock_t, struct compat_timeval) (compat_sigval_t, compat_siginfo_t): New types. (cpt_si_pid, cpt_si_uid, cpt_si_timerid, cpt_si_overrun) (cpt_si_status, cpt_si_utime, cpt_si_stime, cpt_si_ptr) (cpt_si_addr, cpt_si_band, cpt_si_fd): New defines. (compat_siginfo_from_siginfo, siginfo_from_compat_siginfo) (amd64_linux_siginfo_fixup): New. * linux-nat.c (linux_nat_siginfo_fixup): New. (siginfo_fixup): New. (linux_xfer_siginfo): Use siginfo_fixup to convert between the siginfo layout expected by ptrace and the siginfo layout of the inferior. (linux_nat_set_siginfo_fixup): New. * linux-nat.h (linux_nat_set_siginfo_fixup): Declare. --- gdb/amd64-linux-nat.c | 232 ++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/linux-nat.c | 59 ++++++++++++ gdb/linux-nat.h | 8 + 3 files changed, 297 insertions(+), 2 deletions(-) Index: src/gdb/amd64-linux-nat.c =================================================================== --- src.orig/gdb/amd64-linux-nat.c 2009-02-03 19:20:38.000000000 +0000 +++ src/gdb/amd64-linux-nat.c 2009-02-04 20:11:59.000000000 +0000 @@ -400,6 +400,237 @@ amd64_linux_child_post_startup_inferior } \f +/* When GDB is built as a 64-bit application on linux, the + PTRACE_GETSIGINFO data is always presented in 64-bit layout. Since + debugging a 32-bit inferior with a 64-bit GDB should look the same + as debugging it with a 32-bit GDB, we do the 32-bit <-> 64-bit + conversion in-place ourselves. */ + +/* These types below (compat_*) define a siginfo type that is layout + compatible with the siginfo type exported by the 32-bit userspace + support. */ + +typedef int compat_int_t; +typedef unsigned int compat_uptr_t; + +typedef int compat_time_t; +typedef int compat_timer_t; +typedef int compat_clock_t; + +struct compat_timeval +{ + compat_time_t tv_sec; + int tv_usec; +}; + +typedef union compat_sigval +{ + compat_int_t sival_int; + compat_uptr_t sival_ptr; +} compat_sigval_t; + +typedef struct compat_siginfo +{ + int si_signo; + int si_errno; + int si_code; + + union + { + int _pad[((128 / sizeof (int)) - 3)]; + + /* kill() */ + struct + { + unsigned int _pid; + unsigned int _uid; + } _kill; + + /* POSIX.1b timers */ + struct + { + compat_timer_t _tid; + int _overrun; + compat_sigval_t _sigval; + } _timer; + + /* POSIX.1b signals */ + struct + { + unsigned int _pid; + unsigned int _uid; + compat_sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct + { + unsigned int _pid; + unsigned int _uid; + int _status; + compat_clock_t _utime; + compat_clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct + { + unsigned int _addr; + } _sigfault; + + /* SIGPOLL */ + struct + { + int _band; + int _fd; + } _sigpoll; + } _sifields; +} compat_siginfo_t; + +#define cpt_si_pid _sifields._kill._pid +#define cpt_si_uid _sifields._kill._uid +#define cpt_si_timerid _sifields._timer._tid +#define cpt_si_overrun _sifields._timer._overrun +#define cpt_si_status _sifields._sigchld._status +#define cpt_si_utime _sifields._sigchld._utime +#define cpt_si_stime _sifields._sigchld._stime +#define cpt_si_ptr _sifields._rt._sigval.sival_ptr +#define cpt_si_addr _sifields._sigfault._addr +#define cpt_si_band _sifields._sigpoll._band +#define cpt_si_fd _sifields._sigpoll._fd + +static void +compat_siginfo_from_siginfo (compat_siginfo_t *to, siginfo_t *from) +{ + memset (to, 0, sizeof (*to)); + + to->si_signo = from->si_signo; + to->si_errno = from->si_errno; + to->si_code = from->si_code; + + if (to->si_code < 0) + { + to->cpt_si_ptr = (intptr_t) from->si_ptr; + } + else if (to->si_code == SI_USER) + { + to->cpt_si_pid = from->si_pid; + to->cpt_si_uid = from->si_uid; + } + else if (to->si_code == SI_TIMER) + { + to->cpt_si_timerid = from->si_timerid; + to->cpt_si_overrun = from->si_overrun; + to->cpt_si_ptr = (intptr_t) from->si_ptr; + } + else + { + switch (to->si_signo) + { + case SIGCHLD: + to->cpt_si_pid = from->si_pid; + to->cpt_si_uid = from->si_uid; + to->cpt_si_status = from->si_status; + to->cpt_si_utime = from->si_utime; + to->cpt_si_stime = from->si_stime; + break; + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + to->cpt_si_addr = (intptr_t) from->si_addr; + break; + case SIGPOLL: + to->cpt_si_band = from->si_band; + to->cpt_si_fd = from->si_fd; + break; + default: + to->cpt_si_pid = from->si_pid; + to->cpt_si_uid = from->si_uid; + to->cpt_si_ptr = (intptr_t) from->si_ptr; + } + } +} + +static void +siginfo_from_compat_siginfo (siginfo_t *to, compat_siginfo_t *from) +{ + memset (to, 0, sizeof (*to)); + + to->si_signo = from->si_signo; + to->si_errno = from->si_errno; + to->si_code = from->si_code; + + if (to->si_code < 0) + { + to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr; + } + else if (to->si_code == SI_USER) + { + to->si_pid = from->cpt_si_pid; + to->si_uid = from->cpt_si_uid; + } + else if (to->si_code == SI_TIMER) + { + to->si_timerid = from->cpt_si_timerid; + to->si_overrun = from->cpt_si_overrun; + to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr; + } + else + { + switch (to->si_signo) + { + case SIGCHLD: + to->si_pid = from->cpt_si_pid; + to->si_uid = from->cpt_si_uid; + to->si_status = from->cpt_si_status; + to->si_utime = from->cpt_si_utime; + to->si_stime = from->cpt_si_stime; + break; + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + to->si_addr = (void *) (intptr_t) from->cpt_si_addr; + break; + case SIGPOLL: + to->si_band = from->cpt_si_band; + to->si_fd = from->cpt_si_fd; + break; + default: + to->si_pid = from->cpt_si_pid; + to->si_uid = from->cpt_si_uid; + to->si_ptr = (void* ) (intptr_t) from->cpt_si_ptr; + } + } +} + +/* Convert a native/host siginfo object, into/from the siginfo in the + layout of the inferiors' architecture. Returns true if any + conversion was done; false otherwise. If DIRECTION is 1, then copy + from INF to NATIVE. If DIRECTION is 0, copy from NATIVE to + INF. */ + +static int +amd64_linux_siginfo_fixup (struct siginfo *native, gdb_byte *inf, int direction) +{ + /* Is the inferior 32-bit? If so, then do fixup the siginfo + object. */ + if (gdbarch_addr_bit (get_frame_arch (get_current_frame ())) == 32) + { + gdb_assert (sizeof (struct siginfo) == sizeof (compat_siginfo_t)); + + if (direction == 0) + compat_siginfo_from_siginfo ((struct compat_siginfo *) inf, native); + else + siginfo_from_compat_siginfo (native, (struct compat_siginfo *) inf); + + return 1; + } + else + return 0; +} + /* Provide a prototype to silence -Wmissing-prototypes. */ void _initialize_amd64_linux_nat (void); @@ -434,4 +665,5 @@ _initialize_amd64_linux_nat (void) /* Register the target. */ linux_nat_add_target (t); linux_nat_set_new_thread (t, amd64_linux_new_thread); + linux_nat_set_siginfo_fixup (t, amd64_linux_siginfo_fixup); } Index: src/gdb/linux-nat.c =================================================================== --- src.orig/gdb/linux-nat.c 2009-02-03 19:20:49.000000000 +0000 +++ src/gdb/linux-nat.c 2009-02-04 20:23:46.000000000 +0000 @@ -205,6 +205,13 @@ static struct target_ops linux_ops_saved /* The method to call, if any, when a new thread is attached. */ static void (*linux_nat_new_thread) (ptid_t); +/* The method to call, if any, when the siginfo object needs to be + converted between the layout returned by ptrace, and the layout in + the architecture of the inferior. */ +static int (*linux_nat_siginfo_fixup) (struct siginfo *, + gdb_byte *, + int); + /* The saved to_xfer_partial method, inherited from inf-ptrace.c. Called by our to_xfer_partial. */ static LONGEST (*super_xfer_partial) (struct target_ops *, @@ -3214,6 +3221,28 @@ linux_nat_mourn_inferior (struct target_ linux_fork_mourn_inferior (); } +/* Convert a native/host siginfo object, into/from the siginfo in the + layout of the inferiors' architecture. */ + +static void +siginfo_fixup (struct siginfo *siginfo, gdb_byte *inf_siginfo, int direction) +{ + int done = 0; + + if (linux_nat_siginfo_fixup != NULL) + done = linux_nat_siginfo_fixup (siginfo, inf_siginfo, direction); + + /* If there was no callback, or the callback didn't do anything, + then just do a straight memcpy. */ + if (!done) + { + if (direction == 1) + memcpy (siginfo, inf_siginfo, sizeof (struct siginfo)); + else + memcpy (inf_siginfo, siginfo, sizeof (struct siginfo)); + } +} + static LONGEST linux_xfer_siginfo (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, @@ -3223,6 +3252,7 @@ linux_xfer_siginfo (struct target_ops *o LONGEST n; int pid; struct siginfo siginfo; + gdb_byte inf_siginfo[sizeof (struct siginfo)]; gdb_assert (object == TARGET_OBJECT_SIGNAL_INFO); gdb_assert (readbuf || writebuf); @@ -3239,14 +3269,26 @@ linux_xfer_siginfo (struct target_ops *o if (errno != 0) return -1; + /* When GDB is built as a 64-bit application, ptrace writes into + SIGINFO an object with 64-bit layout. Since debugging a 32-bit + inferior with a 64-bit GDB should look the same as debugging it + with a 32-bit GDB, we need to convert it. GDB core always sees + the converted layout, so any read/write will have to be done + post-conversion. */ + siginfo_fixup (&siginfo, inf_siginfo, 0); + if (offset + len > sizeof (siginfo)) len = sizeof (siginfo) - offset; if (readbuf != NULL) - memcpy (readbuf, (char *)&siginfo + offset, len); + memcpy (readbuf, inf_siginfo + offset, len); else { - memcpy ((char *)&siginfo + offset, writebuf, len); + memcpy (inf_siginfo + offset, writebuf, len); + + /* Convert back to ptrace layout before flushing it out. */ + siginfo_fixup (&siginfo, inf_siginfo, 1); + errno = 0; ptrace (PTRACE_SETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo); if (errno != 0) @@ -4715,6 +4757,19 @@ linux_nat_set_new_thread (struct target_ linux_nat_new_thread = new_thread; } +/* Register a method that converts a siginfo object between the layout + that ptrace returns, and the layout in the architecture of the + inferior. */ +void +linux_nat_set_siginfo_fixup (struct target_ops *t, + int (*siginfo_fixup) (struct siginfo *, + gdb_byte *, + int)) +{ + /* Save the pointer. */ + linux_nat_siginfo_fixup = siginfo_fixup; +} + /* Return the saved siginfo associated with PTID. */ struct siginfo * linux_nat_get_siginfo (ptid_t ptid) Index: src/gdb/linux-nat.h =================================================================== --- src.orig/gdb/linux-nat.h 2009-02-03 20:09:44.000000000 +0000 +++ src/gdb/linux-nat.h 2009-02-04 19:57:44.000000000 +0000 @@ -128,6 +128,14 @@ void linux_nat_add_target (struct target /* Register a method to call whenever a new thread is attached. */ void linux_nat_set_new_thread (struct target_ops *, void (*) (ptid_t)); +/* Register a method that converts a siginfo object between the layout + that ptrace returns, and the layout in the architecture of the + inferior. */ +void linux_nat_set_siginfo_fixup (struct target_ops *, + int (*) (struct siginfo *, + gdb_byte *, + int)); + /* Update linux-nat internal state when changing from one fork to another. */ void linux_nat_switch_fork (ptid_t new_ptid); ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [3/2] Inspect extra signal information, handle amd64 bi-arch gdb 2009-02-04 21:02 ` [3/2] Inspect extra signal information, handle amd64 bi-arch gdb Pedro Alves @ 2009-02-04 21:17 ` Daniel Jacobowitz 2009-02-06 23:37 ` Pedro Alves 2009-02-04 22:07 ` Doug Evans 1 sibling, 1 reply; 53+ messages in thread From: Daniel Jacobowitz @ 2009-02-04 21:17 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches, Ulrich Weigand On Wed, Feb 04, 2009 at 09:02:10PM +0000, Pedro Alves wrote: > Here's a patch that applies on top of the other two. I think > it's easy to read it split out from the other patches. > > This handles the layout conversion for x86/amd64, near the > PTRACE_[G|S]ETSIGINFO calls, like we discussed yesterday. > > I'm not adjusting gdbserver here yet, since the original series > added $_siginfo support for ARM, and x86/amd64 only, and, gdbserver > on x86/amd64 isn't biarch aware yet. We can handle doing something > like this there when we add $_siginfo gdbarch type support for ppc, or > when we add biarch support for x86/amd64. > > What do you think? I've tried to make it as pretty as I could. :-) Seems fine to me. -- Daniel Jacobowitz CodeSourcery ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [3/2] Inspect extra signal information, handle amd64 bi-arch gdb 2009-02-04 21:17 ` Daniel Jacobowitz @ 2009-02-06 23:37 ` Pedro Alves 2009-02-07 2:28 ` Paul Pluzhnikov 0 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-02-06 23:37 UTC (permalink / raw) To: gdb-patches On Wednesday 04 February 2009 21:17:12, Daniel Jacobowitz wrote: > Seems fine to me. Thanks Daniel. Here's the version I just checked in. -- Pedro Alves 2009-02-06 Pedro Alves <pedro@codesourcery.com> * amd64-linux-nat.c (compat_int_t, compat_uptr_t, compat_time_t) (compat_timer_t, compat_clock_t, struct compat_timeval) (compat_sigval_t, compat_siginfo_t): New types. (cpt_si_pid, cpt_si_uid, cpt_si_timerid, cpt_si_overrun) (cpt_si_status, cpt_si_utime, cpt_si_stime, cpt_si_ptr) (cpt_si_addr, cpt_si_band, cpt_si_fd): New defines. (compat_siginfo_from_siginfo, siginfo_from_compat_siginfo) (amd64_linux_siginfo_fixup): New. * linux-nat.c (linux_nat_siginfo_fixup): New. (siginfo_fixup): New. (linux_xfer_siginfo): Use siginfo_fixup to convert between the siginfo layout expected by ptrace and the siginfo layout of the inferior. (linux_nat_set_siginfo_fixup): New. * linux-nat.h (linux_nat_set_siginfo_fixup): Declare. --- gdb/amd64-linux-nat.c | 234 ++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/linux-nat.c | 59 ++++++++++++ gdb/linux-nat.h | 8 + 3 files changed, 299 insertions(+), 2 deletions(-) Index: src/gdb/amd64-linux-nat.c =================================================================== --- src.orig/gdb/amd64-linux-nat.c 2009-02-06 23:02:14.000000000 +0000 +++ src/gdb/amd64-linux-nat.c 2009-02-06 23:04:07.000000000 +0000 @@ -400,6 +400,239 @@ amd64_linux_child_post_startup_inferior } \f +/* When GDB is built as a 64-bit application on linux, the + PTRACE_GETSIGINFO data is always presented in 64-bit layout. Since + debugging a 32-bit inferior with a 64-bit GDB should look the same + as debugging it with a 32-bit GDB, we do the 32-bit <-> 64-bit + conversion in-place ourselves. */ + +/* These types below (compat_*) define a siginfo type that is layout + compatible with the siginfo type exported by the 32-bit userspace + support. */ + +typedef int compat_int_t; +typedef unsigned int compat_uptr_t; + +typedef int compat_time_t; +typedef int compat_timer_t; +typedef int compat_clock_t; + +struct compat_timeval +{ + compat_time_t tv_sec; + int tv_usec; +}; + +typedef union compat_sigval +{ + compat_int_t sival_int; + compat_uptr_t sival_ptr; +} compat_sigval_t; + +typedef struct compat_siginfo +{ + int si_signo; + int si_errno; + int si_code; + + union + { + int _pad[((128 / sizeof (int)) - 3)]; + + /* kill() */ + struct + { + unsigned int _pid; + unsigned int _uid; + } _kill; + + /* POSIX.1b timers */ + struct + { + compat_timer_t _tid; + int _overrun; + compat_sigval_t _sigval; + } _timer; + + /* POSIX.1b signals */ + struct + { + unsigned int _pid; + unsigned int _uid; + compat_sigval_t _sigval; + } _rt; + + /* SIGCHLD */ + struct + { + unsigned int _pid; + unsigned int _uid; + int _status; + compat_clock_t _utime; + compat_clock_t _stime; + } _sigchld; + + /* SIGILL, SIGFPE, SIGSEGV, SIGBUS */ + struct + { + unsigned int _addr; + } _sigfault; + + /* SIGPOLL */ + struct + { + int _band; + int _fd; + } _sigpoll; + } _sifields; +} compat_siginfo_t; + +#define cpt_si_pid _sifields._kill._pid +#define cpt_si_uid _sifields._kill._uid +#define cpt_si_timerid _sifields._timer._tid +#define cpt_si_overrun _sifields._timer._overrun +#define cpt_si_status _sifields._sigchld._status +#define cpt_si_utime _sifields._sigchld._utime +#define cpt_si_stime _sifields._sigchld._stime +#define cpt_si_ptr _sifields._rt._sigval.sival_ptr +#define cpt_si_addr _sifields._sigfault._addr +#define cpt_si_band _sifields._sigpoll._band +#define cpt_si_fd _sifields._sigpoll._fd + +static void +compat_siginfo_from_siginfo (compat_siginfo_t *to, siginfo_t *from) +{ + memset (to, 0, sizeof (*to)); + + to->si_signo = from->si_signo; + to->si_errno = from->si_errno; + to->si_code = from->si_code; + + if (to->si_code < 0) + { + to->cpt_si_ptr = (intptr_t) from->si_ptr; + } + else if (to->si_code == SI_USER) + { + to->cpt_si_pid = from->si_pid; + to->cpt_si_uid = from->si_uid; + } + else if (to->si_code == SI_TIMER) + { + to->cpt_si_timerid = from->si_timerid; + to->cpt_si_overrun = from->si_overrun; + to->cpt_si_ptr = (intptr_t) from->si_ptr; + } + else + { + switch (to->si_signo) + { + case SIGCHLD: + to->cpt_si_pid = from->si_pid; + to->cpt_si_uid = from->si_uid; + to->cpt_si_status = from->si_status; + to->cpt_si_utime = from->si_utime; + to->cpt_si_stime = from->si_stime; + break; + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + to->cpt_si_addr = (intptr_t) from->si_addr; + break; + case SIGPOLL: + to->cpt_si_band = from->si_band; + to->cpt_si_fd = from->si_fd; + break; + default: + to->cpt_si_pid = from->si_pid; + to->cpt_si_uid = from->si_uid; + to->cpt_si_ptr = (intptr_t) from->si_ptr; + break; + } + } +} + +static void +siginfo_from_compat_siginfo (siginfo_t *to, compat_siginfo_t *from) +{ + memset (to, 0, sizeof (*to)); + + to->si_signo = from->si_signo; + to->si_errno = from->si_errno; + to->si_code = from->si_code; + + if (to->si_code < 0) + { + to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr; + } + else if (to->si_code == SI_USER) + { + to->si_pid = from->cpt_si_pid; + to->si_uid = from->cpt_si_uid; + } + else if (to->si_code == SI_TIMER) + { + to->si_timerid = from->cpt_si_timerid; + to->si_overrun = from->cpt_si_overrun; + to->si_ptr = (void *) (intptr_t) from->cpt_si_ptr; + } + else + { + switch (to->si_signo) + { + case SIGCHLD: + to->si_pid = from->cpt_si_pid; + to->si_uid = from->cpt_si_uid; + to->si_status = from->cpt_si_status; + to->si_utime = from->cpt_si_utime; + to->si_stime = from->cpt_si_stime; + break; + case SIGILL: + case SIGFPE: + case SIGSEGV: + case SIGBUS: + to->si_addr = (void *) (intptr_t) from->cpt_si_addr; + break; + case SIGPOLL: + to->si_band = from->cpt_si_band; + to->si_fd = from->cpt_si_fd; + break; + default: + to->si_pid = from->cpt_si_pid; + to->si_uid = from->cpt_si_uid; + to->si_ptr = (void* ) (intptr_t) from->cpt_si_ptr; + break; + } + } +} + +/* Convert a native/host siginfo object, into/from the siginfo in the + layout of the inferiors' architecture. Returns true if any + conversion was done; false otherwise. If DIRECTION is 1, then copy + from INF to NATIVE. If DIRECTION is 0, copy from NATIVE to + INF. */ + +static int +amd64_linux_siginfo_fixup (struct siginfo *native, gdb_byte *inf, int direction) +{ + /* Is the inferior 32-bit? If so, then do fixup the siginfo + object. */ + if (gdbarch_addr_bit (get_frame_arch (get_current_frame ())) == 32) + { + gdb_assert (sizeof (struct siginfo) == sizeof (compat_siginfo_t)); + + if (direction == 0) + compat_siginfo_from_siginfo ((struct compat_siginfo *) inf, native); + else + siginfo_from_compat_siginfo (native, (struct compat_siginfo *) inf); + + return 1; + } + else + return 0; +} + /* Provide a prototype to silence -Wmissing-prototypes. */ void _initialize_amd64_linux_nat (void); @@ -434,4 +667,5 @@ _initialize_amd64_linux_nat (void) /* Register the target. */ linux_nat_add_target (t); linux_nat_set_new_thread (t, amd64_linux_new_thread); + linux_nat_set_siginfo_fixup (t, amd64_linux_siginfo_fixup); } Index: src/gdb/linux-nat.c =================================================================== --- src.orig/gdb/linux-nat.c 2009-02-06 23:02:15.000000000 +0000 +++ src/gdb/linux-nat.c 2009-02-06 23:04:07.000000000 +0000 @@ -205,6 +205,13 @@ static struct target_ops linux_ops_saved /* The method to call, if any, when a new thread is attached. */ static void (*linux_nat_new_thread) (ptid_t); +/* The method to call, if any, when the siginfo object needs to be + converted between the layout returned by ptrace, and the layout in + the architecture of the inferior. */ +static int (*linux_nat_siginfo_fixup) (struct siginfo *, + gdb_byte *, + int); + /* The saved to_xfer_partial method, inherited from inf-ptrace.c. Called by our to_xfer_partial. */ static LONGEST (*super_xfer_partial) (struct target_ops *, @@ -3223,6 +3230,28 @@ linux_nat_mourn_inferior (struct target_ linux_fork_mourn_inferior (); } +/* Convert a native/host siginfo object, into/from the siginfo in the + layout of the inferiors' architecture. */ + +static void +siginfo_fixup (struct siginfo *siginfo, gdb_byte *inf_siginfo, int direction) +{ + int done = 0; + + if (linux_nat_siginfo_fixup != NULL) + done = linux_nat_siginfo_fixup (siginfo, inf_siginfo, direction); + + /* If there was no callback, or the callback didn't do anything, + then just do a straight memcpy. */ + if (!done) + { + if (direction == 1) + memcpy (siginfo, inf_siginfo, sizeof (struct siginfo)); + else + memcpy (inf_siginfo, siginfo, sizeof (struct siginfo)); + } +} + static LONGEST linux_xfer_siginfo (struct target_ops *ops, enum target_object object, const char *annex, gdb_byte *readbuf, @@ -3232,6 +3261,7 @@ linux_xfer_siginfo (struct target_ops *o LONGEST n; int pid; struct siginfo siginfo; + gdb_byte inf_siginfo[sizeof (struct siginfo)]; gdb_assert (object == TARGET_OBJECT_SIGNAL_INFO); gdb_assert (readbuf || writebuf); @@ -3248,14 +3278,26 @@ linux_xfer_siginfo (struct target_ops *o if (errno != 0) return -1; + /* When GDB is built as a 64-bit application, ptrace writes into + SIGINFO an object with 64-bit layout. Since debugging a 32-bit + inferior with a 64-bit GDB should look the same as debugging it + with a 32-bit GDB, we need to convert it. GDB core always sees + the converted layout, so any read/write will have to be done + post-conversion. */ + siginfo_fixup (&siginfo, inf_siginfo, 0); + if (offset + len > sizeof (siginfo)) len = sizeof (siginfo) - offset; if (readbuf != NULL) - memcpy (readbuf, (char *)&siginfo + offset, len); + memcpy (readbuf, inf_siginfo + offset, len); else { - memcpy ((char *)&siginfo + offset, writebuf, len); + memcpy (inf_siginfo + offset, writebuf, len); + + /* Convert back to ptrace layout before flushing it out. */ + siginfo_fixup (&siginfo, inf_siginfo, 1); + errno = 0; ptrace (PTRACE_SETSIGINFO, pid, (PTRACE_TYPE_ARG3) 0, &siginfo); if (errno != 0) @@ -4720,6 +4762,19 @@ linux_nat_set_new_thread (struct target_ linux_nat_new_thread = new_thread; } +/* Register a method that converts a siginfo object between the layout + that ptrace returns, and the layout in the architecture of the + inferior. */ +void +linux_nat_set_siginfo_fixup (struct target_ops *t, + int (*siginfo_fixup) (struct siginfo *, + gdb_byte *, + int)) +{ + /* Save the pointer. */ + linux_nat_siginfo_fixup = siginfo_fixup; +} + /* Return the saved siginfo associated with PTID. */ struct siginfo * linux_nat_get_siginfo (ptid_t ptid) Index: src/gdb/linux-nat.h =================================================================== --- src.orig/gdb/linux-nat.h 2009-02-06 23:02:15.000000000 +0000 +++ src/gdb/linux-nat.h 2009-02-06 23:04:07.000000000 +0000 @@ -125,6 +125,14 @@ void linux_nat_add_target (struct target /* Register a method to call whenever a new thread is attached. */ void linux_nat_set_new_thread (struct target_ops *, void (*) (ptid_t)); +/* Register a method that converts a siginfo object between the layout + that ptrace returns, and the layout in the architecture of the + inferior. */ +void linux_nat_set_siginfo_fixup (struct target_ops *, + int (*) (struct siginfo *, + gdb_byte *, + int)); + /* Update linux-nat internal state when changing from one fork to another. */ void linux_nat_switch_fork (ptid_t new_ptid); ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [3/2] Inspect extra signal information, handle amd64 bi-arch gdb 2009-02-06 23:37 ` Pedro Alves @ 2009-02-07 2:28 ` Paul Pluzhnikov 2009-02-07 14:56 ` Pedro Alves 0 siblings, 1 reply; 53+ messages in thread From: Paul Pluzhnikov @ 2009-02-07 2:28 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches On Fri, Feb 6, 2009 at 3:37 PM, Pedro Alves <pedro@codesourcery.com> wrote: > On Wednesday 04 February 2009 21:17:12, Daniel Jacobowitz wrote: >> Seems fine to me. > > Thanks Daniel. Here's the version I just checked in. This just broke my build :-( ../../src/gdb/linux-nat.c: In function 'linux_xfer_siginfo': ../../src/gdb/linux-nat.c:3302: error: 'PTRACE_SETSIGINFO' undeclared (first use in this function) ../../src/gdb/linux-nat.c:3302: error: (Each undeclared identifier is reported only once ../../src/gdb/linux-nat.c:3302: error: for each function it appears in.) make: *** [linux-nat.o] Error 1 I am targeting glibc-2.3.6, and that doesn't appear to have PTRACE_SETSIGINFO -- Paul Pluzhnikov ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [3/2] Inspect extra signal information, handle amd64 bi-arch gdb 2009-02-07 2:28 ` Paul Pluzhnikov @ 2009-02-07 14:56 ` Pedro Alves 2009-02-07 16:14 ` Paul Pluzhnikov 0 siblings, 1 reply; 53+ messages in thread From: Pedro Alves @ 2009-02-07 14:56 UTC (permalink / raw) To: Paul Pluzhnikov; +Cc: gdb-patches On Saturday 07 February 2009 02:28:44, Paul Pluzhnikov wrote: > On Fri, Feb 6, 2009 at 3:37 PM, Pedro Alves <pedro@codesourcery.com> wrote: > This just broke my build :-( > > ../../src/gdb/linux-nat.c: In function 'linux_xfer_siginfo': > ../../src/gdb/linux-nat.c:3302: error: 'PTRACE_SETSIGINFO' undeclared > (first use in this function) > ../../src/gdb/linux-nat.c:3302: error: (Each undeclared identifier is > reported only once > ../../src/gdb/linux-nat.c:3302: error: for each function it appears in.) > make: *** [linux-nat.o] Error 1 > > I am targeting glibc-2.3.6, and that doesn't appear to have > PTRACE_SETSIGINFO > I've committed the below to fix it. gdbserver doesn't need fixing, as it's already doing this. According to grep over glibc 2.9, this value is good for all archs. -- Pedro Alves 2009-02-07 Pedro Alves <pedro@codesourcery.com> * linux-nat.c (PTRACE_SETSIGINFO): Define if PTRACE_GETSIGINFO isn't defined. --- gdb/linux-nat.c | 1 + 1 file changed, 1 insertion(+) Index: src/gdb/linux-nat.c =================================================================== --- src.orig/gdb/linux-nat.c 2009-02-07 14:34:40.000000000 +0000 +++ src/gdb/linux-nat.c 2009-02-07 14:43:32.000000000 +0000 @@ -195,6 +195,7 @@ blocked. */ #ifndef PTRACE_GETSIGINFO #define PTRACE_GETSIGINFO 0x4202 +#define PTRACE_SETSIGINFO 0x4203 #endif /* The single-threaded native GNU/Linux target_ops. We save a pointer for ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [3/2] Inspect extra signal information, handle amd64 bi-arch gdb 2009-02-07 14:56 ` Pedro Alves @ 2009-02-07 16:14 ` Paul Pluzhnikov 0 siblings, 0 replies; 53+ messages in thread From: Paul Pluzhnikov @ 2009-02-07 16:14 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches On Sat, Feb 7, 2009 at 6:56 AM, Pedro Alves <pedro@codesourcery.com> wrote: > I've committed the below to fix it. gdbserver doesn't need fixing, as > it's already doing this. According to grep over glibc 2.9, this value > is good for all archs. Thanks, it builds again for me :-) -- Paul Pluzhnikov ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [3/2] Inspect extra signal information, handle amd64 bi-arch gdb 2009-02-04 21:02 ` [3/2] Inspect extra signal information, handle amd64 bi-arch gdb Pedro Alves 2009-02-04 21:17 ` Daniel Jacobowitz @ 2009-02-04 22:07 ` Doug Evans 1 sibling, 0 replies; 53+ messages in thread From: Doug Evans @ 2009-02-04 22:07 UTC (permalink / raw) To: Pedro Alves; +Cc: gdb-patches, Daniel Jacobowitz, Ulrich Weigand On Wed, Feb 4, 2009 at 1:02 PM, Pedro Alves <pedro@codesourcery.com> wrote: > Here's a patch that applies on top of the other two. I think > it's easy to read it split out from the other patches. > > This handles the layout conversion for x86/amd64, near the > PTRACE_[G|S]ETSIGINFO calls, like we discussed yesterday. > > I'm not adjusting gdbserver here yet, since the original series > added $_siginfo support for ARM, and x86/amd64 only, and, gdbserver > on x86/amd64 isn't biarch aware yet. We can handle doing something > like this there when we add $_siginfo gdbarch type support for ppc, or > when we add biarch support for x86/amd64. > > What do you think? I've tried to make it as pretty as I could. :-) > > Please, don't hesitate pointing me at anything bogus I may > be doing. Another way to go, for reference sake, is to write a routine that converts a struct siginfo to a string, and another that converts a string to a struct siginfo, and have both gdb and gdbserver use those routines. Then bi-arch gdbserver support would pretty much come for free. Over time it seems like a growing amount of code would be useful to share between gdb and gdbserver. Do we have a plan for that? ^ permalink raw reply [flat|nested] 53+ messages in thread
* Re: [0/2] Inspect extra signal information 2009-02-03 16:42 ` Ulrich Weigand 2009-02-03 18:06 ` Daniel Jacobowitz @ 2009-02-03 18:23 ` Pedro Alves 1 sibling, 0 replies; 53+ messages in thread From: Pedro Alves @ 2009-02-03 18:23 UTC (permalink / raw) To: gdb-patches; +Cc: Ulrich Weigand On Tuesday 03 February 2009 16:42:21, Ulrich Weigand wrote: > Pedro Alves wrote: > > But, I thought I had, but I clearly didn't test before: > > > > - 64-bit gdb x 32-bit inferior, 64-bit kernel > > > > siginfo comes out with the 64-bit layout. > > ^^^^^^ > > Huh. With bi-arch setups, I understand everything is currently > supposed to be set up so that debugging a 32-bit program > with a 64-bit GDB looks just the same as debugging it > with a 32-bit GDB. > > The above would break that assumption: you see different > types of siginfo depending on your host GDB. I'm not sure > if that is really what we want ... Right, I'm not sure either. > On the other hand, it's going to be difficult to avoid. One > way would be for the Linux native target to always return > the 32-bit layout when debugging a 32-bit inferior; if necessary > it would have to convert the data in-place before returning it > (similar to how the native target today converts register contents > to 32 bit even though the ptrace interface returns 64 bit values). I guess I should try this. > > I was looking at target_gdbarch, and it doesn't seem to fit the > > bill either. E.g., a biarch ppc64 gdbserver returns a 32-bit > > target_arch if the inferior is 32-bit. > > That's actually an interesting question. The idea behind > "target_gdbarch" is "the architecture implemented by the > target debugger interface". In a bi-arch setup, the target > today emulates a 32-bit target interface when debugging a 32-bit > inferior, even when GDB itself is 64-bit. This is done by > explicit conversion in the native target (see above). The only weird case I can think of, if when you have an inferior that can do mode switching, and the siginfo_t type is different in different modes. In this case, there'd better be a single siginfo_t layout for all modes, otherwise you get funny cases. Say, a signal handler installed in code that runs mode x-bit, but the signal was raised while running code in mode y-bit. Without kernel help, GDB can't know the correct layout of the siginfo_t object the inferior will see in the signal handler. I don't think we can see that happen on linux, though, so on the fly conversion out of ptrace sounds like a good option. Let's see if it doesn't come out looking too ugly. If I make use of struct type/struct value if may not be bad, but, gdbserver can't use those... > Before real multi-architecture support, there really was to > other way to do it. However, once we get to full multi-arch, > it might in fact be a more natural fit to model the bi-arch > setup by having "target_gdbarch" indicate the actual bitness > of the ptrace interface (i.e. 64-bit), while still setting > the per-frame architecture of all frames to the appropriate > 32-bit architecture ... This might allow us to get rid of > some of the bi-arch special hacks in native target code. That's actually what I initially thought target_gdbarch was reporting. Full multi-arch is something that is also interesting for multi-process. E.g, a bi-arch gdbserver, that supports multi-process has issues, when trying to debug simultaneously 32-bit and 64-bit inferiors. In this case, we have one target interface active (remote) and one target_gdbarch. Since the register layouts in the protocol aren't dynamic depending on the inferior (after the first inferior), on the multi-process branch, gdbserver only allows debugging multiple inferiors if they're of the same arch. current_gdbarch of course bites back in this scenario as well. BTW, what is the status of your per-frame gdbarch patches submitted a while ago? -- Pedro Alves ^ permalink raw reply [flat|nested] 53+ messages in thread
end of thread, other threads:[~2009-04-07 14:57 UTC | newest] Thread overview: 53+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2009-01-12 18:47 [0/2] Inspect extra signal information Pedro Alves 2009-01-12 18:49 ` Pedro Alves 2009-01-12 18:52 ` [1/2] " Pedro Alves 2009-01-12 19:40 ` Eli Zaretskii 2009-02-02 16:51 ` Pedro Alves 2009-02-02 21:04 ` Eli Zaretskii 2009-02-05 1:14 ` Pedro Alves 2009-02-05 20:30 ` Eli Zaretskii 2009-02-06 23:31 ` Pedro Alves 2009-01-12 18:50 ` [2/2] " Pedro Alves 2009-01-12 19:39 ` Eli Zaretskii 2009-01-13 12:32 ` Pedro Alves 2009-01-13 18:55 ` Eli Zaretskii 2009-01-13 19:08 ` Pedro Alves 2009-01-13 19:15 ` Eli Zaretskii 2009-02-06 23:35 ` Pedro Alves 2009-02-09 6:23 ` Paul Pluzhnikov 2009-02-09 22:17 ` Pedro Alves 2009-04-06 19:00 ` Paul Pluzhnikov 2009-04-06 19:18 ` relying on testsuite results Thiago Jung Bauermann 2009-04-06 19:33 ` Paul Pluzhnikov 2009-04-06 19:57 ` Daniel Jacobowitz 2009-04-06 19:51 ` Tom Tromey 2009-04-06 20:22 ` Mark Kettenis 2009-04-07 14:57 ` [2/2] Inspect extra signal information Pedro Alves 2009-01-12 23:27 ` [0/2] " Mark Kettenis 2009-01-13 11:05 ` Pedro Alves 2009-01-13 18:42 ` Eli Zaretskii 2009-01-13 18:50 ` Pedro Alves 2009-01-13 19:19 ` Eli Zaretskii 2009-01-13 19:37 ` Pedro Alves 2009-01-13 19:47 ` Pedro Alves 2009-02-02 14:40 ` Pedro Alves 2009-02-02 20:49 ` Mark Kettenis 2009-02-03 15:02 ` Pedro Alves 2009-02-03 16:42 ` Ulrich Weigand 2009-02-03 18:06 ` Daniel Jacobowitz 2009-02-03 18:24 ` Pedro Alves 2009-02-03 19:04 ` Daniel Jacobowitz 2009-02-03 19:51 ` Pedro Alves 2009-02-03 23:18 ` Doug Evans 2009-02-03 23:50 ` Pedro Alves 2009-02-04 0:17 ` Doug Evans 2009-02-04 0:24 ` Daniel Jacobowitz 2009-02-04 0:49 ` Pedro Alves 2009-02-04 21:02 ` [3/2] Inspect extra signal information, handle amd64 bi-arch gdb Pedro Alves 2009-02-04 21:17 ` Daniel Jacobowitz 2009-02-06 23:37 ` Pedro Alves 2009-02-07 2:28 ` Paul Pluzhnikov 2009-02-07 14:56 ` Pedro Alves 2009-02-07 16:14 ` Paul Pluzhnikov 2009-02-04 22:07 ` Doug Evans 2009-02-03 18:23 ` [0/2] Inspect extra signal information Pedro Alves
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox