Fix PR breakpoints/16297: catch syscall with syscall 0
authorGabriel Krisman Bertazi <gabriel@krisman.be>
Thu, 19 Dec 2013 19:01:49 +0000 (17:01 -0200)
committerSergio Durigan Junior <sergiodj@redhat.com>
Thu, 19 Dec 2013 19:01:49 +0000 (17:01 -0200)
Code rationale
==============
by: Gabriel Krisman Bertazi

This is a fix for bug 16297. The problem occurs when the user attempts
to catch any syscall 0 (such as syscall read on Linux/x86_64). GDB was
not able to catch the syscall and was missing the breakpoint.

Now, breakpoint_hit_catch_syscall returns immediately when it finds the
correct syscall number, avoiding a following check for the end of the
search vector, that returns a no hit if the syscall number was zero.

Testcase rationale
==================
by: Sergio Durigan Junior

This testcase is a little difficult to write.  By doing a quick
inspection at the Linux source, one can see that, in many targets, the
syscall number 0 is restart_syscall, which is forbidden to be called
from userspace.  Therefore, on many targets, there's just no way to test
this safely.

My decision was to take the simpler route and just adds the "read"
syscall on the default test.  Its number on x86_64 is zero, which is
"good enough" since many people here do their tests on x86_64 anyway and
it is a popular architecture.

However, there was another little gotcha.  When using "read" passing 0
as the third parameter (i.e., asking it to read 0 bytes), current libc
implementations could choose not to effectively call the syscall.
Therefore, the best solution was to create a temporary pipe, write 1
byte into it, and then read this byte from it.

gdb/ChangeLog
2013-12-19  Gabriel Krisman Bertazi  <gabriel@krisman.be>

PR breakpoints/16297
* breakpoint.c (breakpoint_hit_catch_syscall): Return immediately
when expected syscall is hit.

gdb/testsuite/ChangeLog
2013-12-19  Sergio Durigan Junior  <sergiodj@redhat.com>

PR breakpoints/16297
* gdb.base/catch-syscall.c (read_syscall, pipe_syscall)
(write_syscall): New variables.
(main): Create a pipe, write 1 byte in it, and read 1 byte from
it.
* gdb.base/catch-syscall.exp (all_syscalls): Include "pipe,
"write" and "read" syscalls.
(fill_all_syscalls_numbers): Improve the way to obtain syscalls
numbers.

gdb/ChangeLog
gdb/breakpoint.c
gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/catch-syscall.c
gdb/testsuite/gdb.base/catch-syscall.exp

index 374b8c5fe3fe22ebe51be3fb46698e2879e56dd4..2bae7aed397d51ac1adef7f8fd235186f7cb9bf8 100644 (file)
@@ -1,3 +1,9 @@
+2013-12-19  Gabriel Krisman Bertazi  <gabriel@krisman.be>
+
+       PR breakpoints/16297
+       * breakpoint.c (breakpoint_hit_catch_syscall): Return immediately
+       when expected syscall is hit.
+
 2013-12-19  Tom Tromey  <tromey@redhat.com>
 
        * ser-unix.c (hardwire_ops): New global.
index 589aa19b5c7834a025e3aedb427bad8cc6291567..6a11ddf8064584efec55befce2335d164b5e3249 100644 (file)
@@ -8325,10 +8325,9 @@ breakpoint_hit_catch_syscall (const struct bp_location *bl,
            VEC_iterate (int, c->syscalls_to_be_caught, i, iter);
            i++)
        if (syscall_number == iter)
-         break;
-      /* Not the same.  */
-      if (!iter)
-       return 0;
+         return 1;
+
+      return 0;
     }
 
   return 1;
index 3e1c756d139d68e575e947fe212b09e8a42d6320..97ad49b90efbc6d4c070c7d6e014a75addfd4434 100644 (file)
@@ -1,3 +1,15 @@
+2013-12-19  Sergio Durigan Junior  <sergiodj@redhat.com>
+
+       PR breakpoints/16297
+       * gdb.base/catch-syscall.c (read_syscall, pipe_syscall)
+       (write_syscall): New variables.
+       (main): Create a pipe, write 1 byte in it, and read 1 byte from
+       it.
+       * gdb.base/catch-syscall.exp (all_syscalls): Include "pipe,
+       "write" and "read" syscalls.
+       (fill_all_syscalls_numbers): Improve the way to obtain syscalls
+       numbers.
+
 2013-12-19  Keven Boell  <keven.boell@intel.com>
 
        * gdb.fortran/module.exp: Completion matches fortran module
index 8f941912f3ced082b32868607f6e875b055d457b..aa5727a9e2c31a5faf85dd993b507e4ae569c91a 100644 (file)
 
 static int close_syscall = SYS_close;
 static int chroot_syscall = SYS_chroot;
+/* GDB had a bug where it couldn't catch syscall number 0 (PR 16297).
+   In most GNU/Linux architectures, syscall number 0 is
+   restart_syscall, which can't be called from userspace.  However,
+   the "read" syscall is zero on x86_64.  */
+static int read_syscall = SYS_read;
+static int pipe_syscall = SYS_pipe;
+static int write_syscall = SYS_write;
 static int exit_group_syscall = SYS_exit_group;
 
 int
 main (void)
 {
+       int fd[2];
+       char buf1[2] = "a";
+       char buf2[2];
+
        /* A close() with a wrong argument.  We are only
           interested in the syscall.  */
        close (-1);
 
        chroot (".");
 
+       pipe (fd);
+
+       write (fd[1], buf1, sizeof (buf1));
+       read (fd[0], buf2, sizeof (buf2));
+
        /* The last syscall.  Do not change this.  */
        _exit (0);
 }
index fd7d2dba658a6528bf10ee571e9824255e0250d8..5925419f08bae021abd28100dfda2344f47bbae5 100644 (file)
@@ -47,7 +47,7 @@ if  { [prepare_for_testing ${testfile}.exp $testfile ${testfile}.c] } {
 
 # All (but the last) syscalls from the example code
 # They are ordered according to the file, so do not change this.
-set all_syscalls { "close" "chroot" }
+set all_syscalls { "close" "chroot" "pipe" "write" "read" }
 set all_syscalls_numbers { }
 
 # The last syscall (exit()) does not return, so
@@ -392,11 +392,12 @@ proc do_syscall_tests_without_xml {} {
 # This procedure fills the vector "all_syscalls_numbers" with the proper
 # numbers for the used syscalls according to the architecture.
 proc fill_all_syscalls_numbers {} {
-    global all_syscalls_numbers last_syscall_number
+    global all_syscalls_numbers last_syscall_number all_syscalls
+
+    foreach syscall $all_syscalls {
+       lappend all_syscalls_numbers [get_integer_valueof "${syscall}_syscall" -1]
+    }
 
-    set close_syscall [get_integer_valueof "close_syscall" -1]
-    set chroot_syscall [get_integer_valueof "chroot_syscall" -1]
-    set all_syscalls_numbers [list $close_syscall $chroot_syscall]
     set last_syscall_number [get_integer_valueof "exit_group_syscall" -1]
 }