This is the mail archive of the gdb-patches@sourceware.org mailing list for the GDB project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: [RFC 3/3] catch syscall -- try 6 -- Build system, testcase and documentation


Hi Eli,

On Saturday 05 September 2009, Eli Zaretskii wrote:
> > From: Sérgio_Durigan_Júnior <sergiodj@linux.vnet.ibm.com>
> > Date: Fri, 4 Sep 2009 16:00:53 -0300
> >
> > At last but not least, here is the patch that updates the build system,
> > testcase and documentation parts of GDB.
> 
> Thanks.  I do have some comments, though (sorry).

No problem.

> > +* GDB now has the new command `catch syscall'.  It can be used to
> > +catch when the inferior calls a system call, or when the system call
> > +returns.  Also, you can specify which system calls you would like GDB
> > +to catch (or issue only a `catch syscall' without arguments, which will
> > +make GDB catch every system call).  For instance, if you would like to
> > +catch the system call close, you would issue a:
> > +
> > +    (gdb) catch syscall close
> > +
> > +Then, when the program is running again, GDB will keep track of all
> > +the system calls the inferior is calling, and will stop the execution
> > +if the system call called or returned is equal to the system call
> > +that you asked it to catch (note that if you did not provide any system
> > +call, then GDB would stop on any system call).  After stopping the
> > +inferior, GDB will print something like:
> > +
> > +    Catchpoint 1 (call to syscall 'close'),
> > +    	0xb7ff831d in ?? () from /lib/ld-linux.so.2
> > +
> > +It indicates that the correct system call was caught.  If you choose
> > +to continue the execution of the inferior from this point, then you
> > +should see GDB catching the return of this system call, like that:
> > +
> > +    Catchpoint 1 (returned from syscall 'close'),
> > +	   0xb7ff831d in ?? () from /lib/ld-linux.so.2
> > +
> > +This feature is available with a native GDB running on the Linux Kernel,
> > +under the following architectures: x86, x86_64, PowerPC and PowerPC64.
> 
> This is okay, but much too long for a NEWS entry.  I suggest the
> following shorter variant, which is similar to other NEWS entries:
> 
>     catch syscall [NAME(S) | NUMBER(S)]
>       Catch system calls.  Arguments, which should be names of system
>       calls or their numbers, mean catch only those syscalls.  Without
>       arguments, every syscall will be caught.  When the inferior issues
>       any of the specified syscalls, GDB will stop and announce the system
>       call, both when it is called and when its call returns.  This
>       feature is currently available with a native GDB running on the
>       Linux Kernel, under the following architectures: x86, x86_64,
>       PowerPC and PowerPC64.
> 
> Also, please put this entry in the "New commands" section of NEWS.

Ok, done.  Please, take a look at this now.

Regards,

-- 
Sérgio Durigan Júnior
Linux on Power Toolchain - Software Engineer
Linux Technology Center - LTC
IBM Brazil
diff --git a/gdb/Makefile.in b/gdb/Makefile.in
index 7f2fe58..d42d6fb 100644
--- a/gdb/Makefile.in
+++ b/gdb/Makefile.in
@@ -166,6 +166,9 @@ INTL_CFLAGS = @INCINTL@
 TARGET_SYSTEM_ROOT = @TARGET_SYSTEM_ROOT@
 TARGET_SYSTEM_ROOT_DEFINE = @TARGET_SYSTEM_ROOT_DEFINE@
 
+# Did the user give us a --with-gdb-datadir option?
+GDB_DATADIR_PATH = @GDB_DATADIR_PATH@
+
 # Helper code from gnulib.
 LIBGNU = gnulib/libgnu.a
 INCGNU = -I$(srcdir)/gnulib -Ignulib
@@ -677,7 +680,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
 	xml-tdesc.c xml-support.c \
 	inferior.c gdb_usleep.c \
 	record.c \
-	jit.c
+	jit.c \
+	xml-syscall.c \
 
 LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
 
@@ -746,7 +750,7 @@ 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 linux-tdep.h \
-gdb_usleep.h jit.h
+gdb_usleep.h jit.h xml-syscall.h
 
 # Header files that already have srcdir in them, or which are in objdir.
 
@@ -826,11 +830,17 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
 	trad-frame.o \
 	tramp-frame.o \
 	solib.o solib-null.o \
-	prologue-value.o memory-map.o xml-support.o \
+	prologue-value.o memory-map.o xml-support.o xml-syscall.o \
 	target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
 	inferior.o osdata.o gdb_usleep.o record.o \
 	jit.o
 
+# Definitions for the syscall's XML files and dir
+XML_SYSCALLS_DIR = syscalls/
+XML_SYSCALLS_FILES = gdb-syscalls.dtd \
+		     ppc-linux.xml ppc64-linux.xml \
+		     i386-linux.xml amd64-linux.xml
+
 TSOBS = inflow.o
 
 SUBDIRS = @subdirs@
@@ -864,11 +874,41 @@ generated_files = config.h observer.h observer.inc ada-lex.c \
 	$(COMPILE) $<
 	$(POSTCOMPILE)
 
-all: gdb$(EXEEXT) $(CONFIG_ALL)
+all: gdb$(EXEEXT) $(CONFIG_ALL) xml-syscall-copy
 	@$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do
 .PHONY: all-tui
 all-tui: $(TUI)$(EXEEXT)
 
+# This is needed for running GDB from the build directory
+.PHONY: xml-syscall-copy
+xml-syscall-copy:
+	if [ "`cd $(srcdir) && pwd`" != "`pwd`" ] ; then \
+	  mkdir -p ./$(XML_SYSCALLS_DIR) ; \
+	  list='$(XML_SYSCALLS_FILES)' ; \
+ 	  for file in $$list ; do \
+	    f=$(srcdir)/$(XML_SYSCALLS_DIR)/$$file ; \
+	    if test -f $$f ; then \
+	      $(INSTALL_DATA) $$f \
+	    	  ./$(XML_SYSCALLS_DIR) ; \
+	    fi ; \
+	  done ; \
+	fi ;
+
+# This target is responsible for properly installing the syscalls'
+# XML files in the system.
+.PHONY: xml-syscall-install
+xml-syscall-install:
+	$(SHELL) $(srcdir)/../mkinstalldirs \
+		$(DESTDIR)$(GDB_DATADIR_PATH)/$(XML_SYSCALLS_DIR) ; \
+	list='$(XML_SYSCALLS_FILES)' ; \
+	for file in $$list ; do \
+	  f=$(srcdir)/$(XML_SYSCALLS_DIR)/$$file ; \
+	  if test -f $$f ; then \
+	    $(INSTALL_DATA) $$f \
+	    	$(DESTDIR)$(GDB_DATADIR_PATH)/$(XML_SYSCALLS_DIR) ; \
+	  fi ; \
+	done ;
+
 installcheck:
 
 # The check target can not use subdir_do, because subdir_do does not
@@ -925,8 +965,11 @@ gdb.z:gdb.1
 # source file and doesn't care about rebuilding or just wants to save the
 # time it takes for make to check that all is up to date.
 # install-only is intended to address that need.
-install: all install-only
-install-only: $(CONFIG_INSTALL)
+install: all install-only 
+
+# The "install-only" target also installs the syscalls' XML files in
+# the system.
+install-only: $(CONFIG_INSTALL) xml-syscall-install
 	transformed_name=`t='$(program_transform_name)'; \
 			  echo gdb | sed -e "$$t"` ; \
 		if test "x$$transformed_name" = x; then \
diff --git a/gdb/NEWS b/gdb/NEWS
index 56fdae9..21c4ac4 100644
--- a/gdb/NEWS
+++ b/gdb/NEWS
@@ -3,6 +3,18 @@
 
 *** Changes since GDB 6.8
 
+* GDB now has the new command `catch syscall'.
+
+  catch syscall [NAME(S) | NUMBER(S)]
+    Catch system calls.  Arguments, which should be names of system
+    calls or their numbers, mean catch only those syscalls.  Without
+    arguments, every syscall will be caught.  When the inferior issues
+    any of the specified syscalls, GDB will stop and announce the system
+    call, both when it is called and when its call returns.  This
+    feature is currently available with a native GDB running on the
+    Linux Kernel, under the following architectures: x86, x86_64,
+    PowerPC and PowerPC64.
+
 * GDB now has an interface for JIT compilation.  Applications that
 dynamically generate code can create symbol files in memory and register
 them with GDB.  For users, the feature should work transparently, and
@@ -234,6 +246,10 @@ powerpc-linux or powerpc64-linux and the spu-elf targets, using the
 
 * New commands (for set/show, see "New options" below)
 
+catch syscall [NAME(S) | NUMBER(S)]
+  Catch system calls.  Arguments should be names of system calls or their
+  numbers.  Without arguments, every system call will be caught.
+
 find [/size-char] [/max-count] start-address, end-address|+search-space-size,
     val1 [, val2, ...]
   Search memory for a sequence of bytes.
diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo
index 2027351..80b4789 100644
--- a/gdb/doc/gdb.texinfo
+++ b/gdb/doc/gdb.texinfo
@@ -3685,6 +3685,137 @@ A failed Ada assertion.
 A call to @code{exec}.  This is currently only available for HP-UX
 and @sc{gnu}/Linux.
 
+@item syscall
+@itemx syscall @r{[}@var{name} @r{|} @var{number}@r{]} @r{...}
+@cindex break on a system call.
+A call to or return from a system call, a.k.a.@: @dfn{syscall}.  A
+syscall is a mechanism for application programs to request a service
+from the operating system (OS) or one of the OS system services.
+@value{GDBN} can catch some or all of the syscalls issued by the
+debuggee, and show the related information for each syscall.  If no
+argument is specified, calls to and returns from all system calls
+will be caught.
+
+@var{name} can be any system call name that is valid for the
+underlying OS.  Just what syscalls are valid depends on the OS.  On
+GNU and Unix systems, you can find the full list of valid syscall
+names on @file{/usr/include/asm/unistd.h}.
+
+@c For MS-Windows, the syscall names and the corresponding numbers
+@c can be found, e.g., on this URL:
+@c http://www.metasploit.com/users/opcode/syscalls.html
+@c but we don't support Windows syscalls yet.
+
+Normally, @value{GDBN} knows in advance which syscalls are valid for
+each OS, so you can use the @value{GDBN} command-line completion
+facilities (@pxref{Completion,, command completion}) to list the
+available choices.
+
+You may also specify the system call numerically.  A syscall's
+number is the value passed to the OS's syscall dispatcher to
+identify the requested service.  When you specify the syscall by its
+name, @value{GDBN} uses its database of syscalls to convert the name
+into the corresponding numeric code, but using the number directly
+may be useful if @value{GDBN}'s database does not have the complete
+list of syscalls on your system (e.g., because @value{GDBN} lags
+behind the OS upgrades).
+
+The example below illustrates how this command works if you don't provide
+arguments to it:
+
+@smallexample
+(@value{GDBP}) catch syscall
+Catchpoint 1 (syscall)
+(@value{GDBP}) r
+Starting program: /tmp/catch-syscall
+
+Catchpoint 1 (call to syscall 'close'), \
+	   0xffffe424 in __kernel_vsyscall ()
+(@value{GDBP}) c
+Continuing.
+
+Catchpoint 1 (returned from syscall 'close'), \
+	0xffffe424 in __kernel_vsyscall ()
+(@value{GDBP})
+@end smallexample
+
+Here is an example of catching a system call by name:
+
+@smallexample
+(@value{GDBP}) catch syscall chroot
+Catchpoint 1 (syscall 'chroot' [61])
+(@value{GDBP}) r
+Starting program: /tmp/catch-syscall
+
+Catchpoint 1 (call to syscall 'chroot'), \
+		   0xffffe424 in __kernel_vsyscall ()
+(@value{GDBP}) c
+Continuing.
+
+Catchpoint 1 (returned from syscall 'chroot'), \
+	0xffffe424 in __kernel_vsyscall ()
+(@value{GDBP})
+@end smallexample
+
+An example of specifying a system call numerically.  In the case
+below, the syscall number has a corresponding entry in the XML
+file, so @value{GDBN} finds its name and prints it:
+
+@smallexample
+(@value{GDBP}) catch syscall 252
+Catchpoint 1 (syscall(s) 'exit_group')
+(@value{GDBP}) r
+Starting program: /tmp/catch-syscall
+
+Catchpoint 1 (call to syscall 'exit_group'), \
+		   0xffffe424 in __kernel_vsyscall ()
+(@value{GDBP}) c
+Continuing.
+
+Program exited normally.
+(@value{GDBP})
+@end smallexample
+
+However, there can be situations when there is no corresponding name
+in XML file for that syscall number.  In this case, @value{GDBN} prints
+a warning message saying that it was not able to find the syscall name,
+but the catchpoint will be set anyway.  See the example below:
+
+@smallexample
+(@value{GDBP}) catch syscall 764
+warning: The number '764' does not represent a known syscall.
+Catchpoint 2 (syscall 764)
+(@value{GDBP})
+@end smallexample
+
+If you configure @value{GDBN} using the @samp{--without-expat} option,
+it will not be able to display syscall names.  Also, if your
+architecture does not have an XML file describing its system calls,
+you will not be able to see the syscall names.  It is important to
+notice that these two features are used for accessing the syscall
+name database.  In either case, you will see a warning like this:
+
+@smallexample
+(@value{GDBP}) catch syscall
+warning: Could not open "syscalls/i386-linux.xml"
+warning: Could not load the syscall XML file 'syscalls/i386-linux.xml'.
+GDB will not be able to display syscall names.
+Catchpoint 1 (syscall)
+(@value{GDBP})
+@end smallexample
+
+Of course, the file name will change depending on your architecture and system.
+
+Still using the example above, you can also try to catch a syscall by its
+number.  In this case, you would see something like:
+
+@smallexample
+(@value{GDBP}) catch syscall 252
+Catchpoint 1 (syscall(s) 252)
+@end smallexample
+
+Again, in this case @value{GDBN} would not be able to display syscall's names.
+
 @item fork
 A call to @code{fork}.  This is currently only available for HP-UX
 and @sc{gnu}/Linux.
diff --git a/gdb/testsuite/gdb.base/Makefile.in b/gdb/testsuite/gdb.base/Makefile.in
index 9f382db..12db521 100644
--- a/gdb/testsuite/gdb.base/Makefile.in
+++ b/gdb/testsuite/gdb.base/Makefile.in
@@ -12,7 +12,7 @@ EXECUTABLES = all-types annota1 bitfields break \
 	scope section_command setshow setvar shmain sigall signals \
 	solib solib_sl so-impl-ld so-indr-cl \
 	step-line step-test structs structs2 \
-	twice-tmp varargs vforked-prog watchpoint whatis
+	twice-tmp varargs vforked-prog watchpoint whatis catch-syscall
 
 MISCELLANEOUS = coremmap.data ../foobar.baz \
 	shr1.sl shr2.sl solib_sl.sl solib1.sl solib2.sl
diff --git a/gdb/testsuite/gdb.base/catch-syscall.c b/gdb/testsuite/gdb.base/catch-syscall.c
new file mode 100644
index 0000000..64850de
--- /dev/null
+++ b/gdb/testsuite/gdb.base/catch-syscall.c
@@ -0,0 +1,25 @@
+/* This file is used to test the 'catch syscall' feature on GDB.
+ 
+   Please, if you are going to edit this file DO NOT change the syscalls
+   being called (nor the order of them).  If you really must do this, then
+   take a look at catch-syscall.exp and modify there too.
+
+   Written by Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
+   September, 2008 */
+
+#include <unistd.h>
+#include <fcntl.h>
+#include <sys/stat.h>
+
+int
+main (void)
+{
+	/* A close() with a wrong argument.  We are only
+	   interested in the syscall.  */
+	close (-1);
+
+	chroot (".");
+
+	/* The last syscall.  Do not change this.  */
+	_exit (0);
+}
diff --git a/gdb/testsuite/gdb.base/catch-syscall.exp b/gdb/testsuite/gdb.base/catch-syscall.exp
new file mode 100644
index 0000000..6798d04
--- /dev/null
+++ b/gdb/testsuite/gdb.base/catch-syscall.exp
@@ -0,0 +1,445 @@
+#   Copyright 1997, 1999, 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/>.
+
+
+# This program tests the 'catch syscall' functionality.
+#
+# It was written by Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
+# on September/2008.
+
+if { [is_remote target] || ![isnative] } then {
+    continue
+}
+
+set prms_id 0
+set bug_id 0
+
+global srcfile
+set testfile "catch-syscall"
+set srcfile ${testfile}.c
+set binfile ${objdir}/${subdir}/${testfile}
+
+# 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_numbers { }
+# The last syscall (exit()) does not return, so
+# we cannot expect the catchpoint to be triggered
+# twice.  It is a special case.
+set last_syscall "exit_group"
+
+if  { [gdb_compile "${srcdir}/${subdir}/${srcfile}" "${binfile}" executable {debug}] != "" } {
+     untested catch-syscall.exp
+     return -1
+}
+
+# Until "catch syscall" is implemented on other targets...
+if {![istarget "hppa*-hp-hpux*"] && ![istarget "*-linux*"]} then {
+    continue
+}
+
+# This shall be updated whenever 'catch syscall' is implemented
+# on some architecture.
+#if { ![istarget "i\[34567\]86-*-linux*"]
+if { ![istarget "x86_64-*-linux*"] && ![istarget "i\[34567\]86-*-linux*"]
+     && ![istarget "powerpc-*-linux*"] && ![istarget "powerpc64-*-linux*"] } {
+     continue
+}
+
+# Internal procedure used to check if, after issuing a 'catch syscall'
+# command (without arguments), the 'info breakpoints' command displays
+# that '"any syscall"' is to be caught.
+proc check_info_bp_any_syscall {} {
+    global gdb_prompt
+
+    # Verifying that the catchpoint appears in the 'info breakpoints'
+    # command, but with "<any syscall>".
+    set thistest "catch syscall appears in 'info breakpoints'"
+    gdb_test "info breakpoints" ".*catchpoint.*keep y.*syscall \"<any syscall>\".*" $thistest
+}
+
+# Internal procedure used to check if, after issuing a 'catch syscall X'
+# command (with arguments), the 'info breakpoints' command displays
+# that the syscall 'X' is to be caught.
+proc check_info_bp_specific_syscall { syscall } {
+    global gdb_prompt
+
+    set thistest "syscall(s) $syscall appears in 'info breakpoints'"
+    gdb_test "info breakpoints" ".*catchpoint.*keep y.*syscall(\[(\]s\[)\])? (.)?${syscall}(.)?.*" $thistest
+}
+
+# Internal procedure used to check if, after issuing a 'catch syscall X'
+# command (with many arguments), the 'info breakpoints' command displays
+# that the syscalls 'X' are to be caught.
+proc check_info_bp_many_syscalls { syscalls } {
+    global gdb_prompt
+    set filter_str ""
+
+    foreach name $syscalls {
+      set filter_str "${filter_str}${name}, "
+    }
+
+    set filter_str [ string trimright $filter_str ", " ]
+
+    set thistest "syscalls $filter_str appears in 'info breakpoints'"
+    gdb_test "info breakpoints" ".*catchpoint.*keep y.*syscalls (.)?${filter_str}(.)?.*" $thistest
+}
+
+# This procedure checks if there was a call to a syscall.
+proc check_call_to_syscall { syscall } {
+    global gdb_prompt
+
+    set thistest "program has called $syscall"
+    gdb_test "continue" "Catchpoint .*(call to syscall .?${syscall}.?).*" $thistest
+}
+
+# This procedure checks if the syscall returned.
+proc check_return_from_syscall { syscall } {
+    global gdb_prompt
+
+    set thistest "syscall $syscall has returned"
+    gdb_test "continue" "Catchpoint .*(returned from syscall (.)?${syscall}(.)?).*" $thistest
+}
+
+# Internal procedure that performs two 'continue' commands and checks if
+# a syscall call AND return occur.
+proc check_continue { syscall } {
+    global gdb_prompt
+
+    # Testing if the 'continue' stops at the
+    # specified syscall_name.  If it does, then it should
+    # first print that the infeior has called the syscall,
+    # and after print that the syscall has returned.
+
+    # Testing if the inferiorr has called the syscall.
+    check_call_to_syscall $syscall
+    # And now, that the syscall has returned.
+    check_return_from_syscall $syscall
+}
+
+# Inserts a syscall catchpoint with an argument.
+proc insert_catch_syscall_with_arg { syscall } {
+    global gdb_prompt
+
+    # Trying to set the catchpoint
+    set thistest "catch syscall with arguments ($syscall)"
+    gdb_test "catch syscall $syscall" "Catchpoint .*(syscall (.)?${syscall}(.)?( \[\[0-9\]+\])?).*" $thistest
+
+    check_info_bp_specific_syscall $syscall
+}
+
+# Inserts a syscall catchpoint with many arguments.
+proc insert_catch_syscall_with_many_args { syscalls numbers } {
+    global gdb_prompt
+    set catch [ join $syscalls " " ]
+    set filter_str ""
+
+    foreach name $syscalls number $numbers {
+      set filter_str "${filter_str}'${name}' \[${number}\] "
+    }
+
+    set filter_str [ string trimright $filter_str " " ]
+
+    # Trying to set the catchpoint
+    set thistest "catch syscall with arguments ($filter_str)"
+    gdb_test "catch syscall $catch" "Catchpoint .*(syscalls (.)?${filter_str}(.)?).*" $thistest
+
+    check_info_bp_many_syscalls $syscalls
+}
+
+proc check_for_program_end {} {
+    global gdb_prompt
+
+    # Deleting the catchpoints
+    delete_breakpoints
+
+    set thistest "successful program end"
+    gdb_test "continue" "Program exited normally.*" $thistest
+
+}
+
+proc test_catch_syscall_without_args {} {
+    global gdb_prompt all_syscalls last_syscall
+
+    # Trying to set the syscall
+    set thistest "setting catch syscall without arguments"
+    gdb_test "catch syscall" "Catchpoint .*(syscall).*" $thistest
+
+    check_info_bp_any_syscall
+
+    # We have to check every syscall
+    foreach name $all_syscalls {
+        check_continue $name
+    }
+
+    # At last but not least, we check if the inferior
+    # has called the last (exit) syscall.
+    check_call_to_syscall $last_syscall
+
+    # Now let's see if the inferior correctly finishes.
+    check_for_program_end
+}
+
+proc test_catch_syscall_with_args {} {
+    global gdb_prompt
+    set syscall_name "close"
+
+    insert_catch_syscall_with_arg $syscall_name 
+
+    # Can we continue until we catch the syscall?
+    check_continue $syscall_name
+
+    # Now let's see if the inferior correctly finishes.
+    check_for_program_end
+}
+
+proc test_catch_syscall_with_many_args {} {
+    global gdb_prompt all_syscalls all_syscalls_numbers
+
+    insert_catch_syscall_with_many_args $all_syscalls $all_syscalls_numbers
+
+    # Can we continue until we catch the syscalls?
+    foreach name $all_syscalls {
+        check_continue $name
+    }
+
+    # Now let's see if the inferior correctly finishes.
+    check_for_program_end
+}
+
+proc test_catch_syscall_with_wrong_args {} {
+    global gdb_prompt
+    # mlock is not called from the source
+    set syscall_name "mlock"
+
+    insert_catch_syscall_with_arg $syscall_name
+
+    # Now, we must verify if the program stops with a continue.
+    # If it doesn't, everything is right (since we don't have
+    # a syscall named "mlock" in it).  Otherwise, this is a failure.
+    set thistest "catch syscall with unused syscall ($syscall_name)"
+    gdb_test "continue" "Program exited normally.*" $thistest
+}
+
+proc test_catch_syscall_restarting_inferior {} {
+    global gdb_prompt
+    set syscall_name "chroot"
+
+    insert_catch_syscall_with_arg $syscall_name
+
+    # Let's first reach the call of the syscall.
+    check_call_to_syscall $syscall_name
+
+    # Now, restart the program
+    rerun_to_main
+
+    # And check for call/return
+    check_continue $syscall_name
+
+    # Can we finish?
+    check_for_program_end
+}
+
+proc do_syscall_tests {} {
+    global gdb_prompt srcdir
+
+    # First, we need to set GDB datadir.
+    send_gdb "set data-directory $srcdir/..\n"
+    gdb_expect 10 {
+	-re "$gdb_prompt $" {
+	    verbose "Setting GDB datadir to $srcdir/..." 2
+	}
+	timeout {
+	    error "Couldn't set GDB datadir."
+	}
+    }
+
+    # Verify that the 'catch syscall' help is available
+    set thistest "help catch syscall"
+    gdb_test "help catch syscall" "Catch system calls.*" $thistest
+
+    # Try to set a catchpoint to a nonsense syscall
+    set thistest "catch syscall to a nonsense syscall is prohibited"
+    gdb_test "catch syscall nonsense_syscall" "Unknown syscall name .*" $thistest
+
+    # Testing the 'catch syscall' command without arguments.
+    # This test should catch any syscalls.
+    if [runto_main] then { test_catch_syscall_without_args }
+
+    # Testing the 'catch syscall' command with arguments.
+    # This test should only catch the specified syscall.
+    if [runto_main] then { test_catch_syscall_with_args }
+
+    # Testing the 'catch syscall' command with many arguments.
+    # This test should catch $all_syscalls.
+    if [runto_main] then { test_catch_syscall_with_many_args }
+
+    # Testing the 'catch syscall' command with WRONG arguments.
+    # This test should not trigger any catchpoints.
+    if [runto_main] then { test_catch_syscall_with_wrong_args }
+
+    # Testing the 'catch' syscall command during a restart of
+    # the inferior.
+    if [runto_main] then { test_catch_syscall_restarting_inferior }
+}
+
+proc test_catch_syscall_fail_noxml {} {
+    global gdb_prompt
+
+    # Sanitizing.
+    delete_breakpoints
+
+    # Testing to see if we receive a warning when calling "catch syscall"
+    # without XML support.
+    set thistest "Catch syscall displays a warning when there is no XML support"
+    gdb_test "catch syscall" "warning: Could not open .*warning: Could not load the syscall XML file .*GDB will not be able to display syscall names.*Catchpoint .*(syscall).*" $thistest
+
+    # Since the catchpoint was set, we must check if it's present at
+    # "info breakpoints"
+    check_info_bp_any_syscall
+
+    # Sanitizing.
+    delete_breakpoints
+}
+
+proc test_catch_syscall_without_args_noxml {} {
+    # We will need the syscall names even not using it
+    # because we need to know know many syscalls are in
+    # the example file.
+    global gdb_prompt all_syscalls last_syscall
+
+    delete_breakpoints
+
+    set thistest "Catch syscall without arguments and without XML support"
+    gdb_test "catch syscall" "Catchpoint .*(syscall).*"
+
+    # Now, we should be able to set a catchpoint,
+    # and GDB shall not display the warning anymore.
+    foreach name $all_syscalls {
+        # Unfortunately, we don't know the syscall number
+        # that will be caught because this information is
+        # arch-dependent.  Thus, we try to catch anything
+        # similar to a number.
+        check_continue "\[0-9\]*"
+    }
+
+    # At last but not least, we check if the inferior
+    # has called the last (exit) syscall.
+    check_call_to_syscall "\[0-9\]*"
+
+    delete_breakpoints
+}
+
+proc test_catch_syscall_with_args_noxml {} {
+    global gdb_prompt
+
+    # The number of the "close" syscall.  This is our
+    # option for a "long-estabilished" syscall in all
+    # Linux architectures, but unfortunately x86_64 and
+    # a few other platforms don't "follow the convention".
+    # Because of this, we need this ugly check :-(.
+    set close_number ""
+    if { [istarget "x86_64-*-linux*"] } {
+        set close_number "3"
+    } else {
+        set close_number "6"
+    }
+
+    delete_breakpoints
+
+    insert_catch_syscall_with_arg $close_number
+
+    check_continue $close_number
+
+    delete_breakpoints
+}
+
+proc test_catch_syscall_with_wrong_args_noxml {} {
+    global gdb_prompt
+
+    delete_breakpoints
+
+    # Even without XML support, GDB should not accept unknown
+    # syscall names for the catchpoint.
+    set thistest "Catch a nonsense syscall without XML support"
+    gdb_test "catch syscall nonsense_syscall" "Unknown syscall name .nonsense_syscall.*" $thistest
+
+    delete_breakpoints
+}
+
+proc do_syscall_tests_without_xml {} {
+    global gdb_prompt srcdir
+
+    # In this case, we don't need to set GDB's datadir because
+    # we want GDB to display only numbers, not names.  So, let's
+    # begin with the tests.
+
+    # The first test is to see if GDB displays a warning when we
+    # try to catch syscalls without the XML support.
+    test_catch_syscall_fail_noxml
+
+    # Now, let's test if we can catch syscalls without XML support.
+    # We should succeed, but GDB is not supposed to print syscall names.
+    if [runto_main] then { test_catch_syscall_without_args_noxml }
+
+    # The only valid argument "catch syscall" should accept is the
+    # syscall number, and not the name (since it can't translate a
+    # name to a number).
+    #
+    # It's worth mentioning that we only try to catch the syscall
+    # close().  This is because the syscall number is an arch-dependent
+    # information, so we can't assume that we know every syscall number
+    # in this system.  Therefore, we have decided to use a "long-estabilished"
+    # system call, and close() just sounded the right choice :-).
+    if [runto_main] then { test_catch_syscall_with_args_noxml }
+
+    # Now, we'll try to provide a syscall name (valid or not) to the command,
+    # and expect it to fail.
+    if [runto_main] then { test_catch_syscall_with_wrong_args_noxml }
+}
+
+# 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
+
+    # For Linux on x86, PPC and PPC64, the numbers for the syscalls "close" and
+    # "chroot" are the same.
+    if { ![istarget "i\[34567\]86-*-linux*"]
+         || ![istarget "powerpc-*-linux*"] || ![istarget "powerpc64-*-linux*"] } {
+         set all_syscalls_numbers { "6" "61" }
+    }
+}
+
+# Start with a fresh gdb
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# Execute the tests, using XML support
+do_syscall_tests
+
+# Restart gdb
+
+gdb_exit
+gdb_start
+gdb_reinitialize_dir $srcdir/$subdir
+gdb_load ${binfile}
+
+# Execute the tests, without XML support.  In this case, GDB will
+# only display syscall numbers, and not syscall names.
+do_syscall_tests_without_xml

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]