[2/2] Inspect extra signal information

Pedro Alves
2009-01-12T18:50:11Z

[-- 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 (&current_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 (&current_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"