Implementing catch syscall.
* amd64-linux-tdep.c: Include xml-syscall.h header, define the XML syscall name for the architecture. (amd64_linux_get_syscall_number): New function. (amd64_linux_init_abi): Register the correct functions for syscall catchpoint; set the correct syscall file name. * breakpoint.c: New include: xml-syscall.h. (set_raw_breakpoint_without_location): Setting the parameters for the catch syscall feature. (insert_catch_syscall): New. (remove_catch_syscall): New. (breakpoint_hit_catch_syscall): New. (print_it_catch_syscall): New. (print_one_catch_syscall): New. (print_mention_catch_syscall): New. (catch_syscall_breakpoint_ops): New. (syscall_catchpoint_p): New. (create_catchpoint_without_mention): New. (create_catchpoint): Modified in order to use create_catchpoint_without_mention. (create_syscall_event_catchpoint): New. (clean_up_filters): New. (catch_syscall_split_args): New. (catch_syscall_command_1): New. (delete_breakpoint): Add cleanup for catch syscall. (is_syscall_catchpoint_enabled): New. (catch_syscall_enabled): New. (catching_syscall_number): New. (catch_syscall_completer): New completer function. (add_catch_command): Add the completer function for catchpoints. * breakpoint.h (syscalls_to_be_caught): New vector. (catch_syscall_enabled): New. (catching_syscall_number): New. * gdbarch.c: Regenerated. * gdbarch.h: Regenerated. * gdbarch.sh: Add syscall catchpoint functions and structures. (get_syscall_number): New. (UNKNOWN_SYSCALL): New definition. * i386-linux-nat.c (i386_linux_resume): Select the proper request to be made for ptrace() considering if we are catching syscalls or not. * i386-linux-tdep.c: Include xml-syscall.h header, define the XML syscall name for the architecture. (i386_linux_get_syscall_number): New. (i386_linux_init_abi): Register the correct functions for syscall catchpoint; set the correct syscall file name. * inf-child.c (inf_child_set_syscall_catchpoint): New. (inf_child_target): Assign default values to target_ops. * inf-ptrace.c (inf_ptrace_resume): Select the proper request to be made for ptrace() considering if we are catching syscalls or not. * inferior.h (struct inferior): Included new variables any_syscall_count, syscalls_counts and total_syscalls_count, used to keep track of requested syscall catchpoints. * infrun.c (resume): Add syscall catchpoint. (deal_with_syscall_event): New. (handle_inferior_event): Add syscall entry/return events. (inferior_has_called_syscall): New. * linux-nat.c: Define some helpful variables to track wether we have support for the needed ptrace option. (linux_test_for_tracesysgood): New. (linux_supports_tracesysgood): New. (linux_enable_tracesysgood): New. (linux_enable_event_reporting): Save the current used ptrace options. (linux_child_post_attach): Calling linux_enable_tracesysgood. (linux_child_post_startup_inferior): Likewise. (linux_child_set_syscall_catchpoint): New function. (linux_handle_extended_wait): Handle the case which the inferior stops because it has called or returned from a syscall. (linux_target_install_ops): Install the necessary functions to handle syscall catchpoints. * linux-nat.h (struct lwp_info): Include syscall_state into the structure, which indicates if we are in a syscall entry or return. * ppc-linux-tdep.c: Include xml-syscall.h header, define the XML syscall filename for the arch. (ppc_linux_get_syscall_number): New. (ppc_linux_init_abi): Register the correct functions for syscall catchpoint; setting the correct name for the XML syscall file. * target.c (update_current_target): Update/copy functions related to syscall catchpoint. (target_waitstatus_to_string): Add syscall catchpoint entry/return events. * target.h (struct target_waitstatus): Add syscall number. (struct syscall): New struct to hold information about syscalls in the system. (struct target_ops): Add ops for syscall catchpoint. (inferior_has_called_syscall): New. (target_set_syscall_catchpoint): New. * xml-support.c (xml_fetch_content_from_file): New function, transferred from xml-tdesc.c. * xml-support.h (xml_fetch_content_from_file): New. * xml-tdesc.c (fetch_xml_from_file): Function removed; transferred to xml-support.c. (file_read_description_xml): Updated to use the new xml_fetch_content_from_file function. * syscalls/gdb-syscalls.dtd: New definition file for syscall's XML support. * syscalls/amd64-linux.xml: New file containing information about syscalls for GNU/Linux systems that use amd64 architecture. * syscalls/i386-linux.xml: New file containing information about syscalls for GNU/Linux systems that use i386 architecture. * syscalls/ppc-linux.xml: New file containing information about syscalls for GNU/Linux systems that use PPC architecture. * syscalls/ppc64-linux.xml: New file containing information about syscalls for GNU/Linux systems that use PPC64 architecture. * xml-syscall.c: New file containing functions for manipulating syscall's XML files. * xml-syscall.h: New file, exporting the functions above mentioned. * Makefile.in: Support for relocatable GDB datadir and XML syscall. * NEWS: Added information about the catch syscall feature. * doc/gdb.texinfo (Set Catchpoints): Documentation about the new feature. * testsuite/Makefile.in: Inclusion of catch-syscall object. * testsuite/gdb.base/catch-syscall.c: New file. * testsuite/gdb.base/catch-syscall.exp: New file.
This commit is contained in:
parent
22fe6da0f9
commit
a96d9b2e9a
114
gdb/ChangeLog
114
gdb/ChangeLog
@ -1,3 +1,117 @@
|
|||||||
|
2009-09-14 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
|
||||||
|
|
||||||
|
* amd64-linux-tdep.c: Include xml-syscall.h header, define the XML
|
||||||
|
syscall name for the architecture.
|
||||||
|
(amd64_linux_get_syscall_number): New function.
|
||||||
|
(amd64_linux_init_abi): Register the correct functions for syscall
|
||||||
|
catchpoint; set the correct syscall file name.
|
||||||
|
* breakpoint.c: New include: xml-syscall.h.
|
||||||
|
(set_raw_breakpoint_without_location): Setting the parameters
|
||||||
|
for the catch syscall feature.
|
||||||
|
(insert_catch_syscall): New.
|
||||||
|
(remove_catch_syscall): New.
|
||||||
|
(breakpoint_hit_catch_syscall): New.
|
||||||
|
(print_it_catch_syscall): New.
|
||||||
|
(print_one_catch_syscall): New.
|
||||||
|
(print_mention_catch_syscall): New.
|
||||||
|
(catch_syscall_breakpoint_ops): New.
|
||||||
|
(syscall_catchpoint_p): New.
|
||||||
|
(create_catchpoint_without_mention): New.
|
||||||
|
(create_catchpoint): Modified in order to use
|
||||||
|
create_catchpoint_without_mention.
|
||||||
|
(create_syscall_event_catchpoint): New.
|
||||||
|
(clean_up_filters): New.
|
||||||
|
(catch_syscall_split_args): New.
|
||||||
|
(catch_syscall_command_1): New.
|
||||||
|
(delete_breakpoint): Add cleanup for catch syscall.
|
||||||
|
(is_syscall_catchpoint_enabled): New.
|
||||||
|
(catch_syscall_enabled): New.
|
||||||
|
(catching_syscall_number): New.
|
||||||
|
(catch_syscall_completer): New completer function.
|
||||||
|
(add_catch_command): Add the completer function for catchpoints.
|
||||||
|
* breakpoint.h (syscalls_to_be_caught): New vector.
|
||||||
|
(catch_syscall_enabled): New.
|
||||||
|
(catching_syscall_number): New.
|
||||||
|
* gdbarch.c: Regenerated.
|
||||||
|
* gdbarch.h: Regenerated.
|
||||||
|
* gdbarch.sh: Add syscall catchpoint functions and structures.
|
||||||
|
(get_syscall_number): New.
|
||||||
|
(UNKNOWN_SYSCALL): New definition.
|
||||||
|
* i386-linux-nat.c (i386_linux_resume): Select the proper request
|
||||||
|
to be made for ptrace() considering if we are catching syscalls
|
||||||
|
or not.
|
||||||
|
* i386-linux-tdep.c: Include xml-syscall.h header, define the XML
|
||||||
|
syscall name for the architecture.
|
||||||
|
(i386_linux_get_syscall_number): New.
|
||||||
|
(i386_linux_init_abi): Register the correct functions for syscall
|
||||||
|
catchpoint; set the correct syscall file name.
|
||||||
|
* inf-child.c (inf_child_set_syscall_catchpoint): New.
|
||||||
|
(inf_child_target): Assign default values to target_ops.
|
||||||
|
* inf-ptrace.c (inf_ptrace_resume): Select the proper request
|
||||||
|
to be made for ptrace() considering if we are catching syscalls
|
||||||
|
or not.
|
||||||
|
* inferior.h (struct inferior): Included new variables
|
||||||
|
any_syscall_count, syscalls_counts and total_syscalls_count,
|
||||||
|
used to keep track of requested syscall catchpoints.
|
||||||
|
* infrun.c (resume): Add syscall catchpoint.
|
||||||
|
(deal_with_syscall_event): New.
|
||||||
|
(handle_inferior_event): Add syscall entry/return events.
|
||||||
|
(inferior_has_called_syscall): New.
|
||||||
|
* linux-nat.c: Define some helpful variables to track wether we have
|
||||||
|
support for the needed ptrace option.
|
||||||
|
(linux_test_for_tracesysgood): New.
|
||||||
|
(linux_supports_tracesysgood): New.
|
||||||
|
(linux_enable_tracesysgood): New.
|
||||||
|
(linux_enable_event_reporting): Save the current used ptrace
|
||||||
|
options.
|
||||||
|
(linux_child_post_attach): Calling linux_enable_tracesysgood.
|
||||||
|
(linux_child_post_startup_inferior): Likewise.
|
||||||
|
(linux_child_set_syscall_catchpoint): New function.
|
||||||
|
(linux_handle_extended_wait): Handle the case which the inferior stops
|
||||||
|
because it has called or returned from a syscall.
|
||||||
|
(linux_target_install_ops): Install the necessary functions to handle
|
||||||
|
syscall catchpoints.
|
||||||
|
* linux-nat.h (struct lwp_info): Include syscall_state into the
|
||||||
|
structure, which indicates if we are in a syscall entry or return.
|
||||||
|
* ppc-linux-tdep.c: Include xml-syscall.h header, define the XML
|
||||||
|
syscall filename for the arch.
|
||||||
|
(ppc_linux_get_syscall_number): New.
|
||||||
|
(ppc_linux_init_abi): Register the correct functions for syscall
|
||||||
|
catchpoint; setting the correct name for the XML syscall file.
|
||||||
|
* target.c (update_current_target): Update/copy functions related to
|
||||||
|
syscall catchpoint.
|
||||||
|
(target_waitstatus_to_string): Add syscall catchpoint entry/return
|
||||||
|
events.
|
||||||
|
* target.h (struct target_waitstatus): Add syscall number.
|
||||||
|
(struct syscall): New struct to hold information about syscalls
|
||||||
|
in the system.
|
||||||
|
(struct target_ops): Add ops for syscall catchpoint.
|
||||||
|
(inferior_has_called_syscall): New.
|
||||||
|
(target_set_syscall_catchpoint): New.
|
||||||
|
* xml-support.c (xml_fetch_content_from_file): New function,
|
||||||
|
transferred from xml-tdesc.c.
|
||||||
|
* xml-support.h (xml_fetch_content_from_file): New.
|
||||||
|
* xml-tdesc.c (fetch_xml_from_file): Function removed;
|
||||||
|
transferred to xml-support.c.
|
||||||
|
(file_read_description_xml): Updated to use the new
|
||||||
|
xml_fetch_content_from_file function.
|
||||||
|
* syscalls/gdb-syscalls.dtd: New definition file for syscall's XML
|
||||||
|
support.
|
||||||
|
* syscalls/amd64-linux.xml: New file containing information about
|
||||||
|
syscalls for GNU/Linux systems that use amd64 architecture.
|
||||||
|
* syscalls/i386-linux.xml: New file containing information about
|
||||||
|
syscalls for GNU/Linux systems that use i386 architecture.
|
||||||
|
* syscalls/ppc-linux.xml: New file containing information about
|
||||||
|
syscalls for GNU/Linux systems that use PPC architecture.
|
||||||
|
* syscalls/ppc64-linux.xml: New file containing information about
|
||||||
|
syscalls for GNU/Linux systems that use PPC64 architecture.
|
||||||
|
* xml-syscall.c: New file containing functions for manipulating
|
||||||
|
syscall's XML files.
|
||||||
|
* xml-syscall.h: New file, exporting the functions above mentioned.
|
||||||
|
* Makefile.in: Support for relocatable GDB datadir and XML
|
||||||
|
syscall.
|
||||||
|
* NEWS: Added information about the catch syscall feature.
|
||||||
|
|
||||||
2009-09-14 Doug Evans <dje@google.com>
|
2009-09-14 Doug Evans <dje@google.com>
|
||||||
|
|
||||||
* target.c (memory_xfer_partial): Only update dcache after we know
|
* target.c (memory_xfer_partial): Only update dcache after we know
|
||||||
|
@ -166,6 +166,9 @@ INTL_CFLAGS = @INCINTL@
|
|||||||
TARGET_SYSTEM_ROOT = @TARGET_SYSTEM_ROOT@
|
TARGET_SYSTEM_ROOT = @TARGET_SYSTEM_ROOT@
|
||||||
TARGET_SYSTEM_ROOT_DEFINE = @TARGET_SYSTEM_ROOT_DEFINE@
|
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.
|
# Helper code from gnulib.
|
||||||
LIBGNU = gnulib/libgnu.a
|
LIBGNU = gnulib/libgnu.a
|
||||||
INCGNU = -I$(srcdir)/gnulib -Ignulib
|
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 \
|
xml-tdesc.c xml-support.c \
|
||||||
inferior.c gdb_usleep.c \
|
inferior.c gdb_usleep.c \
|
||||||
record.c \
|
record.c \
|
||||||
jit.c
|
jit.c \
|
||||||
|
xml-syscall.c \
|
||||||
|
|
||||||
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.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 \
|
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 \
|
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 \
|
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.
|
# 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 \
|
trad-frame.o \
|
||||||
tramp-frame.o \
|
tramp-frame.o \
|
||||||
solib.o solib-null.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 \
|
target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
|
||||||
inferior.o osdata.o gdb_usleep.o record.o \
|
inferior.o osdata.o gdb_usleep.o record.o \
|
||||||
jit.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
|
TSOBS = inflow.o
|
||||||
|
|
||||||
SUBDIRS = @subdirs@
|
SUBDIRS = @subdirs@
|
||||||
@ -864,11 +874,41 @@ generated_files = config.h observer.h observer.inc ada-lex.c \
|
|||||||
$(COMPILE) $<
|
$(COMPILE) $<
|
||||||
$(POSTCOMPILE)
|
$(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
|
@$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do
|
||||||
.PHONY: all-tui
|
.PHONY: all-tui
|
||||||
all-tui: $(TUI)$(EXEEXT)
|
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:
|
installcheck:
|
||||||
|
|
||||||
# The check target can not use subdir_do, because subdir_do does not
|
# 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
|
# 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.
|
# time it takes for make to check that all is up to date.
|
||||||
# install-only is intended to address that need.
|
# install-only is intended to address that need.
|
||||||
install: all install-only
|
install: all install-only
|
||||||
install-only: $(CONFIG_INSTALL)
|
|
||||||
|
# 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)'; \
|
transformed_name=`t='$(program_transform_name)'; \
|
||||||
echo gdb | sed -e "$$t"` ; \
|
echo gdb | sed -e "$$t"` ; \
|
||||||
if test "x$$transformed_name" = x; then \
|
if test "x$$transformed_name" = x; then \
|
||||||
|
10
gdb/NEWS
10
gdb/NEWS
@ -234,6 +234,16 @@ powerpc-linux or powerpc64-linux and the spu-elf targets, using the
|
|||||||
|
|
||||||
* New commands (for set/show, see "New options" below)
|
* New commands (for set/show, see "New options" below)
|
||||||
|
|
||||||
|
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.
|
||||||
|
|
||||||
find [/size-char] [/max-count] start-address, end-address|+search-space-size,
|
find [/size-char] [/max-count] start-address, end-address|+search-space-size,
|
||||||
val1 [, val2, ...]
|
val1 [, val2, ...]
|
||||||
Search memory for a sequence of bytes.
|
Search memory for a sequence of bytes.
|
||||||
|
@ -35,6 +35,10 @@
|
|||||||
|
|
||||||
#include "amd64-tdep.h"
|
#include "amd64-tdep.h"
|
||||||
#include "solib-svr4.h"
|
#include "solib-svr4.h"
|
||||||
|
#include "xml-syscall.h"
|
||||||
|
|
||||||
|
/* The syscall's XML filename for i386. */
|
||||||
|
#define XML_SYSCALL_FILENAME_AMD64 "syscalls/amd64-linux.xml"
|
||||||
|
|
||||||
#include "record.h"
|
#include "record.h"
|
||||||
#include "linux-record.h"
|
#include "linux-record.h"
|
||||||
@ -174,6 +178,28 @@ amd64_linux_sigcontext_addr (struct frame_info *this_frame)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static LONGEST
|
||||||
|
amd64_linux_get_syscall_number (struct gdbarch *gdbarch,
|
||||||
|
ptid_t ptid)
|
||||||
|
{
|
||||||
|
struct regcache *regcache = get_thread_regcache (ptid);
|
||||||
|
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
||||||
|
/* The content of a register. */
|
||||||
|
gdb_byte buf[8];
|
||||||
|
/* The result. */
|
||||||
|
LONGEST ret;
|
||||||
|
|
||||||
|
/* Getting the system call number from the register.
|
||||||
|
When dealing with x86_64 architecture, this information
|
||||||
|
is stored at %rax register. */
|
||||||
|
regcache_cooked_read (regcache, AMD64_LINUX_ORIG_RAX_REGNUM, buf);
|
||||||
|
|
||||||
|
ret = extract_signed_integer (buf, 8, byte_order);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/* From <asm/sigcontext.h>. */
|
/* From <asm/sigcontext.h>. */
|
||||||
static int amd64_linux_sc_reg_offset[] =
|
static int amd64_linux_sc_reg_offset[] =
|
||||||
{
|
{
|
||||||
@ -1168,6 +1194,11 @@ amd64_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
|||||||
set_gdbarch_register_type (gdbarch, amd64_linux_register_type);
|
set_gdbarch_register_type (gdbarch, amd64_linux_register_type);
|
||||||
set_gdbarch_register_reggroup_p (gdbarch, amd64_linux_register_reggroup_p);
|
set_gdbarch_register_reggroup_p (gdbarch, amd64_linux_register_reggroup_p);
|
||||||
|
|
||||||
|
/* Functions for 'catch syscall'. */
|
||||||
|
set_xml_syscall_file_name (XML_SYSCALL_FILENAME_AMD64);
|
||||||
|
set_gdbarch_get_syscall_number (gdbarch,
|
||||||
|
amd64_linux_get_syscall_number);
|
||||||
|
|
||||||
/* Enable TLS support. */
|
/* Enable TLS support. */
|
||||||
set_gdbarch_fetch_tls_load_module_address (gdbarch,
|
set_gdbarch_fetch_tls_load_module_address (gdbarch,
|
||||||
svr4_fetch_objfile_link_map);
|
svr4_fetch_objfile_link_map);
|
||||||
|
489
gdb/breakpoint.c
489
gdb/breakpoint.c
@ -60,6 +60,7 @@
|
|||||||
#include "wrapper.h"
|
#include "wrapper.h"
|
||||||
#include "valprint.h"
|
#include "valprint.h"
|
||||||
#include "jit.h"
|
#include "jit.h"
|
||||||
|
#include "xml-syscall.h"
|
||||||
|
|
||||||
/* readline include files */
|
/* readline include files */
|
||||||
#include "readline/readline.h"
|
#include "readline/readline.h"
|
||||||
@ -204,6 +205,8 @@ static int is_hardware_watchpoint (struct breakpoint *bpt);
|
|||||||
|
|
||||||
static void insert_breakpoint_locations (void);
|
static void insert_breakpoint_locations (void);
|
||||||
|
|
||||||
|
static int syscall_catchpoint_p (struct breakpoint *b);
|
||||||
|
|
||||||
static void tracepoints_info (char *, int);
|
static void tracepoints_info (char *, int);
|
||||||
|
|
||||||
static void delete_trace_command (char *, int);
|
static void delete_trace_command (char *, int);
|
||||||
@ -4445,6 +4448,7 @@ set_raw_breakpoint_without_location (struct gdbarch *gdbarch,
|
|||||||
b->frame_id = null_frame_id;
|
b->frame_id = null_frame_id;
|
||||||
b->forked_inferior_pid = null_ptid;
|
b->forked_inferior_pid = null_ptid;
|
||||||
b->exec_pathname = NULL;
|
b->exec_pathname = NULL;
|
||||||
|
b->syscalls_to_be_caught = NULL;
|
||||||
b->ops = NULL;
|
b->ops = NULL;
|
||||||
b->condition_not_parsed = 0;
|
b->condition_not_parsed = 0;
|
||||||
|
|
||||||
@ -4939,7 +4943,266 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
|
|||||||
print_mention_catch_vfork
|
print_mention_catch_vfork
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Create a new breakpoint of the bp_catchpoint kind and return it.
|
/* Implement the "insert" breakpoint_ops method for syscall
|
||||||
|
catchpoints. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
insert_catch_syscall (struct breakpoint *b)
|
||||||
|
{
|
||||||
|
struct inferior *inf = current_inferior ();
|
||||||
|
|
||||||
|
++inf->total_syscalls_count;
|
||||||
|
if (!b->syscalls_to_be_caught)
|
||||||
|
++inf->any_syscall_count;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i, iter;
|
||||||
|
for (i = 0;
|
||||||
|
VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
|
||||||
|
i++)
|
||||||
|
{
|
||||||
|
int elem;
|
||||||
|
if (iter >= VEC_length (int, inf->syscalls_counts))
|
||||||
|
{
|
||||||
|
int old_size = VEC_length (int, inf->syscalls_counts);
|
||||||
|
uintptr_t vec_addr_offset = old_size * ((uintptr_t) sizeof (int));
|
||||||
|
uintptr_t vec_addr;
|
||||||
|
VEC_safe_grow (int, inf->syscalls_counts, iter + 1);
|
||||||
|
vec_addr = (uintptr_t) VEC_address (int, inf->syscalls_counts) +
|
||||||
|
vec_addr_offset;
|
||||||
|
memset ((void *) vec_addr, 0,
|
||||||
|
(iter + 1 - old_size) * sizeof (int));
|
||||||
|
}
|
||||||
|
elem = VEC_index (int, inf->syscalls_counts, iter);
|
||||||
|
VEC_replace (int, inf->syscalls_counts, iter, ++elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
target_set_syscall_catchpoint (PIDGET (inferior_ptid),
|
||||||
|
inf->total_syscalls_count != 0,
|
||||||
|
inf->any_syscall_count,
|
||||||
|
VEC_length (int, inf->syscalls_counts),
|
||||||
|
VEC_address (int, inf->syscalls_counts));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implement the "remove" breakpoint_ops method for syscall
|
||||||
|
catchpoints. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
remove_catch_syscall (struct breakpoint *b)
|
||||||
|
{
|
||||||
|
struct inferior *inf = current_inferior ();
|
||||||
|
|
||||||
|
--inf->total_syscalls_count;
|
||||||
|
if (!b->syscalls_to_be_caught)
|
||||||
|
--inf->any_syscall_count;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
int i, iter;
|
||||||
|
for (i = 0;
|
||||||
|
VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
|
||||||
|
i++)
|
||||||
|
{
|
||||||
|
int elem;
|
||||||
|
if (iter >= VEC_length (int, inf->syscalls_counts))
|
||||||
|
/* Shouldn't happen. */
|
||||||
|
continue;
|
||||||
|
elem = VEC_index (int, inf->syscalls_counts, iter);
|
||||||
|
VEC_replace (int, inf->syscalls_counts, iter, --elem);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return target_set_syscall_catchpoint (PIDGET (inferior_ptid),
|
||||||
|
inf->total_syscalls_count != 0,
|
||||||
|
inf->any_syscall_count,
|
||||||
|
VEC_length (int, inf->syscalls_counts),
|
||||||
|
VEC_address (int, inf->syscalls_counts));
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implement the "breakpoint_hit" breakpoint_ops method for syscall
|
||||||
|
catchpoints. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
breakpoint_hit_catch_syscall (struct breakpoint *b)
|
||||||
|
{
|
||||||
|
/* We must check if we are catching specific syscalls in this breakpoint.
|
||||||
|
If we are, then we must guarantee that the called syscall is the same
|
||||||
|
syscall we are catching. */
|
||||||
|
int syscall_number = 0;
|
||||||
|
|
||||||
|
if (!inferior_has_called_syscall (inferior_ptid, &syscall_number))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
/* Now, checking if the syscall is the same. */
|
||||||
|
if (b->syscalls_to_be_caught)
|
||||||
|
{
|
||||||
|
int i, iter;
|
||||||
|
for (i = 0;
|
||||||
|
VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
|
||||||
|
i++)
|
||||||
|
if (syscall_number == iter)
|
||||||
|
break;
|
||||||
|
/* Not the same. */
|
||||||
|
if (!iter)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implement the "print_it" breakpoint_ops method for syscall
|
||||||
|
catchpoints. */
|
||||||
|
|
||||||
|
static enum print_stop_action
|
||||||
|
print_it_catch_syscall (struct breakpoint *b)
|
||||||
|
{
|
||||||
|
/* These are needed because we want to know in which state a
|
||||||
|
syscall is. It can be in the TARGET_WAITKIND_SYSCALL_ENTRY
|
||||||
|
or TARGET_WAITKIND_SYSCALL_RETURN, and depending on it we
|
||||||
|
must print "called syscall" or "returned from syscall". */
|
||||||
|
ptid_t ptid;
|
||||||
|
struct target_waitstatus last;
|
||||||
|
struct syscall s;
|
||||||
|
struct cleanup *old_chain;
|
||||||
|
char *syscall_id;
|
||||||
|
|
||||||
|
get_last_target_status (&ptid, &last);
|
||||||
|
|
||||||
|
get_syscall_by_number (last.value.syscall_number, &s);
|
||||||
|
|
||||||
|
annotate_catchpoint (b->number);
|
||||||
|
|
||||||
|
if (s.name == NULL)
|
||||||
|
syscall_id = xstrprintf ("%d", last.value.syscall_number);
|
||||||
|
else
|
||||||
|
syscall_id = xstrprintf ("'%s'", s.name);
|
||||||
|
|
||||||
|
old_chain = make_cleanup (xfree, syscall_id);
|
||||||
|
|
||||||
|
if (last.kind == TARGET_WAITKIND_SYSCALL_ENTRY)
|
||||||
|
printf_filtered (_("\nCatchpoint %d (call to syscall %s), "),
|
||||||
|
b->number, syscall_id);
|
||||||
|
else if (last.kind == TARGET_WAITKIND_SYSCALL_RETURN)
|
||||||
|
printf_filtered (_("\nCatchpoint %d (returned from syscall %s), "),
|
||||||
|
b->number, syscall_id);
|
||||||
|
|
||||||
|
do_cleanups (old_chain);
|
||||||
|
|
||||||
|
return PRINT_SRC_AND_LOC;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implement the "print_one" breakpoint_ops method for syscall
|
||||||
|
catchpoints. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_one_catch_syscall (struct breakpoint *b,
|
||||||
|
struct bp_location **last_loc)
|
||||||
|
{
|
||||||
|
struct value_print_options opts;
|
||||||
|
|
||||||
|
get_user_print_options (&opts);
|
||||||
|
/* Field 4, the address, is omitted (which makes the columns
|
||||||
|
not line up too nicely with the headers, but the effect
|
||||||
|
is relatively readable). */
|
||||||
|
if (opts.addressprint)
|
||||||
|
ui_out_field_skip (uiout, "addr");
|
||||||
|
annotate_field (5);
|
||||||
|
|
||||||
|
if (b->syscalls_to_be_caught
|
||||||
|
&& VEC_length (int, b->syscalls_to_be_caught) > 1)
|
||||||
|
ui_out_text (uiout, "syscalls \"");
|
||||||
|
else
|
||||||
|
ui_out_text (uiout, "syscall \"");
|
||||||
|
|
||||||
|
if (b->syscalls_to_be_caught)
|
||||||
|
{
|
||||||
|
int i, iter;
|
||||||
|
char *text = xstrprintf ("%s", "");
|
||||||
|
for (i = 0;
|
||||||
|
VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
|
||||||
|
i++)
|
||||||
|
{
|
||||||
|
char *x = text;
|
||||||
|
struct syscall s;
|
||||||
|
get_syscall_by_number (iter, &s);
|
||||||
|
|
||||||
|
if (s.name != NULL)
|
||||||
|
text = xstrprintf ("%s%s, ", text, s.name);
|
||||||
|
else
|
||||||
|
text = xstrprintf ("%s%d, ", text, iter);
|
||||||
|
|
||||||
|
/* We have to xfree the last 'text' (now stored at 'x')
|
||||||
|
because xstrprintf dinamically allocates new space for it
|
||||||
|
on every call. */
|
||||||
|
xfree (x);
|
||||||
|
}
|
||||||
|
/* Remove the last comma. */
|
||||||
|
text[strlen (text) - 2] = '\0';
|
||||||
|
ui_out_field_string (uiout, "what", text);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
ui_out_field_string (uiout, "what", "<any syscall>");
|
||||||
|
ui_out_text (uiout, "\" ");
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implement the "print_mention" breakpoint_ops method for syscall
|
||||||
|
catchpoints. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
print_mention_catch_syscall (struct breakpoint *b)
|
||||||
|
{
|
||||||
|
if (b->syscalls_to_be_caught)
|
||||||
|
{
|
||||||
|
int i, iter;
|
||||||
|
|
||||||
|
if (VEC_length (int, b->syscalls_to_be_caught) > 1)
|
||||||
|
printf_filtered (_("Catchpoint %d (syscalls"), b->number);
|
||||||
|
else
|
||||||
|
printf_filtered (_("Catchpoint %d (syscall"), b->number);
|
||||||
|
|
||||||
|
for (i = 0;
|
||||||
|
VEC_iterate (int, b->syscalls_to_be_caught, i, iter);
|
||||||
|
i++)
|
||||||
|
{
|
||||||
|
struct syscall s;
|
||||||
|
get_syscall_by_number (iter, &s);
|
||||||
|
|
||||||
|
if (s.name)
|
||||||
|
printf_filtered (" '%s' [%d]", s.name, s.number);
|
||||||
|
else
|
||||||
|
printf_filtered (" %d", s.number);
|
||||||
|
}
|
||||||
|
printf_filtered (")");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
printf_filtered (_("Catchpoint %d (any syscall)"),
|
||||||
|
b->number);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* The breakpoint_ops structure to be used in syscall catchpoints. */
|
||||||
|
|
||||||
|
static struct breakpoint_ops catch_syscall_breakpoint_ops =
|
||||||
|
{
|
||||||
|
insert_catch_syscall,
|
||||||
|
remove_catch_syscall,
|
||||||
|
breakpoint_hit_catch_syscall,
|
||||||
|
print_it_catch_syscall,
|
||||||
|
print_one_catch_syscall,
|
||||||
|
print_mention_catch_syscall
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Returns non-zero if 'b' is a syscall catchpoint. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
syscall_catchpoint_p (struct breakpoint *b)
|
||||||
|
{
|
||||||
|
return (b->ops == &catch_syscall_breakpoint_ops);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a new breakpoint of the bp_catchpoint kind and return it,
|
||||||
|
but does NOT mention it nor update the global location list.
|
||||||
|
This is useful if you need to fill more fields in the
|
||||||
|
struct breakpoint before calling mention.
|
||||||
|
|
||||||
If TEMPFLAG is non-zero, then make the breakpoint temporary.
|
If TEMPFLAG is non-zero, then make the breakpoint temporary.
|
||||||
If COND_STRING is not NULL, then store it in the breakpoint.
|
If COND_STRING is not NULL, then store it in the breakpoint.
|
||||||
@ -4947,16 +5210,14 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
|
|||||||
to the catchpoint. */
|
to the catchpoint. */
|
||||||
|
|
||||||
static struct breakpoint *
|
static struct breakpoint *
|
||||||
create_catchpoint (struct gdbarch *gdbarch, int tempflag,
|
create_catchpoint_without_mention (struct gdbarch *gdbarch, int tempflag,
|
||||||
char *cond_string, struct breakpoint_ops *ops)
|
char *cond_string,
|
||||||
|
struct breakpoint_ops *ops)
|
||||||
{
|
{
|
||||||
struct symtab_and_line sal;
|
struct symtab_and_line sal;
|
||||||
struct breakpoint *b;
|
struct breakpoint *b;
|
||||||
|
|
||||||
init_sal (&sal);
|
init_sal (&sal);
|
||||||
sal.pc = 0;
|
|
||||||
sal.symtab = NULL;
|
|
||||||
sal.line = 0;
|
|
||||||
|
|
||||||
b = set_raw_breakpoint (gdbarch, sal, bp_catchpoint);
|
b = set_raw_breakpoint (gdbarch, sal, bp_catchpoint);
|
||||||
set_breakpoint_count (breakpoint_count + 1);
|
set_breakpoint_count (breakpoint_count + 1);
|
||||||
@ -4969,6 +5230,23 @@ create_catchpoint (struct gdbarch *gdbarch, int tempflag,
|
|||||||
b->disposition = tempflag ? disp_del : disp_donttouch;
|
b->disposition = tempflag ? disp_del : disp_donttouch;
|
||||||
b->ops = ops;
|
b->ops = ops;
|
||||||
|
|
||||||
|
return b;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Create a new breakpoint of the bp_catchpoint kind and return it.
|
||||||
|
|
||||||
|
If TEMPFLAG is non-zero, then make the breakpoint temporary.
|
||||||
|
If COND_STRING is not NULL, then store it in the breakpoint.
|
||||||
|
OPS, if not NULL, is the breakpoint_ops structure associated
|
||||||
|
to the catchpoint. */
|
||||||
|
|
||||||
|
static struct breakpoint *
|
||||||
|
create_catchpoint (struct gdbarch *gdbarch, int tempflag,
|
||||||
|
char *cond_string, struct breakpoint_ops *ops)
|
||||||
|
{
|
||||||
|
struct breakpoint *b =
|
||||||
|
create_catchpoint_without_mention (gdbarch, tempflag, cond_string, ops);
|
||||||
|
|
||||||
mention (b);
|
mention (b);
|
||||||
update_global_location_list (1);
|
update_global_location_list (1);
|
||||||
|
|
||||||
@ -5055,6 +5333,22 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
|
|||||||
print_mention_catch_exec
|
print_mention_catch_exec
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
create_syscall_event_catchpoint (int tempflag, VEC(int) *filter,
|
||||||
|
struct breakpoint_ops *ops)
|
||||||
|
{
|
||||||
|
struct gdbarch *gdbarch = get_current_arch ();
|
||||||
|
struct breakpoint *b =
|
||||||
|
create_catchpoint_without_mention (gdbarch, tempflag, NULL, ops);
|
||||||
|
|
||||||
|
b->syscalls_to_be_caught = filter;
|
||||||
|
|
||||||
|
/* Now, we have to mention the breakpoint and update the global
|
||||||
|
location list. */
|
||||||
|
mention (b);
|
||||||
|
update_global_location_list (1);
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
hw_breakpoint_used_count (void)
|
hw_breakpoint_used_count (void)
|
||||||
{
|
{
|
||||||
@ -7150,6 +7444,113 @@ catch_ada_exception_command (char *arg, int from_tty,
|
|||||||
from_tty);
|
from_tty);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Cleanup function for a syscall filter list. */
|
||||||
|
static void
|
||||||
|
clean_up_filters (void *arg)
|
||||||
|
{
|
||||||
|
VEC(int) *iter = *(VEC(int) **) arg;
|
||||||
|
VEC_free (int, iter);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Splits the argument using space as delimiter. Returns an xmalloc'd
|
||||||
|
filter list, or NULL if no filtering is required. */
|
||||||
|
static VEC(int) *
|
||||||
|
catch_syscall_split_args (char *arg)
|
||||||
|
{
|
||||||
|
VEC(int) *result = NULL;
|
||||||
|
struct cleanup *cleanup = make_cleanup (clean_up_filters, &result);
|
||||||
|
|
||||||
|
while (*arg != '\0')
|
||||||
|
{
|
||||||
|
int i, syscall_number;
|
||||||
|
char *endptr;
|
||||||
|
char cur_name[128];
|
||||||
|
struct syscall s;
|
||||||
|
|
||||||
|
/* Skip whitespace. */
|
||||||
|
while (isspace (*arg))
|
||||||
|
arg++;
|
||||||
|
|
||||||
|
for (i = 0; i < 127 && arg[i] && !isspace (arg[i]); ++i)
|
||||||
|
cur_name[i] = arg[i];
|
||||||
|
cur_name[i] = '\0';
|
||||||
|
arg += i;
|
||||||
|
|
||||||
|
/* Check if the user provided a syscall name or a number. */
|
||||||
|
syscall_number = (int) strtol (cur_name, &endptr, 0);
|
||||||
|
if (*endptr == '\0')
|
||||||
|
{
|
||||||
|
get_syscall_by_number (syscall_number, &s);
|
||||||
|
|
||||||
|
if (s.name == NULL)
|
||||||
|
/* We can issue just a warning, but still create the catchpoint.
|
||||||
|
This is because, even not knowing the syscall name that
|
||||||
|
this number represents, we can still try to catch the syscall
|
||||||
|
number. */
|
||||||
|
warning (_("The number '%d' does not represent a known syscall."),
|
||||||
|
syscall_number);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
/* We have a name. Let's check if it's valid and convert it
|
||||||
|
to a number. */
|
||||||
|
get_syscall_by_name (cur_name, &s);
|
||||||
|
|
||||||
|
if (s.number == UNKNOWN_SYSCALL)
|
||||||
|
/* Here we have to issue an error instead of a warning, because
|
||||||
|
GDB cannot do anything useful if there's no syscall number to
|
||||||
|
be caught. */
|
||||||
|
error (_("Unknown syscall name '%s'."), cur_name);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Ok, it's valid. */
|
||||||
|
VEC_safe_push (int, result, s.number);
|
||||||
|
}
|
||||||
|
|
||||||
|
discard_cleanups (cleanup);
|
||||||
|
return result;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Implement the "catch syscall" command. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
catch_syscall_command_1 (char *arg, int from_tty, struct cmd_list_element *command)
|
||||||
|
{
|
||||||
|
int tempflag;
|
||||||
|
VEC(int) *filter;
|
||||||
|
struct syscall s;
|
||||||
|
struct gdbarch *gdbarch = get_current_arch ();
|
||||||
|
|
||||||
|
/* Checking if the feature if supported. */
|
||||||
|
if (gdbarch_get_syscall_number_p (gdbarch) == 0)
|
||||||
|
error (_("The feature 'catch syscall' is not supported on \
|
||||||
|
this architeture yet."));
|
||||||
|
|
||||||
|
tempflag = get_cmd_context (command) == CATCH_TEMPORARY;
|
||||||
|
|
||||||
|
ep_skip_leading_whitespace (&arg);
|
||||||
|
|
||||||
|
/* We need to do this first "dummy" translation in order
|
||||||
|
to get the syscall XML file loaded or, most important,
|
||||||
|
to display a warning to the user if there's no XML file
|
||||||
|
for his/her architecture. */
|
||||||
|
get_syscall_by_number (0, &s);
|
||||||
|
|
||||||
|
/* The allowed syntax is:
|
||||||
|
catch syscall
|
||||||
|
catch syscall <name | number> [<name | number> ... <name | number>]
|
||||||
|
|
||||||
|
Let's check if there's a syscall name. */
|
||||||
|
|
||||||
|
if (arg != NULL)
|
||||||
|
filter = catch_syscall_split_args (arg);
|
||||||
|
else
|
||||||
|
filter = NULL;
|
||||||
|
|
||||||
|
create_syscall_event_catchpoint (tempflag, filter,
|
||||||
|
&catch_syscall_breakpoint_ops);
|
||||||
|
}
|
||||||
|
|
||||||
/* Implement the "catch assert" command. */
|
/* Implement the "catch assert" command. */
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -7616,6 +8017,7 @@ delete_breakpoint (struct breakpoint *bpt)
|
|||||||
xfree (bpt->source_file);
|
xfree (bpt->source_file);
|
||||||
if (bpt->exec_pathname != NULL)
|
if (bpt->exec_pathname != NULL)
|
||||||
xfree (bpt->exec_pathname);
|
xfree (bpt->exec_pathname);
|
||||||
|
clean_up_filters (&bpt->syscalls_to_be_caught);
|
||||||
|
|
||||||
/* Be sure no bpstat's are pointing at it after it's been freed. */
|
/* Be sure no bpstat's are pointing at it after it's been freed. */
|
||||||
/* FIXME, how can we find all bpstat's?
|
/* FIXME, how can we find all bpstat's?
|
||||||
@ -8552,6 +8954,60 @@ single_step_breakpoint_inserted_here_p (CORE_ADDR pc)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Returns 0 if 'bp' is NOT a syscall catchpoint,
|
||||||
|
non-zero otherwise. */
|
||||||
|
static int
|
||||||
|
is_syscall_catchpoint_enabled (struct breakpoint *bp)
|
||||||
|
{
|
||||||
|
if (syscall_catchpoint_p (bp)
|
||||||
|
&& bp->enable_state != bp_disabled
|
||||||
|
&& bp->enable_state != bp_call_disabled)
|
||||||
|
return 1;
|
||||||
|
else
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
catch_syscall_enabled (void)
|
||||||
|
{
|
||||||
|
struct inferior *inf = current_inferior ();
|
||||||
|
|
||||||
|
return inf->total_syscalls_count != 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
catching_syscall_number (int syscall_number)
|
||||||
|
{
|
||||||
|
struct breakpoint *bp;
|
||||||
|
|
||||||
|
ALL_BREAKPOINTS (bp)
|
||||||
|
if (is_syscall_catchpoint_enabled (bp))
|
||||||
|
{
|
||||||
|
if (bp->syscalls_to_be_caught)
|
||||||
|
{
|
||||||
|
int i, iter;
|
||||||
|
for (i = 0;
|
||||||
|
VEC_iterate (int, bp->syscalls_to_be_caught, i, iter);
|
||||||
|
i++)
|
||||||
|
if (syscall_number == iter)
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Complete syscall names. Used by "catch syscall". */
|
||||||
|
static char **
|
||||||
|
catch_syscall_completer (struct cmd_list_element *cmd,
|
||||||
|
char *text, char *word)
|
||||||
|
{
|
||||||
|
const char **list = get_syscall_names ();
|
||||||
|
return (list == NULL) ? NULL : complete_on_enum (list, text, word);
|
||||||
|
}
|
||||||
|
|
||||||
/* Tracepoint-specific operations. */
|
/* Tracepoint-specific operations. */
|
||||||
|
|
||||||
/* Set tracepoint count to NUM. */
|
/* Set tracepoint count to NUM. */
|
||||||
@ -8903,6 +9359,8 @@ static void
|
|||||||
add_catch_command (char *name, char *docstring,
|
add_catch_command (char *name, char *docstring,
|
||||||
void (*sfunc) (char *args, int from_tty,
|
void (*sfunc) (char *args, int from_tty,
|
||||||
struct cmd_list_element *command),
|
struct cmd_list_element *command),
|
||||||
|
char **(*completer) (struct cmd_list_element *cmd,
|
||||||
|
char *text, char *word),
|
||||||
void *user_data_catch,
|
void *user_data_catch,
|
||||||
void *user_data_tcatch)
|
void *user_data_tcatch)
|
||||||
{
|
{
|
||||||
@ -8912,11 +9370,13 @@ add_catch_command (char *name, char *docstring,
|
|||||||
&catch_cmdlist);
|
&catch_cmdlist);
|
||||||
set_cmd_sfunc (command, sfunc);
|
set_cmd_sfunc (command, sfunc);
|
||||||
set_cmd_context (command, user_data_catch);
|
set_cmd_context (command, user_data_catch);
|
||||||
|
set_cmd_completer (command, completer);
|
||||||
|
|
||||||
command = add_cmd (name, class_breakpoint, NULL, docstring,
|
command = add_cmd (name, class_breakpoint, NULL, docstring,
|
||||||
&tcatch_cmdlist);
|
&tcatch_cmdlist);
|
||||||
set_cmd_sfunc (command, sfunc);
|
set_cmd_sfunc (command, sfunc);
|
||||||
set_cmd_context (command, user_data_tcatch);
|
set_cmd_context (command, user_data_tcatch);
|
||||||
|
set_cmd_completer (command, completer);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
@ -9190,36 +9650,53 @@ Set temporary catchpoints to catch events."),
|
|||||||
Catch an exception, when caught.\n\
|
Catch an exception, when caught.\n\
|
||||||
With an argument, catch only exceptions with the given name."),
|
With an argument, catch only exceptions with the given name."),
|
||||||
catch_catch_command,
|
catch_catch_command,
|
||||||
|
NULL,
|
||||||
CATCH_PERMANENT,
|
CATCH_PERMANENT,
|
||||||
CATCH_TEMPORARY);
|
CATCH_TEMPORARY);
|
||||||
add_catch_command ("throw", _("\
|
add_catch_command ("throw", _("\
|
||||||
Catch an exception, when thrown.\n\
|
Catch an exception, when thrown.\n\
|
||||||
With an argument, catch only exceptions with the given name."),
|
With an argument, catch only exceptions with the given name."),
|
||||||
catch_throw_command,
|
catch_throw_command,
|
||||||
|
NULL,
|
||||||
CATCH_PERMANENT,
|
CATCH_PERMANENT,
|
||||||
CATCH_TEMPORARY);
|
CATCH_TEMPORARY);
|
||||||
add_catch_command ("fork", _("Catch calls to fork."),
|
add_catch_command ("fork", _("Catch calls to fork."),
|
||||||
catch_fork_command_1,
|
catch_fork_command_1,
|
||||||
|
NULL,
|
||||||
(void *) (uintptr_t) catch_fork_permanent,
|
(void *) (uintptr_t) catch_fork_permanent,
|
||||||
(void *) (uintptr_t) catch_fork_temporary);
|
(void *) (uintptr_t) catch_fork_temporary);
|
||||||
add_catch_command ("vfork", _("Catch calls to vfork."),
|
add_catch_command ("vfork", _("Catch calls to vfork."),
|
||||||
catch_fork_command_1,
|
catch_fork_command_1,
|
||||||
|
NULL,
|
||||||
(void *) (uintptr_t) catch_vfork_permanent,
|
(void *) (uintptr_t) catch_vfork_permanent,
|
||||||
(void *) (uintptr_t) catch_vfork_temporary);
|
(void *) (uintptr_t) catch_vfork_temporary);
|
||||||
add_catch_command ("exec", _("Catch calls to exec."),
|
add_catch_command ("exec", _("Catch calls to exec."),
|
||||||
catch_exec_command_1,
|
catch_exec_command_1,
|
||||||
|
NULL,
|
||||||
|
CATCH_PERMANENT,
|
||||||
|
CATCH_TEMPORARY);
|
||||||
|
add_catch_command ("syscall", _("\
|
||||||
|
Catch system calls by their names and/or numbers.\n\
|
||||||
|
Arguments say which system calls to catch. If no arguments\n\
|
||||||
|
are given, every system call will be caught.\n\
|
||||||
|
Arguments, if given, should be one or more system call names\n\
|
||||||
|
(if your system supports that), or system call numbers."),
|
||||||
|
catch_syscall_command_1,
|
||||||
|
catch_syscall_completer,
|
||||||
CATCH_PERMANENT,
|
CATCH_PERMANENT,
|
||||||
CATCH_TEMPORARY);
|
CATCH_TEMPORARY);
|
||||||
add_catch_command ("exception", _("\
|
add_catch_command ("exception", _("\
|
||||||
Catch Ada exceptions, when raised.\n\
|
Catch Ada exceptions, when raised.\n\
|
||||||
With an argument, catch only exceptions with the given name."),
|
With an argument, catch only exceptions with the given name."),
|
||||||
catch_ada_exception_command,
|
catch_ada_exception_command,
|
||||||
|
NULL,
|
||||||
CATCH_PERMANENT,
|
CATCH_PERMANENT,
|
||||||
CATCH_TEMPORARY);
|
CATCH_TEMPORARY);
|
||||||
add_catch_command ("assert", _("\
|
add_catch_command ("assert", _("\
|
||||||
Catch failed Ada assertions, when raised.\n\
|
Catch failed Ada assertions, when raised.\n\
|
||||||
With an argument, catch only exceptions with the given name."),
|
With an argument, catch only exceptions with the given name."),
|
||||||
catch_assert_command,
|
catch_assert_command,
|
||||||
|
NULL,
|
||||||
CATCH_PERMANENT,
|
CATCH_PERMANENT,
|
||||||
CATCH_TEMPORARY);
|
CATCH_TEMPORARY);
|
||||||
|
|
||||||
|
@ -33,7 +33,8 @@ struct block;
|
|||||||
|
|
||||||
#define BREAKPOINT_MAX 16
|
#define BREAKPOINT_MAX 16
|
||||||
|
|
||||||
/* Type of breakpoint. */
|
|
||||||
|
/* Type of breakpoint. */
|
||||||
/* FIXME In the future, we should fold all other breakpoint-like things into
|
/* FIXME In the future, we should fold all other breakpoint-like things into
|
||||||
here. This includes:
|
here. This includes:
|
||||||
|
|
||||||
@ -359,6 +360,9 @@ enum watchpoint_triggered
|
|||||||
watch_triggered_yes
|
watch_triggered_yes
|
||||||
};
|
};
|
||||||
|
|
||||||
|
/* This is used to declare the VEC syscalls_to_be_caught. */
|
||||||
|
DEF_VEC_I(int);
|
||||||
|
|
||||||
typedef struct bp_location *bp_location_p;
|
typedef struct bp_location *bp_location_p;
|
||||||
DEF_VEC_P(bp_location_p);
|
DEF_VEC_P(bp_location_p);
|
||||||
|
|
||||||
@ -469,6 +473,12 @@ struct breakpoint
|
|||||||
triggered. */
|
triggered. */
|
||||||
char *exec_pathname;
|
char *exec_pathname;
|
||||||
|
|
||||||
|
/* Syscall numbers used for the 'catch syscall' feature.
|
||||||
|
If no syscall has been specified for filtering, its value is NULL.
|
||||||
|
Otherwise, it holds a list of all syscalls to be caught.
|
||||||
|
The list elements are allocated with xmalloc. */
|
||||||
|
VEC(int) *syscalls_to_be_caught;
|
||||||
|
|
||||||
/* Methods associated with this breakpoint. */
|
/* Methods associated with this breakpoint. */
|
||||||
struct breakpoint_ops *ops;
|
struct breakpoint_ops *ops;
|
||||||
|
|
||||||
@ -924,6 +934,15 @@ extern int breakpoints_always_inserted_mode (void);
|
|||||||
in our opinion won't ever trigger. */
|
in our opinion won't ever trigger. */
|
||||||
extern void breakpoint_retire_moribund (void);
|
extern void breakpoint_retire_moribund (void);
|
||||||
|
|
||||||
|
/* Checks if we are catching syscalls or not.
|
||||||
|
Returns 0 if not, greater than 0 if we are. */
|
||||||
|
extern int catch_syscall_enabled (void);
|
||||||
|
|
||||||
|
/* Checks if we are catching syscalls with the specific
|
||||||
|
syscall_number. Used for "filtering" the catchpoints.
|
||||||
|
Returns 0 if not, greater than 0 if we are. */
|
||||||
|
extern int catching_syscall_number (int syscall_number);
|
||||||
|
|
||||||
/* Tell a breakpoint to be quiet. */
|
/* Tell a breakpoint to be quiet. */
|
||||||
extern void make_breakpoint_silent (struct breakpoint *);
|
extern void make_breakpoint_silent (struct breakpoint *);
|
||||||
|
|
||||||
|
@ -1,3 +1,8 @@
|
|||||||
|
2009-09-14 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
|
||||||
|
|
||||||
|
* gdb.texinfo (Set Catchpoints): Documentation about the catch syscall
|
||||||
|
feature.
|
||||||
|
|
||||||
2009-09-13 Daniel Jacobowitz <dan@codesourcery.com>
|
2009-09-13 Daniel Jacobowitz <dan@codesourcery.com>
|
||||||
|
|
||||||
* gdbint.texinfo (Unwinding the Frame ID): Reference outer_frame_id.
|
* gdbint.texinfo (Unwinding the Frame ID): Reference outer_frame_id.
|
||||||
|
@ -3685,6 +3685,137 @@ A failed Ada assertion.
|
|||||||
A call to @code{exec}. This is currently only available for HP-UX
|
A call to @code{exec}. This is currently only available for HP-UX
|
||||||
and @sc{gnu}/Linux.
|
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
|
@item fork
|
||||||
A call to @code{fork}. This is currently only available for HP-UX
|
A call to @code{fork}. This is currently only available for HP-UX
|
||||||
and @sc{gnu}/Linux.
|
and @sc{gnu}/Linux.
|
||||||
|
@ -244,6 +244,7 @@ struct gdbarch
|
|||||||
gdbarch_target_signal_to_host_ftype *target_signal_to_host;
|
gdbarch_target_signal_to_host_ftype *target_signal_to_host;
|
||||||
gdbarch_get_siginfo_type_ftype *get_siginfo_type;
|
gdbarch_get_siginfo_type_ftype *get_siginfo_type;
|
||||||
gdbarch_record_special_symbol_ftype *record_special_symbol;
|
gdbarch_record_special_symbol_ftype *record_special_symbol;
|
||||||
|
gdbarch_get_syscall_number_ftype *get_syscall_number;
|
||||||
int has_global_solist;
|
int has_global_solist;
|
||||||
int has_global_breakpoints;
|
int has_global_breakpoints;
|
||||||
};
|
};
|
||||||
@ -381,6 +382,7 @@ struct gdbarch startup_gdbarch =
|
|||||||
default_target_signal_to_host, /* target_signal_to_host */
|
default_target_signal_to_host, /* target_signal_to_host */
|
||||||
0, /* get_siginfo_type */
|
0, /* get_siginfo_type */
|
||||||
0, /* record_special_symbol */
|
0, /* record_special_symbol */
|
||||||
|
0, /* get_syscall_number */
|
||||||
0, /* has_global_solist */
|
0, /* has_global_solist */
|
||||||
0, /* has_global_breakpoints */
|
0, /* has_global_breakpoints */
|
||||||
/* startup_gdbarch() */
|
/* startup_gdbarch() */
|
||||||
@ -637,6 +639,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
|
|||||||
/* Skip verify of target_signal_to_host, invalid_p == 0 */
|
/* Skip verify of target_signal_to_host, invalid_p == 0 */
|
||||||
/* Skip verify of get_siginfo_type, has predicate */
|
/* Skip verify of get_siginfo_type, has predicate */
|
||||||
/* Skip verify of record_special_symbol, has predicate */
|
/* Skip verify of record_special_symbol, has predicate */
|
||||||
|
/* Skip verify of get_syscall_number, has predicate */
|
||||||
/* Skip verify of has_global_solist, invalid_p == 0 */
|
/* Skip verify of has_global_solist, invalid_p == 0 */
|
||||||
/* Skip verify of has_global_breakpoints, invalid_p == 0 */
|
/* Skip verify of has_global_breakpoints, invalid_p == 0 */
|
||||||
buf = ui_file_xstrdup (log, &length);
|
buf = ui_file_xstrdup (log, &length);
|
||||||
@ -865,6 +868,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
|
|||||||
fprintf_unfiltered (file,
|
fprintf_unfiltered (file,
|
||||||
"gdbarch_dump: get_siginfo_type = <%s>\n",
|
"gdbarch_dump: get_siginfo_type = <%s>\n",
|
||||||
host_address_to_string (gdbarch->get_siginfo_type));
|
host_address_to_string (gdbarch->get_siginfo_type));
|
||||||
|
fprintf_unfiltered (file,
|
||||||
|
"gdbarch_dump: gdbarch_get_syscall_number_p() = %d\n",
|
||||||
|
gdbarch_get_syscall_number_p (gdbarch));
|
||||||
|
fprintf_unfiltered (file,
|
||||||
|
"gdbarch_dump: get_syscall_number = <%s>\n",
|
||||||
|
host_address_to_string (gdbarch->get_syscall_number));
|
||||||
fprintf_unfiltered (file,
|
fprintf_unfiltered (file,
|
||||||
"gdbarch_dump: has_global_breakpoints = %s\n",
|
"gdbarch_dump: has_global_breakpoints = %s\n",
|
||||||
plongest (gdbarch->has_global_breakpoints));
|
plongest (gdbarch->has_global_breakpoints));
|
||||||
@ -3380,6 +3389,30 @@ set_gdbarch_record_special_symbol (struct gdbarch *gdbarch,
|
|||||||
gdbarch->record_special_symbol = record_special_symbol;
|
gdbarch->record_special_symbol = record_special_symbol;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
gdbarch_get_syscall_number_p (struct gdbarch *gdbarch)
|
||||||
|
{
|
||||||
|
gdb_assert (gdbarch != NULL);
|
||||||
|
return gdbarch->get_syscall_number != NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
LONGEST
|
||||||
|
gdbarch_get_syscall_number (struct gdbarch *gdbarch, ptid_t ptid)
|
||||||
|
{
|
||||||
|
gdb_assert (gdbarch != NULL);
|
||||||
|
gdb_assert (gdbarch->get_syscall_number != NULL);
|
||||||
|
if (gdbarch_debug >= 2)
|
||||||
|
fprintf_unfiltered (gdb_stdlog, "gdbarch_get_syscall_number called\n");
|
||||||
|
return gdbarch->get_syscall_number (gdbarch, ptid);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
set_gdbarch_get_syscall_number (struct gdbarch *gdbarch,
|
||||||
|
gdbarch_get_syscall_number_ftype get_syscall_number)
|
||||||
|
{
|
||||||
|
gdbarch->get_syscall_number = get_syscall_number;
|
||||||
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
gdbarch_has_global_solist (struct gdbarch *gdbarch)
|
gdbarch_has_global_solist (struct gdbarch *gdbarch)
|
||||||
{
|
{
|
||||||
|
@ -52,6 +52,7 @@ struct bp_target_info;
|
|||||||
struct target_desc;
|
struct target_desc;
|
||||||
struct displaced_step_closure;
|
struct displaced_step_closure;
|
||||||
struct core_regset_section;
|
struct core_regset_section;
|
||||||
|
struct syscall;
|
||||||
|
|
||||||
/* The architecture associated with the connection to the target.
|
/* The architecture associated with the connection to the target.
|
||||||
|
|
||||||
@ -853,6 +854,15 @@ typedef void (gdbarch_record_special_symbol_ftype) (struct gdbarch *gdbarch, str
|
|||||||
extern void gdbarch_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile, asymbol *sym);
|
extern void gdbarch_record_special_symbol (struct gdbarch *gdbarch, struct objfile *objfile, asymbol *sym);
|
||||||
extern void set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, gdbarch_record_special_symbol_ftype *record_special_symbol);
|
extern void set_gdbarch_record_special_symbol (struct gdbarch *gdbarch, gdbarch_record_special_symbol_ftype *record_special_symbol);
|
||||||
|
|
||||||
|
/* Function for the 'catch syscall' feature.
|
||||||
|
Get architecture-specific system calls information from registers. */
|
||||||
|
|
||||||
|
extern int gdbarch_get_syscall_number_p (struct gdbarch *gdbarch);
|
||||||
|
|
||||||
|
typedef LONGEST (gdbarch_get_syscall_number_ftype) (struct gdbarch *gdbarch, ptid_t ptid);
|
||||||
|
extern LONGEST gdbarch_get_syscall_number (struct gdbarch *gdbarch, ptid_t ptid);
|
||||||
|
extern void set_gdbarch_get_syscall_number (struct gdbarch *gdbarch, gdbarch_get_syscall_number_ftype *get_syscall_number);
|
||||||
|
|
||||||
/* True if the list of shared libraries is one and only for all
|
/* True if the list of shared libraries is one and only for all
|
||||||
processes, as opposed to a list of shared libraries per inferior.
|
processes, as opposed to a list of shared libraries per inferior.
|
||||||
This usually means that all processes, although may or may not share
|
This usually means that all processes, although may or may not share
|
||||||
@ -870,6 +880,9 @@ extern void set_gdbarch_has_global_solist (struct gdbarch *gdbarch, int has_glob
|
|||||||
extern int gdbarch_has_global_breakpoints (struct gdbarch *gdbarch);
|
extern int gdbarch_has_global_breakpoints (struct gdbarch *gdbarch);
|
||||||
extern void set_gdbarch_has_global_breakpoints (struct gdbarch *gdbarch, int has_global_breakpoints);
|
extern void set_gdbarch_has_global_breakpoints (struct gdbarch *gdbarch, int has_global_breakpoints);
|
||||||
|
|
||||||
|
/* Definition for an unknown syscall, used basically in error-cases. */
|
||||||
|
#define UNKNOWN_SYSCALL (-1)
|
||||||
|
|
||||||
extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
|
extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
|
||||||
|
|
||||||
|
|
||||||
|
@ -724,6 +724,11 @@ M:struct type *:get_siginfo_type:void:
|
|||||||
# Record architecture-specific information from the symbol table.
|
# Record architecture-specific information from the symbol table.
|
||||||
M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym
|
M:void:record_special_symbol:struct objfile *objfile, asymbol *sym:objfile, sym
|
||||||
|
|
||||||
|
# Function for the 'catch syscall' feature.
|
||||||
|
|
||||||
|
# Get architecture-specific system calls information from registers.
|
||||||
|
M:LONGEST:get_syscall_number:ptid_t ptid:ptid
|
||||||
|
|
||||||
# True if the list of shared libraries is one and only for all
|
# True if the list of shared libraries is one and only for all
|
||||||
# processes, as opposed to a list of shared libraries per inferior.
|
# processes, as opposed to a list of shared libraries per inferior.
|
||||||
# This usually means that all processes, although may or may not share
|
# This usually means that all processes, although may or may not share
|
||||||
@ -848,6 +853,7 @@ struct bp_target_info;
|
|||||||
struct target_desc;
|
struct target_desc;
|
||||||
struct displaced_step_closure;
|
struct displaced_step_closure;
|
||||||
struct core_regset_section;
|
struct core_regset_section;
|
||||||
|
struct syscall;
|
||||||
|
|
||||||
/* The architecture associated with the connection to the target.
|
/* The architecture associated with the connection to the target.
|
||||||
|
|
||||||
@ -926,6 +932,9 @@ done
|
|||||||
# close it off
|
# close it off
|
||||||
cat <<EOF
|
cat <<EOF
|
||||||
|
|
||||||
|
/* Definition for an unknown syscall, used basically in error-cases. */
|
||||||
|
#define UNKNOWN_SYSCALL (-1)
|
||||||
|
|
||||||
extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
|
extern struct gdbarch_tdep *gdbarch_tdep (struct gdbarch *gdbarch);
|
||||||
|
|
||||||
|
|
||||||
|
@ -752,7 +752,12 @@ i386_linux_resume (struct target_ops *ops,
|
|||||||
{
|
{
|
||||||
int pid = PIDGET (ptid);
|
int pid = PIDGET (ptid);
|
||||||
|
|
||||||
int request = PTRACE_CONT;
|
int request;
|
||||||
|
|
||||||
|
if (catch_syscall_enabled () > 0)
|
||||||
|
request = PTRACE_SYSCALL;
|
||||||
|
else
|
||||||
|
request = PTRACE_CONT;
|
||||||
|
|
||||||
if (step)
|
if (step)
|
||||||
{
|
{
|
||||||
|
@ -37,6 +37,10 @@
|
|||||||
#include "symtab.h"
|
#include "symtab.h"
|
||||||
#include "arch-utils.h"
|
#include "arch-utils.h"
|
||||||
#include "regset.h"
|
#include "regset.h"
|
||||||
|
#include "xml-syscall.h"
|
||||||
|
|
||||||
|
/* The syscall's XML filename for i386. */
|
||||||
|
#define XML_SYSCALL_FILENAME_I386 "syscalls/i386-linux.xml"
|
||||||
|
|
||||||
#include "record.h"
|
#include "record.h"
|
||||||
#include "linux-record.h"
|
#include "linux-record.h"
|
||||||
@ -411,6 +415,27 @@ i386_linux_intx80_sysenter_record (struct regcache *regcache)
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
static LONGEST
|
||||||
|
i386_linux_get_syscall_number (struct gdbarch *gdbarch,
|
||||||
|
ptid_t ptid)
|
||||||
|
{
|
||||||
|
struct regcache *regcache = get_thread_regcache (ptid);
|
||||||
|
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
||||||
|
/* The content of a register. */
|
||||||
|
gdb_byte buf[4];
|
||||||
|
/* The result. */
|
||||||
|
LONGEST ret;
|
||||||
|
|
||||||
|
/* Getting the system call number from the register.
|
||||||
|
When dealing with x86 architecture, this information
|
||||||
|
is stored at %eax register. */
|
||||||
|
regcache_cooked_read (regcache, I386_LINUX_ORIG_EAX_REGNUM, buf);
|
||||||
|
|
||||||
|
ret = extract_signed_integer (buf, 4, byte_order);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
/* The register sets used in GNU/Linux ELF core-dumps are identical to
|
/* The register sets used in GNU/Linux ELF core-dumps are identical to
|
||||||
the register sets in `struct user' that are used for a.out
|
the register sets in `struct user' that are used for a.out
|
||||||
core-dumps. These are also used by ptrace(2). The corresponding
|
core-dumps. These are also used by ptrace(2). The corresponding
|
||||||
@ -697,6 +722,11 @@ i386_linux_init_abi (struct gdbarch_info info, struct gdbarch *gdbarch)
|
|||||||
set_gdbarch_displaced_step_location (gdbarch,
|
set_gdbarch_displaced_step_location (gdbarch,
|
||||||
displaced_step_at_entry_point);
|
displaced_step_at_entry_point);
|
||||||
|
|
||||||
|
/* Functions for 'catch syscall'. */
|
||||||
|
set_xml_syscall_file_name (XML_SYSCALL_FILENAME_I386);
|
||||||
|
set_gdbarch_get_syscall_number (gdbarch,
|
||||||
|
i386_linux_get_syscall_number);
|
||||||
|
|
||||||
set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
|
set_gdbarch_get_siginfo_type (gdbarch, linux_get_siginfo_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -147,6 +147,15 @@ inf_child_remove_exec_catchpoint (int pid)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
inf_child_set_syscall_catchpoint (int pid, int needed, int any_count,
|
||||||
|
int table_size, int *table)
|
||||||
|
{
|
||||||
|
/* This version of Unix doesn't support notification of syscall
|
||||||
|
events. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
inf_child_can_run (void)
|
inf_child_can_run (void)
|
||||||
{
|
{
|
||||||
@ -190,6 +199,7 @@ inf_child_target (void)
|
|||||||
t->to_follow_fork = inf_child_follow_fork;
|
t->to_follow_fork = inf_child_follow_fork;
|
||||||
t->to_insert_exec_catchpoint = inf_child_insert_exec_catchpoint;
|
t->to_insert_exec_catchpoint = inf_child_insert_exec_catchpoint;
|
||||||
t->to_remove_exec_catchpoint = inf_child_remove_exec_catchpoint;
|
t->to_remove_exec_catchpoint = inf_child_remove_exec_catchpoint;
|
||||||
|
t->to_set_syscall_catchpoint = inf_child_set_syscall_catchpoint;
|
||||||
t->to_can_run = inf_child_can_run;
|
t->to_can_run = inf_child_can_run;
|
||||||
t->to_pid_to_exec_file = inf_child_pid_to_exec_file;
|
t->to_pid_to_exec_file = inf_child_pid_to_exec_file;
|
||||||
t->to_stratum = process_stratum;
|
t->to_stratum = process_stratum;
|
||||||
|
@ -332,13 +332,18 @@ inf_ptrace_resume (struct target_ops *ops,
|
|||||||
ptid_t ptid, int step, enum target_signal signal)
|
ptid_t ptid, int step, enum target_signal signal)
|
||||||
{
|
{
|
||||||
pid_t pid = ptid_get_pid (ptid);
|
pid_t pid = ptid_get_pid (ptid);
|
||||||
int request = PT_CONTINUE;
|
int request;
|
||||||
|
|
||||||
if (pid == -1)
|
if (pid == -1)
|
||||||
/* Resume all threads. Traditionally ptrace() only supports
|
/* Resume all threads. Traditionally ptrace() only supports
|
||||||
single-threaded processes, so simply resume the inferior. */
|
single-threaded processes, so simply resume the inferior. */
|
||||||
pid = ptid_get_pid (inferior_ptid);
|
pid = ptid_get_pid (inferior_ptid);
|
||||||
|
|
||||||
|
if (catch_syscall_enabled () > 0)
|
||||||
|
request = PT_SYSCALL;
|
||||||
|
else
|
||||||
|
request = PT_CONTINUE;
|
||||||
|
|
||||||
if (step)
|
if (step)
|
||||||
{
|
{
|
||||||
/* If this system does not support PT_STEP, a higher level
|
/* If this system does not support PT_STEP, a higher level
|
||||||
|
@ -425,6 +425,20 @@ struct inferior
|
|||||||
|
|
||||||
/* Private data used by the target vector implementation. */
|
/* Private data used by the target vector implementation. */
|
||||||
struct private_inferior *private;
|
struct private_inferior *private;
|
||||||
|
|
||||||
|
/* We keep a count of the number of times the user has requested a
|
||||||
|
particular syscall to be tracked, and pass this information to the
|
||||||
|
target. This lets capable targets implement filtering directly. */
|
||||||
|
|
||||||
|
/* Number of times that "any" syscall is requested. */
|
||||||
|
int any_syscall_count;
|
||||||
|
|
||||||
|
/* Count of each system call. */
|
||||||
|
VEC(int) *syscalls_counts;
|
||||||
|
|
||||||
|
/* This counts all syscall catch requests, so we can readily determine
|
||||||
|
if any catching is necessary. */
|
||||||
|
int total_syscalls_count;
|
||||||
};
|
};
|
||||||
|
|
||||||
/* Create an empty inferior list, or empty the existing one. */
|
/* Create an empty inferior list, or empty the existing one. */
|
||||||
|
88
gdb/infrun.c
88
gdb/infrun.c
@ -2042,6 +2042,10 @@ wait_for_inferior (int treat_exec_as_sigtrap)
|
|||||||
state. */
|
state. */
|
||||||
old_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
|
old_chain = make_cleanup (finish_thread_state_cleanup, &minus_one_ptid);
|
||||||
|
|
||||||
|
if (ecs->ws.kind == TARGET_WAITKIND_SYSCALL_ENTRY
|
||||||
|
|| ecs->ws.kind == TARGET_WAITKIND_SYSCALL_RETURN)
|
||||||
|
ecs->ws.value.syscall_number = UNKNOWN_SYSCALL;
|
||||||
|
|
||||||
/* Now figure out what to do with the result of the result. */
|
/* Now figure out what to do with the result of the result. */
|
||||||
handle_inferior_event (ecs);
|
handle_inferior_event (ecs);
|
||||||
|
|
||||||
@ -2378,6 +2382,56 @@ stepped_in_from (struct frame_info *frame, struct frame_id step_frame_id)
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Auxiliary function that handles syscall entry/return events.
|
||||||
|
It returns 1 if the inferior should keep going (and GDB
|
||||||
|
should ignore the event), or 0 if the event deserves to be
|
||||||
|
processed. */
|
||||||
|
static int
|
||||||
|
deal_with_syscall_event (struct execution_control_state *ecs)
|
||||||
|
{
|
||||||
|
struct regcache *regcache = get_thread_regcache (ecs->ptid);
|
||||||
|
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||||||
|
int syscall_number = gdbarch_get_syscall_number (gdbarch,
|
||||||
|
ecs->ptid);
|
||||||
|
target_last_waitstatus.value.syscall_number = syscall_number;
|
||||||
|
|
||||||
|
if (catch_syscall_enabled () > 0
|
||||||
|
&& catching_syscall_number (syscall_number) > 0)
|
||||||
|
{
|
||||||
|
if (debug_infrun)
|
||||||
|
fprintf_unfiltered (gdb_stdlog, "infrun: syscall number = '%d'\n",
|
||||||
|
syscall_number);
|
||||||
|
ecs->event_thread->stop_signal = TARGET_SIGNAL_TRAP;
|
||||||
|
|
||||||
|
if (!ptid_equal (ecs->ptid, inferior_ptid))
|
||||||
|
{
|
||||||
|
context_switch (ecs->ptid);
|
||||||
|
reinit_frame_cache ();
|
||||||
|
}
|
||||||
|
|
||||||
|
stop_pc = regcache_read_pc (get_thread_regcache (ecs->ptid));
|
||||||
|
|
||||||
|
ecs->event_thread->stop_bpstat = bpstat_stop_status (stop_pc, ecs->ptid);
|
||||||
|
|
||||||
|
ecs->random_signal = !bpstat_explains_signal (ecs->event_thread->stop_bpstat);
|
||||||
|
|
||||||
|
/* If no catchpoint triggered for this, then keep going. */
|
||||||
|
if (ecs->random_signal)
|
||||||
|
{
|
||||||
|
ecs->event_thread->stop_signal = TARGET_SIGNAL_0;
|
||||||
|
keep_going (ecs);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
resume (0, TARGET_SIGNAL_0);
|
||||||
|
prepare_to_wait (ecs);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/* Given an execution control state that has been freshly filled in
|
/* Given an execution control state that has been freshly filled in
|
||||||
by an event from the inferior, figure out what it means and take
|
by an event from the inferior, figure out what it means and take
|
||||||
appropriate action. */
|
appropriate action. */
|
||||||
@ -2698,9 +2752,11 @@ handle_inferior_event (struct execution_control_state *ecs)
|
|||||||
case TARGET_WAITKIND_SYSCALL_ENTRY:
|
case TARGET_WAITKIND_SYSCALL_ENTRY:
|
||||||
if (debug_infrun)
|
if (debug_infrun)
|
||||||
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_ENTRY\n");
|
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_ENTRY\n");
|
||||||
resume (0, TARGET_SIGNAL_0);
|
/* Getting the current syscall number */
|
||||||
prepare_to_wait (ecs);
|
if (deal_with_syscall_event (ecs) != 0)
|
||||||
return;
|
return;
|
||||||
|
goto process_event_stop_test;
|
||||||
|
break;
|
||||||
|
|
||||||
/* Before examining the threads further, step this thread to
|
/* Before examining the threads further, step this thread to
|
||||||
get it entirely out of the syscall. (We get notice of the
|
get it entirely out of the syscall. (We get notice of the
|
||||||
@ -2710,9 +2766,10 @@ handle_inferior_event (struct execution_control_state *ecs)
|
|||||||
case TARGET_WAITKIND_SYSCALL_RETURN:
|
case TARGET_WAITKIND_SYSCALL_RETURN:
|
||||||
if (debug_infrun)
|
if (debug_infrun)
|
||||||
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_RETURN\n");
|
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_RETURN\n");
|
||||||
target_resume (ecs->ptid, 1, TARGET_SIGNAL_0);
|
if (deal_with_syscall_event (ecs) != 0)
|
||||||
prepare_to_wait (ecs);
|
return;
|
||||||
return;
|
goto process_event_stop_test;
|
||||||
|
break;
|
||||||
|
|
||||||
case TARGET_WAITKIND_STOPPED:
|
case TARGET_WAITKIND_STOPPED:
|
||||||
if (debug_infrun)
|
if (debug_infrun)
|
||||||
@ -5626,6 +5683,25 @@ inferior_has_execd (ptid_t pid, char **execd_pathname)
|
|||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
inferior_has_called_syscall (ptid_t pid, int *syscall_number)
|
||||||
|
{
|
||||||
|
struct target_waitstatus last;
|
||||||
|
ptid_t last_ptid;
|
||||||
|
|
||||||
|
get_last_target_status (&last_ptid, &last);
|
||||||
|
|
||||||
|
if (last.kind != TARGET_WAITKIND_SYSCALL_ENTRY &&
|
||||||
|
last.kind != TARGET_WAITKIND_SYSCALL_RETURN)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
if (!ptid_equal (last_ptid, pid))
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
*syscall_number = last.value.syscall_number;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
/* Oft used ptids */
|
/* Oft used ptids */
|
||||||
ptid_t null_ptid;
|
ptid_t null_ptid;
|
||||||
ptid_t minus_one_ptid;
|
ptid_t minus_one_ptid;
|
||||||
|
144
gdb/linux-nat.c
144
gdb/linux-nat.c
@ -67,6 +67,10 @@
|
|||||||
# endif
|
# endif
|
||||||
#endif /* HAVE_PERSONALITY */
|
#endif /* HAVE_PERSONALITY */
|
||||||
|
|
||||||
|
/* To be used when one needs to know wether a
|
||||||
|
WSTOPSIG (status) is a syscall */
|
||||||
|
#define TRAP_IS_SYSCALL (SIGTRAP | 0x80)
|
||||||
|
|
||||||
/* This comment documents high-level logic of this file.
|
/* This comment documents high-level logic of this file.
|
||||||
|
|
||||||
Waiting for events in sync mode
|
Waiting for events in sync mode
|
||||||
@ -279,6 +283,11 @@ struct simple_pid_list *stopped_pids;
|
|||||||
|
|
||||||
static int linux_supports_tracefork_flag = -1;
|
static int linux_supports_tracefork_flag = -1;
|
||||||
|
|
||||||
|
/* This variable is a tri-state flag: -1 for unknown, 0 if PTRACE_O_TRACESYSGOOD
|
||||||
|
can not be used, 1 if it can. */
|
||||||
|
|
||||||
|
static int linux_supports_tracesysgood_flag = -1;
|
||||||
|
|
||||||
/* If we have PTRACE_O_TRACEFORK, this flag indicates whether we also have
|
/* If we have PTRACE_O_TRACEFORK, this flag indicates whether we also have
|
||||||
PTRACE_O_TRACEVFORKDONE. */
|
PTRACE_O_TRACEVFORKDONE. */
|
||||||
|
|
||||||
@ -290,6 +299,9 @@ static int linux_supports_tracevforkdone_flag = -1;
|
|||||||
linux_nat_wait should behave as if async mode was off. */
|
linux_nat_wait should behave as if async mode was off. */
|
||||||
static int linux_nat_async_mask_value = 1;
|
static int linux_nat_async_mask_value = 1;
|
||||||
|
|
||||||
|
/* Stores the current used ptrace() options. */
|
||||||
|
static int current_ptrace_options = 0;
|
||||||
|
|
||||||
/* The read/write ends of the pipe registered as waitable file in the
|
/* The read/write ends of the pipe registered as waitable file in the
|
||||||
event loop. */
|
event loop. */
|
||||||
static int linux_nat_event_pipe[2] = { -1, -1 };
|
static int linux_nat_event_pipe[2] = { -1, -1 };
|
||||||
@ -525,6 +537,43 @@ linux_test_for_tracefork (int original_pid)
|
|||||||
restore_child_signals_mask (&prev_mask);
|
restore_child_signals_mask (&prev_mask);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Determine if PTRACE_O_TRACESYSGOOD can be used to follow syscalls.
|
||||||
|
|
||||||
|
We try to enable syscall tracing on ORIGINAL_PID. If this fails,
|
||||||
|
we know that the feature is not available. This may change the tracing
|
||||||
|
options for ORIGINAL_PID, but we'll be setting them shortly anyway. */
|
||||||
|
|
||||||
|
static void
|
||||||
|
linux_test_for_tracesysgood (int original_pid)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
sigset_t prev_mask;
|
||||||
|
|
||||||
|
/* We don't want those ptrace calls to be interrupted. */
|
||||||
|
block_child_signals (&prev_mask);
|
||||||
|
|
||||||
|
linux_supports_tracesysgood_flag = 0;
|
||||||
|
|
||||||
|
ret = ptrace (PTRACE_SETOPTIONS, original_pid, 0, PTRACE_O_TRACESYSGOOD);
|
||||||
|
if (ret != 0)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
linux_supports_tracesysgood_flag = 1;
|
||||||
|
out:
|
||||||
|
restore_child_signals_mask (&prev_mask);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Determine wether we support PTRACE_O_TRACESYSGOOD option available.
|
||||||
|
This function also sets linux_supports_tracesysgood_flag. */
|
||||||
|
|
||||||
|
static int
|
||||||
|
linux_supports_tracesysgood (int pid)
|
||||||
|
{
|
||||||
|
if (linux_supports_tracesysgood_flag == -1)
|
||||||
|
linux_test_for_tracesysgood (pid);
|
||||||
|
return linux_supports_tracesysgood_flag;
|
||||||
|
}
|
||||||
|
|
||||||
/* Return non-zero iff we have tracefork functionality available.
|
/* Return non-zero iff we have tracefork functionality available.
|
||||||
This function also sets linux_supports_tracefork_flag. */
|
This function also sets linux_supports_tracefork_flag. */
|
||||||
|
|
||||||
@ -544,12 +593,27 @@ linux_supports_tracevforkdone (int pid)
|
|||||||
return linux_supports_tracevforkdone_flag;
|
return linux_supports_tracevforkdone_flag;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
linux_enable_tracesysgood (ptid_t ptid)
|
||||||
|
{
|
||||||
|
int pid = ptid_get_lwp (ptid);
|
||||||
|
|
||||||
|
if (pid == 0)
|
||||||
|
pid = ptid_get_pid (ptid);
|
||||||
|
|
||||||
|
if (linux_supports_tracesysgood (pid) == 0)
|
||||||
|
return;
|
||||||
|
|
||||||
|
current_ptrace_options |= PTRACE_O_TRACESYSGOOD;
|
||||||
|
|
||||||
|
ptrace (PTRACE_SETOPTIONS, pid, 0, current_ptrace_options);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
void
|
void
|
||||||
linux_enable_event_reporting (ptid_t ptid)
|
linux_enable_event_reporting (ptid_t ptid)
|
||||||
{
|
{
|
||||||
int pid = ptid_get_lwp (ptid);
|
int pid = ptid_get_lwp (ptid);
|
||||||
int options;
|
|
||||||
|
|
||||||
if (pid == 0)
|
if (pid == 0)
|
||||||
pid = ptid_get_pid (ptid);
|
pid = ptid_get_pid (ptid);
|
||||||
@ -557,15 +621,16 @@ linux_enable_event_reporting (ptid_t ptid)
|
|||||||
if (! linux_supports_tracefork (pid))
|
if (! linux_supports_tracefork (pid))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXEC
|
current_ptrace_options |= PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK
|
||||||
| PTRACE_O_TRACECLONE;
|
| PTRACE_O_TRACEEXEC | PTRACE_O_TRACECLONE;
|
||||||
|
|
||||||
if (linux_supports_tracevforkdone (pid))
|
if (linux_supports_tracevforkdone (pid))
|
||||||
options |= PTRACE_O_TRACEVFORKDONE;
|
current_ptrace_options |= PTRACE_O_TRACEVFORKDONE;
|
||||||
|
|
||||||
/* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to support
|
/* Do not enable PTRACE_O_TRACEEXIT until GDB is more prepared to support
|
||||||
read-only process state. */
|
read-only process state. */
|
||||||
|
|
||||||
ptrace (PTRACE_SETOPTIONS, pid, 0, options);
|
ptrace (PTRACE_SETOPTIONS, pid, 0, current_ptrace_options);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -573,6 +638,7 @@ linux_child_post_attach (int pid)
|
|||||||
{
|
{
|
||||||
linux_enable_event_reporting (pid_to_ptid (pid));
|
linux_enable_event_reporting (pid_to_ptid (pid));
|
||||||
check_for_thread_db ();
|
check_for_thread_db ();
|
||||||
|
linux_enable_tracesysgood (pid_to_ptid (pid));
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
@ -580,6 +646,7 @@ linux_child_post_startup_inferior (ptid_t ptid)
|
|||||||
{
|
{
|
||||||
linux_enable_event_reporting (ptid);
|
linux_enable_event_reporting (ptid);
|
||||||
check_for_thread_db ();
|
check_for_thread_db ();
|
||||||
|
linux_enable_tracesysgood (ptid);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int
|
static int
|
||||||
@ -810,6 +877,20 @@ linux_child_insert_exec_catchpoint (int pid)
|
|||||||
error (_("Your system does not support exec catchpoints."));
|
error (_("Your system does not support exec catchpoints."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
linux_child_set_syscall_catchpoint (int pid, int needed, int any_count,
|
||||||
|
int table_size, int *table)
|
||||||
|
{
|
||||||
|
if (! linux_supports_tracesysgood (pid))
|
||||||
|
error (_("Your system does not support syscall catchpoints."));
|
||||||
|
/* On GNU/Linux, we ignore the arguments. It means that we only
|
||||||
|
enable the syscall catchpoints, but do not disable them.
|
||||||
|
|
||||||
|
Also, we do not use the `table' information because we do not
|
||||||
|
filter system calls here. We let GDB do the logic for us. */
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
/* On GNU/Linux there are no real LWP's. The closest thing to LWP's
|
/* On GNU/Linux there are no real LWP's. The closest thing to LWP's
|
||||||
are processes sharing the same VM space. A multi-threaded process
|
are processes sharing the same VM space. A multi-threaded process
|
||||||
is basically a group of such processes. However, such a grouping
|
is basically a group of such processes. However, such a grouping
|
||||||
@ -1982,6 +2063,47 @@ linux_handle_extended_wait (struct lwp_info *lp, int status,
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Used for 'catch syscall' feature. */
|
||||||
|
if (WSTOPSIG (status) == TRAP_IS_SYSCALL)
|
||||||
|
{
|
||||||
|
if (catch_syscall_enabled () == 0)
|
||||||
|
ourstatus->kind = TARGET_WAITKIND_IGNORE;
|
||||||
|
else
|
||||||
|
{
|
||||||
|
struct regcache *regcache = get_thread_regcache (lp->ptid);
|
||||||
|
struct gdbarch *gdbarch = get_regcache_arch (regcache);
|
||||||
|
|
||||||
|
ourstatus->value.syscall_number =
|
||||||
|
(int) gdbarch_get_syscall_number (gdbarch, lp->ptid);
|
||||||
|
|
||||||
|
/* If we are catching this specific syscall number, then we
|
||||||
|
should update the target_status to reflect which event
|
||||||
|
has occurred. But if this syscall is not to be caught,
|
||||||
|
then we can safely mark the event as a SYSCALL_RETURN.
|
||||||
|
|
||||||
|
This is particularly needed if:
|
||||||
|
|
||||||
|
- We are catching any syscalls, or
|
||||||
|
- We are catching the syscall "exit"
|
||||||
|
|
||||||
|
In this case, as the syscall "exit" *doesn't* return,
|
||||||
|
then GDB would be confused because it would mark the last
|
||||||
|
syscall event as a SYSCALL_ENTRY. After that, if we re-ran the
|
||||||
|
inferior GDB will think that the first syscall event is
|
||||||
|
the opposite of a SYSCALL_ENTRY, which is the SYSCALL_RETURN.
|
||||||
|
Therefore, GDB would report inverted syscall events. */
|
||||||
|
if (catching_syscall_number (ourstatus->value.syscall_number))
|
||||||
|
ourstatus->kind =
|
||||||
|
(lp->syscall_state == TARGET_WAITKIND_SYSCALL_ENTRY) ?
|
||||||
|
TARGET_WAITKIND_SYSCALL_RETURN : TARGET_WAITKIND_SYSCALL_ENTRY;
|
||||||
|
else
|
||||||
|
ourstatus->kind = TARGET_WAITKIND_SYSCALL_RETURN;
|
||||||
|
|
||||||
|
lp->syscall_state = ourstatus->kind;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
internal_error (__FILE__, __LINE__,
|
internal_error (__FILE__, __LINE__,
|
||||||
_("unknown ptrace event %d"), event);
|
_("unknown ptrace event %d"), event);
|
||||||
}
|
}
|
||||||
@ -2580,11 +2702,16 @@ linux_nat_filter_event (int lwpid, int status, int options)
|
|||||||
}
|
}
|
||||||
|
|
||||||
/* Save the trap's siginfo in case we need it later. */
|
/* Save the trap's siginfo in case we need it later. */
|
||||||
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
|
if (WIFSTOPPED (status)
|
||||||
|
&& (WSTOPSIG (status) == SIGTRAP || WSTOPSIG (status) == TRAP_IS_SYSCALL))
|
||||||
save_siginfo (lp);
|
save_siginfo (lp);
|
||||||
|
|
||||||
/* Handle GNU/Linux's extended waitstatus for trace events. */
|
/* Handle GNU/Linux's extended waitstatus for trace events.
|
||||||
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
|
It is necessary to check if WSTOPSIG is signaling that
|
||||||
|
the inferior is entering/exiting a system call. */
|
||||||
|
if (WIFSTOPPED (status)
|
||||||
|
&& ((WSTOPSIG (status) == TRAP_IS_SYSCALL)
|
||||||
|
|| (WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)))
|
||||||
{
|
{
|
||||||
if (debug_linux_nat)
|
if (debug_linux_nat)
|
||||||
fprintf_unfiltered (gdb_stdlog,
|
fprintf_unfiltered (gdb_stdlog,
|
||||||
@ -4510,6 +4637,7 @@ linux_target_install_ops (struct target_ops *t)
|
|||||||
t->to_insert_fork_catchpoint = linux_child_insert_fork_catchpoint;
|
t->to_insert_fork_catchpoint = linux_child_insert_fork_catchpoint;
|
||||||
t->to_insert_vfork_catchpoint = linux_child_insert_vfork_catchpoint;
|
t->to_insert_vfork_catchpoint = linux_child_insert_vfork_catchpoint;
|
||||||
t->to_insert_exec_catchpoint = linux_child_insert_exec_catchpoint;
|
t->to_insert_exec_catchpoint = linux_child_insert_exec_catchpoint;
|
||||||
|
t->to_set_syscall_catchpoint = linux_child_set_syscall_catchpoint;
|
||||||
t->to_pid_to_exec_file = linux_child_pid_to_exec_file;
|
t->to_pid_to_exec_file = linux_child_pid_to_exec_file;
|
||||||
t->to_post_startup_inferior = linux_child_post_startup_inferior;
|
t->to_post_startup_inferior = linux_child_post_startup_inferior;
|
||||||
t->to_post_attach = linux_child_post_attach;
|
t->to_post_attach = linux_child_post_attach;
|
||||||
|
@ -70,6 +70,13 @@ struct lwp_info
|
|||||||
or to a local variable in lin_lwp_wait. */
|
or to a local variable in lin_lwp_wait. */
|
||||||
struct target_waitstatus waitstatus;
|
struct target_waitstatus waitstatus;
|
||||||
|
|
||||||
|
/* Signal wether we are in a SYSCALL_ENTRY or
|
||||||
|
in a SYSCALL_RETURN event.
|
||||||
|
Values:
|
||||||
|
- TARGET_WAITKIND_SYSCALL_ENTRY
|
||||||
|
- TARGET_WAITKIND_SYSCALL_RETURN */
|
||||||
|
int syscall_state;
|
||||||
|
|
||||||
/* Next LWP in list. */
|
/* Next LWP in list. */
|
||||||
struct lwp_info *next;
|
struct lwp_info *next;
|
||||||
};
|
};
|
||||||
|
@ -47,6 +47,7 @@
|
|||||||
#include "exceptions.h"
|
#include "exceptions.h"
|
||||||
#include "arch-utils.h"
|
#include "arch-utils.h"
|
||||||
#include "spu-tdep.h"
|
#include "spu-tdep.h"
|
||||||
|
#include "xml-syscall.h"
|
||||||
|
|
||||||
#include "features/rs6000/powerpc-32l.c"
|
#include "features/rs6000/powerpc-32l.c"
|
||||||
#include "features/rs6000/powerpc-altivec32l.c"
|
#include "features/rs6000/powerpc-altivec32l.c"
|
||||||
@ -64,6 +65,9 @@
|
|||||||
#include "features/rs6000/powerpc-isa205-vsx64l.c"
|
#include "features/rs6000/powerpc-isa205-vsx64l.c"
|
||||||
#include "features/rs6000/powerpc-e500l.c"
|
#include "features/rs6000/powerpc-e500l.c"
|
||||||
|
|
||||||
|
/* The syscall's XML filename for PPC and PPC64. */
|
||||||
|
#define XML_SYSCALL_FILENAME_PPC "syscalls/ppc-linux.xml"
|
||||||
|
#define XML_SYSCALL_FILENAME_PPC64 "syscalls/ppc64-linux.xml"
|
||||||
|
|
||||||
/* ppc_linux_memory_remove_breakpoints attempts to remove a breakpoint
|
/* ppc_linux_memory_remove_breakpoints attempts to remove a breakpoint
|
||||||
in much the same fashion as memory_remove_breakpoint in mem-break.c,
|
in much the same fashion as memory_remove_breakpoint in mem-break.c,
|
||||||
@ -1066,6 +1070,39 @@ ppc_linux_trap_reg_p (struct gdbarch *gdbarch)
|
|||||||
&& register_size (gdbarch, PPC_TRAP_REGNUM) > 0;
|
&& register_size (gdbarch, PPC_TRAP_REGNUM) > 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* Return the current system call's number present in the
|
||||||
|
r0 register. When the function fails, it returns -1. */
|
||||||
|
static LONGEST
|
||||||
|
ppc_linux_get_syscall_number (struct gdbarch *gdbarch,
|
||||||
|
ptid_t ptid)
|
||||||
|
{
|
||||||
|
struct regcache *regcache = get_thread_regcache (ptid);
|
||||||
|
struct gdbarch_tdep *tdep = gdbarch_tdep (gdbarch);
|
||||||
|
enum bfd_endian byte_order = gdbarch_byte_order (gdbarch);
|
||||||
|
struct cleanup *cleanbuf;
|
||||||
|
/* The content of a register */
|
||||||
|
gdb_byte *buf;
|
||||||
|
/* The result */
|
||||||
|
LONGEST ret;
|
||||||
|
|
||||||
|
/* Make sure we're in a 32- or 64-bit machine */
|
||||||
|
gdb_assert (tdep->wordsize == 4 || tdep->wordsize == 8);
|
||||||
|
|
||||||
|
buf = (gdb_byte *) xmalloc (tdep->wordsize * sizeof (gdb_byte));
|
||||||
|
|
||||||
|
cleanbuf = make_cleanup (xfree, buf);
|
||||||
|
|
||||||
|
/* Getting the system call number from the register.
|
||||||
|
When dealing with PowerPC architecture, this information
|
||||||
|
is stored at 0th register. */
|
||||||
|
regcache_cooked_read (regcache, tdep->ppc_gp0_regnum, buf);
|
||||||
|
|
||||||
|
ret = extract_signed_integer (buf, tdep->wordsize, byte_order);
|
||||||
|
do_cleanups (cleanbuf);
|
||||||
|
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
ppc_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
|
ppc_linux_write_pc (struct regcache *regcache, CORE_ADDR pc)
|
||||||
{
|
{
|
||||||
@ -1435,6 +1472,9 @@ ppc_linux_init_abi (struct gdbarch_info info,
|
|||||||
/* Handle inferior calls during interrupted system calls. */
|
/* Handle inferior calls during interrupted system calls. */
|
||||||
set_gdbarch_write_pc (gdbarch, ppc_linux_write_pc);
|
set_gdbarch_write_pc (gdbarch, ppc_linux_write_pc);
|
||||||
|
|
||||||
|
/* Get the syscall number from the arch's register. */
|
||||||
|
set_gdbarch_get_syscall_number (gdbarch, ppc_linux_get_syscall_number);
|
||||||
|
|
||||||
if (tdep->wordsize == 4)
|
if (tdep->wordsize == 4)
|
||||||
{
|
{
|
||||||
/* Until November 2001, gcc did not comply with the 32 bit SysV
|
/* Until November 2001, gcc did not comply with the 32 bit SysV
|
||||||
@ -1454,6 +1494,9 @@ ppc_linux_init_abi (struct gdbarch_info info,
|
|||||||
set_solib_svr4_fetch_link_map_offsets
|
set_solib_svr4_fetch_link_map_offsets
|
||||||
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
|
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
|
||||||
|
|
||||||
|
/* Setting the correct XML syscall filename. */
|
||||||
|
set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC);
|
||||||
|
|
||||||
/* Trampolines. */
|
/* Trampolines. */
|
||||||
tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sigaction_tramp_frame);
|
tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sigaction_tramp_frame);
|
||||||
tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sighandler_tramp_frame);
|
tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sighandler_tramp_frame);
|
||||||
@ -1477,6 +1520,9 @@ ppc_linux_init_abi (struct gdbarch_info info,
|
|||||||
set_solib_svr4_fetch_link_map_offsets
|
set_solib_svr4_fetch_link_map_offsets
|
||||||
(gdbarch, svr4_lp64_fetch_link_map_offsets);
|
(gdbarch, svr4_lp64_fetch_link_map_offsets);
|
||||||
|
|
||||||
|
/* Setting the correct XML syscall filename. */
|
||||||
|
set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC64);
|
||||||
|
|
||||||
/* Trampolines. */
|
/* Trampolines. */
|
||||||
tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sigaction_tramp_frame);
|
tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sigaction_tramp_frame);
|
||||||
tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sighandler_tramp_frame);
|
tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sighandler_tramp_frame);
|
||||||
|
@ -647,6 +647,7 @@ update_current_target (void)
|
|||||||
/* Do not inherit to_follow_fork. */
|
/* Do not inherit to_follow_fork. */
|
||||||
INHERIT (to_insert_exec_catchpoint, t);
|
INHERIT (to_insert_exec_catchpoint, t);
|
||||||
INHERIT (to_remove_exec_catchpoint, t);
|
INHERIT (to_remove_exec_catchpoint, t);
|
||||||
|
INHERIT (to_set_syscall_catchpoint, t);
|
||||||
INHERIT (to_has_exited, t);
|
INHERIT (to_has_exited, t);
|
||||||
/* Do not inherit to_mourn_inferiour. */
|
/* Do not inherit to_mourn_inferiour. */
|
||||||
INHERIT (to_can_run, t);
|
INHERIT (to_can_run, t);
|
||||||
@ -789,6 +790,9 @@ update_current_target (void)
|
|||||||
de_fault (to_remove_exec_catchpoint,
|
de_fault (to_remove_exec_catchpoint,
|
||||||
(int (*) (int))
|
(int (*) (int))
|
||||||
tcomplain);
|
tcomplain);
|
||||||
|
de_fault (to_set_syscall_catchpoint,
|
||||||
|
(int (*) (int, int, int, int, int *))
|
||||||
|
tcomplain);
|
||||||
de_fault (to_has_exited,
|
de_fault (to_has_exited,
|
||||||
(int (*) (int, int, int *))
|
(int (*) (int, int, int *))
|
||||||
return_zero);
|
return_zero);
|
||||||
@ -2866,9 +2870,9 @@ target_waitstatus_to_string (const struct target_waitstatus *ws)
|
|||||||
case TARGET_WAITKIND_EXECD:
|
case TARGET_WAITKIND_EXECD:
|
||||||
return xstrprintf ("%sexecd", kind_str);
|
return xstrprintf ("%sexecd", kind_str);
|
||||||
case TARGET_WAITKIND_SYSCALL_ENTRY:
|
case TARGET_WAITKIND_SYSCALL_ENTRY:
|
||||||
return xstrprintf ("%ssyscall-entry", kind_str);
|
return xstrprintf ("%sentered syscall", kind_str);
|
||||||
case TARGET_WAITKIND_SYSCALL_RETURN:
|
case TARGET_WAITKIND_SYSCALL_RETURN:
|
||||||
return xstrprintf ("%ssyscall-return", kind_str);
|
return xstrprintf ("%sexited syscall", kind_str);
|
||||||
case TARGET_WAITKIND_SPURIOUS:
|
case TARGET_WAITKIND_SPURIOUS:
|
||||||
return xstrprintf ("%sspurious", kind_str);
|
return xstrprintf ("%sspurious", kind_str);
|
||||||
case TARGET_WAITKIND_IGNORE:
|
case TARGET_WAITKIND_IGNORE:
|
||||||
|
44
gdb/target.h
44
gdb/target.h
@ -142,14 +142,15 @@ struct target_waitstatus
|
|||||||
{
|
{
|
||||||
enum target_waitkind kind;
|
enum target_waitkind kind;
|
||||||
|
|
||||||
/* Forked child pid, execd pathname, exit status or signal number. */
|
/* Forked child pid, execd pathname, exit status, signal number or
|
||||||
|
syscall number. */
|
||||||
union
|
union
|
||||||
{
|
{
|
||||||
int integer;
|
int integer;
|
||||||
enum target_signal sig;
|
enum target_signal sig;
|
||||||
ptid_t related_pid;
|
ptid_t related_pid;
|
||||||
char *execd_pathname;
|
char *execd_pathname;
|
||||||
int syscall_id;
|
int syscall_number;
|
||||||
}
|
}
|
||||||
value;
|
value;
|
||||||
};
|
};
|
||||||
@ -161,6 +162,21 @@ struct target_waitstatus
|
|||||||
event. */
|
event. */
|
||||||
#define TARGET_WNOHANG 1
|
#define TARGET_WNOHANG 1
|
||||||
|
|
||||||
|
/* The structure below stores information about a system call.
|
||||||
|
It is basically used in the "catch syscall" command, and in
|
||||||
|
every function that gives information about a system call.
|
||||||
|
|
||||||
|
It's also good to mention that its fields represent everything
|
||||||
|
that we currently know about a syscall in GDB. */
|
||||||
|
struct syscall
|
||||||
|
{
|
||||||
|
/* The syscall number. */
|
||||||
|
int number;
|
||||||
|
|
||||||
|
/* The syscall name. */
|
||||||
|
const char *name;
|
||||||
|
};
|
||||||
|
|
||||||
/* Return a pretty printed form of target_waitstatus.
|
/* Return a pretty printed form of target_waitstatus.
|
||||||
Space for the result is malloc'd, caller must free. */
|
Space for the result is malloc'd, caller must free. */
|
||||||
extern char *target_waitstatus_to_string (const struct target_waitstatus *);
|
extern char *target_waitstatus_to_string (const struct target_waitstatus *);
|
||||||
@ -406,6 +422,7 @@ struct target_ops
|
|||||||
int (*to_follow_fork) (struct target_ops *, int);
|
int (*to_follow_fork) (struct target_ops *, int);
|
||||||
void (*to_insert_exec_catchpoint) (int);
|
void (*to_insert_exec_catchpoint) (int);
|
||||||
int (*to_remove_exec_catchpoint) (int);
|
int (*to_remove_exec_catchpoint) (int);
|
||||||
|
int (*to_set_syscall_catchpoint) (int, int, int, int, int *);
|
||||||
int (*to_has_exited) (int, int, int *);
|
int (*to_has_exited) (int, int, int *);
|
||||||
void (*to_mourn_inferior) (struct target_ops *);
|
void (*to_mourn_inferior) (struct target_ops *);
|
||||||
int (*to_can_run) (void);
|
int (*to_can_run) (void);
|
||||||
@ -748,6 +765,8 @@ extern int inferior_has_vforked (ptid_t pid, ptid_t *child_pid);
|
|||||||
|
|
||||||
extern int inferior_has_execd (ptid_t pid, char **execd_pathname);
|
extern int inferior_has_execd (ptid_t pid, char **execd_pathname);
|
||||||
|
|
||||||
|
extern int inferior_has_called_syscall (ptid_t pid, int *syscall_number);
|
||||||
|
|
||||||
/* Print a line about the current target. */
|
/* Print a line about the current target. */
|
||||||
|
|
||||||
#define target_files_info() \
|
#define target_files_info() \
|
||||||
@ -900,6 +919,27 @@ int target_follow_fork (int follow_child);
|
|||||||
#define target_remove_exec_catchpoint(pid) \
|
#define target_remove_exec_catchpoint(pid) \
|
||||||
(*current_target.to_remove_exec_catchpoint) (pid)
|
(*current_target.to_remove_exec_catchpoint) (pid)
|
||||||
|
|
||||||
|
/* Syscall catch.
|
||||||
|
|
||||||
|
NEEDED is nonzero if any syscall catch (of any kind) is requested.
|
||||||
|
If NEEDED is zero, it means the target can disable the mechanism to
|
||||||
|
catch system calls because there are no more catchpoints of this type.
|
||||||
|
|
||||||
|
ANY_COUNT is nonzero if a generic (filter-less) syscall catch is
|
||||||
|
being requested. In this case, both TABLE_SIZE and TABLE should
|
||||||
|
be ignored.
|
||||||
|
|
||||||
|
TABLE_SIZE is the number of elements in TABLE. It only matters if
|
||||||
|
ANY_COUNT is zero.
|
||||||
|
|
||||||
|
TABLE is an array of ints, indexed by syscall number. An element in
|
||||||
|
this array is nonzero if that syscall should be caught. This argument
|
||||||
|
only matters if ANY_COUNT is zero. */
|
||||||
|
|
||||||
|
#define target_set_syscall_catchpoint(pid, needed, any_count, table_size, table) \
|
||||||
|
(*current_target.to_set_syscall_catchpoint) (pid, needed, any_count, \
|
||||||
|
table_size, table)
|
||||||
|
|
||||||
/* Returns TRUE if PID has exited. And, also sets EXIT_STATUS to the
|
/* Returns TRUE if PID has exited. And, also sets EXIT_STATUS to the
|
||||||
exit code of PID, if any. */
|
exit code of PID, if any. */
|
||||||
|
|
||||||
|
@ -1,3 +1,9 @@
|
|||||||
|
2009-09-14 Sergio Durigan Junior <sergiodj@linux.vnet.ibm.com>
|
||||||
|
|
||||||
|
* Makefile.in: Inclusion of catch-syscall object.
|
||||||
|
* gdb.base/catch-syscall.c: New file.
|
||||||
|
* gdb.base/catch-syscall.exp: New file.
|
||||||
|
|
||||||
2009-09-12 Michael Snyder <msnyder@vmware.com>
|
2009-09-12 Michael Snyder <msnyder@vmware.com>
|
||||||
|
|
||||||
* gdb.reverse/step-reverse.exp: Explicitly check for targets
|
* gdb.reverse/step-reverse.exp: Explicitly check for targets
|
||||||
|
@ -12,7 +12,7 @@ EXECUTABLES = all-types annota1 bitfields break \
|
|||||||
scope section_command setshow setvar shmain sigall signals \
|
scope section_command setshow setvar shmain sigall signals \
|
||||||
solib solib_sl so-impl-ld so-indr-cl \
|
solib solib_sl so-impl-ld so-indr-cl \
|
||||||
step-line step-test structs structs2 \
|
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 \
|
MISCELLANEOUS = coremmap.data ../foobar.baz \
|
||||||
shr1.sl shr2.sl solib_sl.sl solib1.sl solib2.sl
|
shr1.sl shr2.sl solib_sl.sl solib1.sl solib2.sl
|
||||||
|
@ -1036,6 +1036,66 @@ obstack_xml_printf (struct obstack *obstack, const char *format, ...)
|
|||||||
va_end (ap);
|
va_end (ap);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
char *
|
||||||
|
xml_fetch_content_from_file (const char *filename, void *baton)
|
||||||
|
{
|
||||||
|
const char *dirname = baton;
|
||||||
|
FILE *file;
|
||||||
|
struct cleanup *back_to;
|
||||||
|
char *text;
|
||||||
|
size_t len, offset;
|
||||||
|
|
||||||
|
if (dirname && *dirname)
|
||||||
|
{
|
||||||
|
char *fullname = concat (dirname, "/", filename, (char *) NULL);
|
||||||
|
if (fullname == NULL)
|
||||||
|
nomem (0);
|
||||||
|
file = fopen (fullname, FOPEN_RT);
|
||||||
|
xfree (fullname);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
file = fopen (filename, FOPEN_RT);
|
||||||
|
|
||||||
|
if (file == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
back_to = make_cleanup_fclose (file);
|
||||||
|
|
||||||
|
/* Read in the whole file, one chunk at a time. */
|
||||||
|
len = 4096;
|
||||||
|
offset = 0;
|
||||||
|
text = xmalloc (len);
|
||||||
|
make_cleanup (free_current_contents, &text);
|
||||||
|
while (1)
|
||||||
|
{
|
||||||
|
size_t bytes_read;
|
||||||
|
|
||||||
|
/* Continue reading where the last read left off. Leave at least
|
||||||
|
one byte so that we can NUL-terminate the result. */
|
||||||
|
bytes_read = fread (text + offset, 1, len - offset - 1, file);
|
||||||
|
if (ferror (file))
|
||||||
|
{
|
||||||
|
warning (_("Read error from \"%s\""), filename);
|
||||||
|
do_cleanups (back_to);
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
offset += bytes_read;
|
||||||
|
|
||||||
|
if (feof (file))
|
||||||
|
break;
|
||||||
|
|
||||||
|
len = len * 2;
|
||||||
|
text = xrealloc (text, len);
|
||||||
|
}
|
||||||
|
|
||||||
|
fclose (file);
|
||||||
|
discard_cleanups (back_to);
|
||||||
|
|
||||||
|
text[offset] = '\0';
|
||||||
|
return text;
|
||||||
|
}
|
||||||
|
|
||||||
void _initialize_xml_support (void);
|
void _initialize_xml_support (void);
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -240,4 +240,10 @@ extern void obstack_xml_printf (struct obstack *obstack,
|
|||||||
const char *format, ...)
|
const char *format, ...)
|
||||||
ATTRIBUTE_PRINTF_2;
|
ATTRIBUTE_PRINTF_2;
|
||||||
|
|
||||||
|
/* Open FILENAME, read all its text into memory, close it, and return
|
||||||
|
the text. If something goes wrong, return NULL and warn. */
|
||||||
|
|
||||||
|
extern char *xml_fetch_content_from_file (const char *filename,
|
||||||
|
void *baton);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
@ -426,69 +426,6 @@ tdesc_parse_xml (const char *document, xml_fetch_another fetcher,
|
|||||||
#endif /* HAVE_LIBEXPAT */
|
#endif /* HAVE_LIBEXPAT */
|
||||||
|
|
||||||
|
|
||||||
/* Open FILENAME, read all its text into memory, close it, and return
|
|
||||||
the text. If something goes wrong, return NULL and warn. */
|
|
||||||
|
|
||||||
static char *
|
|
||||||
fetch_xml_from_file (const char *filename, void *baton)
|
|
||||||
{
|
|
||||||
const char *dirname = baton;
|
|
||||||
FILE *file;
|
|
||||||
struct cleanup *back_to;
|
|
||||||
char *text;
|
|
||||||
size_t len, offset;
|
|
||||||
|
|
||||||
if (dirname && *dirname)
|
|
||||||
{
|
|
||||||
char *fullname = concat (dirname, "/", filename, (char *) NULL);
|
|
||||||
if (fullname == NULL)
|
|
||||||
nomem (0);
|
|
||||||
file = fopen (fullname, FOPEN_RT);
|
|
||||||
xfree (fullname);
|
|
||||||
}
|
|
||||||
else
|
|
||||||
file = fopen (filename, FOPEN_RT);
|
|
||||||
|
|
||||||
if (file == NULL)
|
|
||||||
return NULL;
|
|
||||||
|
|
||||||
back_to = make_cleanup_fclose (file);
|
|
||||||
|
|
||||||
/* Read in the whole file, one chunk at a time. */
|
|
||||||
len = 4096;
|
|
||||||
offset = 0;
|
|
||||||
text = xmalloc (len);
|
|
||||||
make_cleanup (free_current_contents, &text);
|
|
||||||
while (1)
|
|
||||||
{
|
|
||||||
size_t bytes_read;
|
|
||||||
|
|
||||||
/* Continue reading where the last read left off. Leave at least
|
|
||||||
one byte so that we can NUL-terminate the result. */
|
|
||||||
bytes_read = fread (text + offset, 1, len - offset - 1, file);
|
|
||||||
if (ferror (file))
|
|
||||||
{
|
|
||||||
warning (_("Read error from \"%s\""), filename);
|
|
||||||
do_cleanups (back_to);
|
|
||||||
return NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
offset += bytes_read;
|
|
||||||
|
|
||||||
if (feof (file))
|
|
||||||
break;
|
|
||||||
|
|
||||||
len = len * 2;
|
|
||||||
text = xrealloc (text, len);
|
|
||||||
}
|
|
||||||
|
|
||||||
fclose (file);
|
|
||||||
discard_cleanups (back_to);
|
|
||||||
|
|
||||||
text[offset] = '\0';
|
|
||||||
return text;
|
|
||||||
}
|
|
||||||
|
|
||||||
/* Read an XML target description from FILENAME. Parse it, and return
|
/* Read an XML target description from FILENAME. Parse it, and return
|
||||||
the parsed description. */
|
the parsed description. */
|
||||||
|
|
||||||
@ -500,7 +437,7 @@ file_read_description_xml (const char *filename)
|
|||||||
struct cleanup *back_to;
|
struct cleanup *back_to;
|
||||||
char *dirname;
|
char *dirname;
|
||||||
|
|
||||||
tdesc_str = fetch_xml_from_file (filename, NULL);
|
tdesc_str = xml_fetch_content_from_file (filename, NULL);
|
||||||
if (tdesc_str == NULL)
|
if (tdesc_str == NULL)
|
||||||
{
|
{
|
||||||
warning (_("Could not open \"%s\""), filename);
|
warning (_("Could not open \"%s\""), filename);
|
||||||
@ -513,7 +450,7 @@ file_read_description_xml (const char *filename)
|
|||||||
if (dirname != NULL)
|
if (dirname != NULL)
|
||||||
make_cleanup (xfree, dirname);
|
make_cleanup (xfree, dirname);
|
||||||
|
|
||||||
tdesc = tdesc_parse_xml (tdesc_str, fetch_xml_from_file, dirname);
|
tdesc = tdesc_parse_xml (tdesc_str, xml_fetch_content_from_file, dirname);
|
||||||
do_cleanups (back_to);
|
do_cleanups (back_to);
|
||||||
|
|
||||||
return tdesc;
|
return tdesc;
|
||||||
|
Loading…
x
Reference in New Issue
Block a user