Browse Source
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.cgen-1_1-branch
28 changed files with 962 additions and 29 deletions
@ -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; |
|||
} |
|||
@ -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 */ |
|||
@ -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; |
|||
} |
|||
@ -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" |
|||
Loading…
Reference in new issue