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:
Pedro Alves 2009-02-06 22:59:01 +00:00
parent 5f5233d48e
commit 4aa995e123
28 changed files with 962 additions and 29 deletions

View 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>

View 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 \

View 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);
}

View 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

View 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)

View 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.

View 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

View 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)
{

View 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);

View File

@ -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

View 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.

View 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

View 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

View 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;

View 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)
{

View 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

View 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. */

View 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);
}
/* 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);
}

View 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));

138
gdb/linux-tdep.c Normal file
View 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
View 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 */

View 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);

View 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, ... */
};

View 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.

View 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;
}

View 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"

View 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);

View 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);