mirror of
https://github.com/darlinghq/darling-gdb.git
synced 2025-02-26 04:15:28 +00:00
2009-02-06 Pedro Alves <pedro@codesourcery.com>
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.
This commit is contained in:
parent
5f5233d48e
commit
4aa995e123
@ -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>
|
||||
|
@ -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 \
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
@ -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;
|
||||
|
@ -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)
|
||||
{
|
||||
|
@ -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
|
||||
|
@ -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. */
|
||||
|
87
gdb/infrun.c
87
gdb/infrun.c
@ -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 (¤t_target, TARGET_OBJECT_SIGNAL_INFO,
|
||||
NULL,
|
||||
value_contents_all_raw (v),
|
||||
value_offset (v),
|
||||
TYPE_LENGTH (value_type (v)));
|
||||
|
||||
if (transferred != TYPE_LENGTH (value_type (v)))
|
||||
error (_("Unable to read siginfo"));
|
||||
}
|
||||
|
||||
/* This function implements the lval_computed support for writing a
|
||||
$_siginfo value. */
|
||||
|
||||
static void
|
||||
siginfo_value_write (struct value *v, struct value *fromval)
|
||||
{
|
||||
LONGEST transferred;
|
||||
|
||||
transferred = target_write (¤t_target,
|
||||
TARGET_OBJECT_SIGNAL_INFO,
|
||||
NULL,
|
||||
value_contents_all_raw (fromval),
|
||||
value_offset (v),
|
||||
TYPE_LENGTH (value_type (fromval)));
|
||||
|
||||
if (transferred != TYPE_LENGTH (value_type (fromval)))
|
||||
error (_("Unable to write siginfo"));
|
||||
}
|
||||
|
||||
static struct lval_funcs siginfo_value_funcs =
|
||||
{
|
||||
siginfo_value_read,
|
||||
siginfo_value_write
|
||||
};
|
||||
|
||||
/* Return a new value with the correct type for the siginfo object of
|
||||
the current thread. Return a void value if there's no object
|
||||
available. */
|
||||
|
||||
struct value *
|
||||
siginfo_make_value (struct internalvar *var)
|
||||
{
|
||||
struct type *type;
|
||||
struct gdbarch *gdbarch;
|
||||
|
||||
if (target_has_stack
|
||||
&& !ptid_equal (inferior_ptid, null_ptid))
|
||||
{
|
||||
gdbarch = get_frame_arch (get_current_frame ());
|
||||
|
||||
if (gdbarch_get_siginfo_type_p (gdbarch))
|
||||
{
|
||||
type = gdbarch_get_siginfo_type (gdbarch);
|
||||
|
||||
return allocate_computed_value (type, &siginfo_value_funcs, NULL);
|
||||
}
|
||||
}
|
||||
|
||||
return allocate_value (builtin_type_void);
|
||||
}
|
||||
|
||||
|
||||
/* 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);
|
||||
}
|
||||
|
@ -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));
|
||||
|
||||
|
138
gdb/linux-tdep.c
Normal file
138
gdb/linux-tdep.c
Normal file
@ -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;
|
||||
}
|
25
gdb/linux-tdep.h
Normal file
25
gdb/linux-tdep.h
Normal file
@ -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 */
|
25
gdb/remote.c
25
gdb/remote.c
@ -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);
|
||||
|
@ -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, ... */
|
||||
};
|
||||
|
||||
|
@ -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.
|
||||
|
70
gdb/testsuite/gdb.base/siginfo-obj.c
Normal file
70
gdb/testsuite/gdb.base/siginfo-obj.c
Normal file
@ -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;
|
||||
}
|
131
gdb/testsuite/gdb.base/siginfo-obj.exp
Normal file
131
gdb/testsuite/gdb.base/siginfo-obj.exp
Normal file
@ -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"
|
62
gdb/value.c
62
gdb/value.c
@ -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);
|
||||
|
@ -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);
|
||||
|
Loading…
x
Reference in New Issue
Block a user