From 1736ad1102dd931b269a5b900f05846442a0566a Mon Sep 17 00:00:00 2001 From: Jan Kratochvil Date: Fri, 24 Sep 2010 18:35:28 +0000 Subject: [PATCH] gdb/ Fix lost siginfo_t for inferior calls. * infrun.c (struct inferior_thread_state) : New. (save_inferior_thread_state): New variables regcache, gdbarch and siginfo_data. Initialize SIGINFO_DATA if gdbarch_get_siginfo_type_p. Move INF_STATE allocation later, pre-clear it. Initialize REGISTERS using REGCACHE. (restore_inferior_thread_state): New variables regcache and gdbarch. Restore SIGINFO_DATA for matching GDBARCH. Restore REGISTERS using REGCACHE. Free also SIGINFO_DATA. gdb/testsuite/ Fix lost siginfo_t for inferior calls. * gdb.base/siginfo-infcall.exp: New file. * gdb.base/siginfo-infcall.c: New file. --- gdb/ChangeLog | 13 ++++ gdb/infrun.c | 58 +++++++++++++++- gdb/testsuite/ChangeLog | 6 ++ gdb/testsuite/gdb.base/siginfo-infcall.c | 79 ++++++++++++++++++++++ gdb/testsuite/gdb.base/siginfo-infcall.exp | 47 +++++++++++++ 5 files changed, 200 insertions(+), 3 deletions(-) create mode 100644 gdb/testsuite/gdb.base/siginfo-infcall.c create mode 100644 gdb/testsuite/gdb.base/siginfo-infcall.exp diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 97dcaac00cb..55b1d88b0ca 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,16 @@ +2010-09-24 Jan Kratochvil + + Fix lost siginfo_t for inferior calls. + * infrun.c + (struct inferior_thread_state) : New. + (save_inferior_thread_state): New variables regcache, gdbarch and + siginfo_data. Initialize SIGINFO_DATA if gdbarch_get_siginfo_type_p. + Move INF_STATE allocation later, pre-clear it. Initialize REGISTERS + using REGCACHE. + (restore_inferior_thread_state): New variables regcache and gdbarch. + Restore SIGINFO_DATA for matching GDBARCH. Restore REGISTERS using + REGCACHE. Free also SIGINFO_DATA. + 2010-09-24 Tom Tromey * dwarf2read.c (dw2_expand_symtabs_matching): Add missing diff --git a/gdb/infrun.c b/gdb/infrun.c index a6f8fd13242..0720b314275 100644 --- a/gdb/infrun.c +++ b/gdb/infrun.c @@ -6037,18 +6037,57 @@ struct inferior_thread_state enum target_signal stop_signal; CORE_ADDR stop_pc; struct regcache *registers; + + /* Format of SIGINFO or NULL if it is not present. */ + struct gdbarch *siginfo_gdbarch; + + /* The inferior format depends on SIGINFO_GDBARCH and it has a length of + TYPE_LENGTH (gdbarch_get_siginfo_type ()). For different gdbarch the + content would be invalid. */ + gdb_byte *siginfo_data; }; struct inferior_thread_state * save_inferior_thread_state (void) { - struct inferior_thread_state *inf_state = XMALLOC (struct inferior_thread_state); + struct inferior_thread_state *inf_state; struct thread_info *tp = inferior_thread (); + struct regcache *regcache = get_current_regcache (); + struct gdbarch *gdbarch = get_regcache_arch (regcache); + gdb_byte *siginfo_data = NULL; + + if (gdbarch_get_siginfo_type_p (gdbarch)) + { + struct type *type = gdbarch_get_siginfo_type (gdbarch); + size_t len = TYPE_LENGTH (type); + struct cleanup *back_to; + + siginfo_data = xmalloc (len); + back_to = make_cleanup (xfree, siginfo_data); + + if (target_read (¤t_target, TARGET_OBJECT_SIGNAL_INFO, NULL, + siginfo_data, 0, len) == len) + discard_cleanups (back_to); + else + { + /* Errors ignored. */ + do_cleanups (back_to); + siginfo_data = NULL; + } + } + + inf_state = XZALLOC (struct inferior_thread_state); + + if (siginfo_data) + { + inf_state->siginfo_gdbarch = gdbarch; + inf_state->siginfo_data = siginfo_data; + } inf_state->stop_signal = tp->stop_signal; inf_state->stop_pc = stop_pc; - inf_state->registers = regcache_dup (get_current_regcache ()); + inf_state->registers = regcache_dup (regcache); return inf_state; } @@ -6059,16 +6098,29 @@ void restore_inferior_thread_state (struct inferior_thread_state *inf_state) { struct thread_info *tp = inferior_thread (); + struct regcache *regcache = get_current_regcache (); + struct gdbarch *gdbarch = get_regcache_arch (regcache); tp->stop_signal = inf_state->stop_signal; stop_pc = inf_state->stop_pc; + if (inf_state->siginfo_gdbarch == gdbarch) + { + struct type *type = gdbarch_get_siginfo_type (gdbarch); + size_t len = TYPE_LENGTH (type); + + /* Errors ignored. */ + target_write (¤t_target, TARGET_OBJECT_SIGNAL_INFO, NULL, + inf_state->siginfo_data, 0, len); + } + /* The inferior can be gone if the user types "print exit(0)" (and perhaps other times). */ if (target_has_execution) /* NB: The register write goes through to the target. */ - regcache_cpy (get_current_regcache (), inf_state->registers); + regcache_cpy (regcache, inf_state->registers); regcache_xfree (inf_state->registers); + xfree (inf_state->siginfo_data); xfree (inf_state); } diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index d2ec668b939..3ae8411478f 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2010-09-24 Jan Kratochvil + + Fix lost siginfo_t for inferior calls. + * gdb.base/siginfo-infcall.exp: New file. + * gdb.base/siginfo-infcall.c: New file. + 2010-09-22 Joel Brobecker * gdb.dwarf2/dw2-const.S: Minor (space) reformatting. diff --git a/gdb/testsuite/gdb.base/siginfo-infcall.c b/gdb/testsuite/gdb.base/siginfo-infcall.c new file mode 100644 index 00000000000..421572548d7 --- /dev/null +++ b/gdb/testsuite/gdb.base/siginfo-infcall.c @@ -0,0 +1,79 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2010 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 . */ + +#include +#include +#include +#include + +#ifndef SA_SIGINFO +# error "SA_SIGINFO is required for this test" +#endif + +static int +callme (void) +{ + return 42; +} + +static int +pass (void) +{ + return 1; +} + +static int +fail (void) +{ + return 1; +} + +static void +handler (int sig, siginfo_t *siginfo, void *context) +{ + assert (sig == SIGUSR1); + assert (siginfo->si_signo == SIGUSR1); + if (siginfo->si_pid == getpid ()) + pass (); + else + fail (); +} + +int +main (void) +{ + struct sigaction sa; + int i; + + callme (); + + memset (&sa, 0, sizeof (sa)); + sa.sa_sigaction = handler; + sa.sa_flags = SA_SIGINFO; + + i = sigemptyset (&sa.sa_mask); + assert (i == 0); + + i = sigaction (SIGUSR1, &sa, NULL); + assert (i == 0); + + i = raise (SIGUSR1); + assert (i == 0); + + sleep (600); + return 0; +} diff --git a/gdb/testsuite/gdb.base/siginfo-infcall.exp b/gdb/testsuite/gdb.base/siginfo-infcall.exp new file mode 100644 index 00000000000..a229345bfca --- /dev/null +++ b/gdb/testsuite/gdb.base/siginfo-infcall.exp @@ -0,0 +1,47 @@ +# Copyright 2010 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 . + +if [target_info exists gdb,nosignals] { + verbose "Skipping siginfo-infcall.exp because of nosignals." + continue +} + +set testfile siginfo-infcall +set srcfile ${testfile}.c +set executable ${testfile} +if { [prepare_for_testing ${testfile}.exp $executable] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +gdb_breakpoint "pass" +gdb_breakpoint "fail" + +gdb_test "continue" "Program received signal SIGUSR1, .*" "continue to SIGUSR1" + +gdb_test "p callme ()" " = 42" + +set test "continue to the handler" +gdb_test_multiple "continue" $test { + -re "Breakpoint \[0-9\]+,\[^\r\n\]* pass .*\r\n$gdb_prompt $" { + pass $test + } + -re "Breakpoint \[0-9\]+,\[^\r\n\]* fail .*\r\n$gdb_prompt $" { + fail $test + } +} -- 2.30.2