[RFC/PATCH] Add new internal variable $_signo

Sergio Durigan Junior
2013-06-14T00:38:06Z

Hi,

This patch comes from a request at:

<https://bugzilla.redhat.com/show_bug.cgi?id=971849>

Basically, the ABRT project (<https://fedorahosted.org/abrt/wiki>) wants
to be able to perform some analysis on corefiles (to be implemented as a
Python GDB module) and for that it needs to be able to inspect the
signal which killed the program being investigated.

This can be done with recent Linux kernels by inspecting the $_siginfo
convenience variable (on corefiles, it works by parsing the contents of
the NT_SIGINFO section, whose support was added by Tom on
1b05b77b857f26c59ad5dc6443fc8baa21696440). The NT_SIGINFO section was
added on the kernel by:

author Denys Vlasenko <vda.linux@googlemail.com> 2012-10-05 00:15:35 (GMT)
commit 49ae4d4b113be03dc4a2ec5f2a1f573ff0fcddb3 (patch)

(This is Linux 3.7-rc1).

Well, the problem is that for older kernels (or not so old, as can be
noted by the date), when one tries to access $_siginfo.si_signo from a
corefile he/she gets:

(gdb) core ./coredump
[New LWP 2703]
Core was generated by `/usr/bin/gnote <<skip>>'.
Program terminated with signal 11, Segmentation fault.
#0 0x09fa5348 in ?? ()
(gdb) print $_siginfo.si_signo
Unable to read siginfo

The signal can obviously be recovered because GDB itself mentioned it
when saying that it was "signal 11, Segmentation fault", and this is why
this patch came to life. It basically sets/creates a new internal
variable called "$_signo" to be used as an alternative to
$_siginfo.si_signo when this one is unavailable. It's not a complex
patch per se, but I would certainly like some review because there may
be other places where we should set the variable as well.

The patch also contains a testcase and an update to the documentation in
order to mention the new convenience variable.

Comments? OK to apply?

--
Sergio

gdb/ChangeLog:
2013-06-13 Denys Vlasenko <dvlasenk@redhat.com>

* corelow.c (core_open): Set internal variable "$_signo".
* infrun.c (handle_inferior_event): Likewise, for
TARGET_WAITKIND_SIGNALLED and TARGET_WAITKIND_STOPPED.

gdb/testsuite/ChangeLog:
2013-06-13 Sergio Durigan Junior <sergiodj@redhat.com>

* gdb.base/signo.c: New file.
* gdb.base/signo.exp: Likewise.

gdb/doc/ChangeLog:
2013-06-13 Sergio Durigan Junior <sergiodj@redhat.com>

* gdb.texinfo (Convenience Variables): Document "$_signo".

diff --git a/gdb/corelow.c b/gdb/corelow.c
index 0bfa743..6044b35 100644
--- a/gdb/corelow.c
+++ b/gdb/corelow.c
@@ -446,6 +446,10 @@ core_open (char *filename, int from_tty)

printf_filtered (_("Program terminated with signal %d, %s.\n"),
siggy, gdb_signal_to_string (sig));
+ /* Set the internal variable $_signo to hold the signal number that
+ triggered the creation of the corefile. */
+ set_internalvar_integer (lookup_internalvar ("_signo"),
+ (LONGEST) siggy);
}

/* Fetch all registers from core file. */
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index e6ec4ff..0eda8bc 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -9759,6 +9759,16 @@ The variable @code{$_siginfo} contains extra signal information
could be empty, if the application has not yet received any signals.
For example, it will be empty before you execute the @code{run} command.

+@item $_signo
+@vindex $_signo@r{, convenience variable}
+The variable @code{$_signo} contains the signal number received by the
+inferior. Its purpose is to serve as an auxiliary way of retrieving
+such information for when the kernel does not provide the necessary
+support for @code{$_siginfo} to be used. Note that @code{$_signo}
+could be @code{void} (empty), if the application has not received any
+signals. For example, it will be @code{void} before you execute the
+@code{run} command.
+
@item $_tlb
@vindex $_tlb@r{, convenience variable}
The variable @code{$_tlb} is automatically set when debugging
diff --git a/gdb/infrun.c b/gdb/infrun.c
index 51a032b..ac1ca9d 100644
--- a/gdb/infrun.c
+++ b/gdb/infrun.c
@@ -3462,7 +3462,13 @@ handle_inferior_event (struct execution_control_state *ecs)
print_exited_reason (ecs->ws.value.integer);
}
else
- print_signal_exited_reason (ecs->ws.value.sig);
+ {
+ print_signal_exited_reason (ecs->ws.value.sig);
+ /* Set the value of the internal variable $_signo to hold the
+ signal number received by the inferior. */
+ set_internalvar_integer (lookup_internalvar ("_signo"),
+ (LONGEST) ecs->ws.value.sig);
+ }

gdb_flush (gdb_stdout);
target_mourn_inferior ();
@@ -3719,6 +3725,10 @@ handle_inferior_event (struct execution_control_state *ecs)
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_STOPPED\n");
ecs->event_thread->suspend.stop_signal = ecs->ws.value.sig;
+ /* Set the value of the internal variable $_signo to hold the signal
+ number that stopped the inferior. */
+ set_internalvar_integer (lookup_internalvar ("_signo"),
+ (LONGEST) ecs->ws.value.sig);
break;

case TARGET_WAITKIND_NO_HISTORY:
diff --git a/gdb/testsuite/gdb.base/signo.c b/gdb/testsuite/gdb.base/signo.c
new file mode 100644
index 0000000..9e2db13
--- /dev/null
+++ b/gdb/testsuite/gdb.base/signo.c
@@ -0,0 +1,27 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright 2013 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/>.
+
+*/
+
+int
+main (int argc, char *argv[])
+{
+ char *p = 0;
+
+ /* Generating a SIGSEGV. */
+ *p = 1;
+}
diff --git a/gdb/testsuite/gdb.base/signo.exp b/gdb/testsuite/gdb.base/signo.exp
new file mode 100644
index 0000000..e75bcf1
--- /dev/null
+++ b/gdb/testsuite/gdb.base/signo.exp
@@ -0,0 +1,45 @@
+# Copyright 2013 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/>.
+
+standard_testfile
+
+if { [prepare_for_testing ${testfile}.exp ${testfile} ${srcfile}] } {
+ return -1
+}
+
+# Run to main
+if { ![runto_main] } {
+ return -1
+}
+
+# Run to the SIGSEGV.
+gdb_test "continue" ".*Program received signal SIGSEGV.*" "continue to SIGSEGV"
+
+# Try to generate a core file, for a later test.
+set gcorefile [standard_output_file $testfile.gcore]
+set gcore_created [gdb_gcore_cmd $gcorefile "save a core file"]
+
+if { !${gcore_created} } {
+ untested "unable to create corefile."
+ return
+}
+
+# Restart all over, but this time with the corefile.
+clean_restart $binfile
+
+gdb_test "core $gcorefile" "Core was generated by.*" \
+ "core [file tail $gcorefile]"
+
+gdb_test "p \$_signo" " = 11"