2009-02-06 Pedro Alves <pedro@codesourcery.com>
authorPedro Alves <palves@redhat.com>
Fri, 6 Feb 2009 22:59:01 +0000 (22:59 +0000)
committerPedro Alves <palves@redhat.com>
Fri, 6 Feb 2009 22:59:01 +0000 (22:59 +0000)
gdb/
* 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.

28 files changed:
gdb/ChangeLog
gdb/Makefile.in
gdb/amd64-linux-tdep.c
gdb/arm-linux-tdep.c
gdb/configure.tgt
gdb/doc/ChangeLog
gdb/doc/gdb.texinfo
gdb/gdbarch.c
gdb/gdbarch.h
gdb/gdbarch.sh
gdb/gdbserver/ChangeLog
gdb/gdbserver/linux-low.c
gdb/gdbserver/server.c
gdb/gdbserver/target.h
gdb/gdbtypes.c
gdb/gdbtypes.h
gdb/i386-linux-tdep.c
gdb/infrun.c
gdb/linux-nat.c
gdb/linux-tdep.c [new file with mode: 0644]
gdb/linux-tdep.h [new file with mode: 0644]
gdb/remote.c
gdb/target.h
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/siginfo-obj.c [new file with mode: 0644]
gdb/testsuite/gdb.base/siginfo-obj.exp [new file with mode: 0644]
gdb/value.c
gdb/value.h

index 01e4156ecd385e4ef259e3d89f521d2c90edf73f..56496fd49d6718708e088d927cd1fec71a215f1f 100644 (file)
@@ -1,3 +1,56 @@
+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  Jim Blandy  <jimb@codesourcery.com>
            Daniel Jacobowitz  <dan@codesourcery.com>
            Vladimir Prus  <vladimir@codesourcery.com>
index 7400702a68f71ad9a95f147920257af9fcf58d18..06bdd98302cba7f496de9f6461d0ad98a7fbb484 100644 (file)
@@ -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/mips/nm-irix5.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 b8e779e538857fe7f10939dd8181a70c4bb9a8b4..badc0b43e7739ab897e76a42d0bb0085d33af12a 100644 (file)
@@ -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_info info, struct gdbarch *gdbarch)
                                            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 c66e814ff0bb43d65a45941d5666adade8b7b3fc..fbe80eef257b2354ed9efb3ed7cb60014b6d7eb8 100644 (file)
@@ -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 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 c778cbff6ca4930a0f9fd9726f381d249aedb238..8053ba4ad11b24f2ba85755903d4f48842907278 100644 (file)
@@ -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 473c6e35890fa691e8f1620478b836048dd95b86..0874a56a833a84cf2bf03d5438ef6fc5a654cf36 100644 (file)
@@ -1,3 +1,11 @@
+2009-02-06  Pedro Alves  <pedro@codesourcery.com>
+
+       * 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>
 
        * gdbint.texinfo (Values): New chapter.
index 354b88804a117531b7d58f846797594d66ba7863..9ba56a8e60c3c1d4122c71f75b8484193789e85f 100644 (file)
@@ -4472,6 +4472,55 @@ a result of the fatal signal once it saw the signal.  To prevent this,
 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 was printed.
 @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 features and their properties:
 @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{qXfer:spu:read} packet
 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} packet must be empty
 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 support reading.
 
 @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 form defined so far.  All
 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 c328a2b19c9992c463a046b779ba22345debc48f..220771bd4a698993d4cc95e47c95b8f940bc2d84 100644 (file)
@@ -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);
@@ -834,6 +837,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
   fprintf_unfiltered (file,
                       "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));
@@ -3219,6 +3228,30 @@ set_gdbarch_target_signal_to_host (struct gdbarch *gdbarch,
   gdbarch->target_signal_to_host = target_signal_to_host;
 }
 
+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)
 {
index 35f8a36f4cd9a77a898cad5515e719a4b645aa27..4f6db30bc32555ac49cd09eb81467228d88ae9b9 100644 (file)
@@ -803,6 +803,16 @@ typedef int (gdbarch_target_signal_to_host_ftype) (struct gdbarch *gdbarch, enum
 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 dc8fb088dd71ff83bd1506c4b44a2f9525b237da..bcca6c937d94ef2b91e75c80b7ed67581cc6132b 100755 (executable)
@@ -705,6 +705,11 @@ m:enum target_signal:target_signal_from_host:int signo:signo::default_target_sig
 # 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 3fda37e45da3894d46d9e3f7c4421dd1c10ee2dc..30d7e0f0420bf0a51f95baaf1635b6d6082e05a7 100644 (file)
@@ -1,3 +1,11 @@
+2009-02-06  Pedro Alves  <pedro@codesourcery.com>
+
+       * 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-01-26  Pedro Alves  <pedro@codesourcery.com>
 
        * server.c (gdbserver_usage): Mention --remote-debug.
index 3fa06ec92552c2d3e81f430663fa1c4bf76d8c61..38dd0007d738b2ca9c2069eaa718fb8088002860 100644 (file)
@@ -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_ops = {
   NULL,
   hostio_last_error_from_errno,
   linux_qxfer_osdata,
+  linux_xfer_siginfo,
 };
 
 static void
index c4e167210bd3c349a60d689986555c658f5a3030..416ceb3e33c2cc2a20436d873dc7e72c9385c8b5 100644 (file)
@@ -810,6 +810,77 @@ handle_query (char *own_buf, int packet_len, int *new_packet_len_p)
       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_len, int *new_packet_len_p)
       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 a1dfad644bf62e94ec8f0ff119b75be3b20f3a8f..7851a4c0d9e4382a5249820332accf9ad747b563 100644 (file)
@@ -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 9f7317318c8e82800639364fe3aa839dbab99f77..810232115306fed59952ed27f119e43dce89eedd 100644 (file)
@@ -1822,8 +1822,8 @@ init_composite_type (char *name, enum type_code code)
 /* 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 *t, char *name,
     {
       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 e78d3cf5d3ba7263ec35554d9c649a01eb3eb90a..c90b6d7bdb4a8fc4b72ca097d3d1023faee20870 100644 (file)
@@ -1112,6 +1112,10 @@ extern struct type *init_type (enum type_code, int, int, char *,
 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 81c8d31c9b432bde0e942c60383366b902a29194..1a2e4f0a0124420c2e71591de39876b51a9cd00a 100644 (file)
@@ -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 info, struct gdbarch *gdbarch)
                                            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 3a67ac5400a64bfbebc54e2e9c8b6c17adf398a6..bed628d5abbf7394132a330e4e401d312441638c 100644 (file)
@@ -4804,6 +4804,87 @@ signals_info (char *signum_exp, int from_tty)
 
   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
 /* 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 33b05fa455d55542257040924a657112bb2ef1a1..0b098a07194592255f0f667c46792668e53f3b6a 100644 (file)
@@ -3223,15 +3223,63 @@ linux_nat_mourn_inferior (struct target_ops *ops)
     linux_fork_mourn_inferior ();
 }
 
+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));
 
diff --git a/gdb/linux-tdep.c b/gdb/linux-tdep.c
new file mode 100644 (file)
index 0000000..f1f7373
--- /dev/null
@@ -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;
+}
diff --git a/gdb/linux-tdep.h b/gdb/linux-tdep.h
new file mode 100644 (file)
index 0000000..50af511
--- /dev/null
@@ -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 aeeb8b8a8730ed1a27fe6dbc9f649d4edcc79381..af2c10b7677eef83f12686408c0daadb7532f0f6 100644 (file)
@@ -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_protocol_features[] = {
     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 *ops, enum target_object object,
                                     [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 bits) in a memory packet."), NULL,
   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 cb7064678beb38ee7b1b1cfa4e57803b9a6ba29f..916d8e949df99dec3a55954117043e7b0c2c7c85 100644 (file)
@@ -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 0b72438cb43d6f79a9df69e330a785e76f3e154d..bf6de5101a58a1912bb72cae4539e235130969af 100644 (file)
@@ -1,3 +1,7 @@
+2009-02-06  Pedro Alves  <pedro@codesourcery.com>
+
+       * gdb.base/siginfo-obj.c, gdb.base/siginfo-obj.exp: New.
+
 2009-02-06  Thiago Jung Bauermann  <bauerman@br.ibm.com>
 
        * gdb.python/python-cmd.exp: New file.
diff --git a/gdb/testsuite/gdb.base/siginfo-obj.c b/gdb/testsuite/gdb.base/siginfo-obj.c
new file mode 100644 (file)
index 0000000..b88976e
--- /dev/null
@@ -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;
+}
diff --git a/gdb/testsuite/gdb.base/siginfo-obj.exp b/gdb/testsuite/gdb.base/siginfo-obj.exp
new file mode 100644 (file)
index 0000000..0dea59a
--- /dev/null
@@ -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"
index 6a9ac5ff544526be3b0d5a8ffbe4544249e6d4f4..4d4329e5b17616c16523f2a0cdac593b7d91be90 100644 (file)
@@ -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 *var)
   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 0c8522382d95ca4404f21e6973e7b01066fed520..aa43365efe575b316515b26a63ce71e20f7a9e50 100644 (file)
@@ -305,11 +305,14 @@ extern struct value *coerce_array (struct value *value);
 /* 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_internalvar (char *name);
 
 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);