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:
Sergio Durigan Junior 2009-09-15 03:30:08 +00:00
parent 22fe6da0f9
commit a96d9b2e9a
27 changed files with 1358 additions and 99 deletions

View File

@ -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>
* target.c (memory_xfer_partial): Only update dcache after we know

View File

@ -166,6 +166,9 @@ INTL_CFLAGS = @INCINTL@
TARGET_SYSTEM_ROOT = @TARGET_SYSTEM_ROOT@
TARGET_SYSTEM_ROOT_DEFINE = @TARGET_SYSTEM_ROOT_DEFINE@
# Did the user give us a --with-gdb-datadir option?
GDB_DATADIR_PATH = @GDB_DATADIR_PATH@
# Helper code from gnulib.
LIBGNU = gnulib/libgnu.a
INCGNU = -I$(srcdir)/gnulib -Ignulib
@ -677,7 +680,8 @@ SFILES = ada-exp.y ada-lang.c ada-typeprint.c ada-valprint.c ada-tasks.c \
xml-tdesc.c xml-support.c \
inferior.c gdb_usleep.c \
record.c \
jit.c
jit.c \
xml-syscall.c \
LINTFILES = $(SFILES) $(YYFILES) $(CONFIG_SRCS) init.c
@ -746,7 +750,7 @@ config/rs6000/nm-rs6000.h top.h bsd-kvm.h gdb-stabs.h reggroups.h \
annotate.h sim-regno.h dictionary.h dfp.h main.h frame-unwind.h \
remote-fileio.h i386-linux-tdep.h vax-tdep.h objc-lang.h \
sentinel-frame.h bcache.h symfile.h windows-tdep.h linux-tdep.h \
gdb_usleep.h jit.h
gdb_usleep.h jit.h xml-syscall.h
# Header files that already have srcdir in them, or which are in objdir.
@ -826,11 +830,17 @@ COMMON_OBS = $(DEPFILES) $(CONFIG_OBS) $(YYOBJ) \
trad-frame.o \
tramp-frame.o \
solib.o solib-null.o \
prologue-value.o memory-map.o xml-support.o \
prologue-value.o memory-map.o xml-support.o xml-syscall.o \
target-descriptions.o target-memory.o xml-tdesc.o xml-builtin.o \
inferior.o osdata.o gdb_usleep.o record.o \
jit.o
# Definitions for the syscall's XML files and dir
XML_SYSCALLS_DIR = syscalls/
XML_SYSCALLS_FILES = gdb-syscalls.dtd \
ppc-linux.xml ppc64-linux.xml \
i386-linux.xml amd64-linux.xml
TSOBS = inflow.o
SUBDIRS = @subdirs@
@ -864,11 +874,41 @@ generated_files = config.h observer.h observer.inc ada-lex.c \
$(COMPILE) $<
$(POSTCOMPILE)
all: gdb$(EXEEXT) $(CONFIG_ALL)
all: gdb$(EXEEXT) $(CONFIG_ALL) xml-syscall-copy
@$(MAKE) $(FLAGS_TO_PASS) DO=all "DODIRS=`echo $(SUBDIRS) | sed 's/testsuite//'`" subdir_do
.PHONY: all-tui
all-tui: $(TUI)$(EXEEXT)
# This is needed for running GDB from the build directory
.PHONY: xml-syscall-copy
xml-syscall-copy:
if [ "`cd $(srcdir) && pwd`" != "`pwd`" ] ; then \
mkdir -p ./$(XML_SYSCALLS_DIR) ; \
list='$(XML_SYSCALLS_FILES)' ; \
for file in $$list ; do \
f=$(srcdir)/$(XML_SYSCALLS_DIR)/$$file ; \
if test -f $$f ; then \
$(INSTALL_DATA) $$f \
./$(XML_SYSCALLS_DIR) ; \
fi ; \
done ; \
fi ;
# This target is responsible for properly installing the syscalls'
# XML files in the system.
.PHONY: xml-syscall-install
xml-syscall-install:
$(SHELL) $(srcdir)/../mkinstalldirs \
$(DESTDIR)$(GDB_DATADIR_PATH)/$(XML_SYSCALLS_DIR) ; \
list='$(XML_SYSCALLS_FILES)' ; \
for file in $$list ; do \
f=$(srcdir)/$(XML_SYSCALLS_DIR)/$$file ; \
if test -f $$f ; then \
$(INSTALL_DATA) $$f \
$(DESTDIR)$(GDB_DATADIR_PATH)/$(XML_SYSCALLS_DIR) ; \
fi ; \
done ;
installcheck:
# The check target can not use subdir_do, because subdir_do does not
@ -925,8 +965,11 @@ gdb.z:gdb.1
# source file and doesn't care about rebuilding or just wants to save the
# time it takes for make to check that all is up to date.
# install-only is intended to address that need.
install: all install-only
install-only: $(CONFIG_INSTALL)
install: all install-only
# The "install-only" target also installs the syscalls' XML files in
# the system.
install-only: $(CONFIG_INSTALL) xml-syscall-install
transformed_name=`t='$(program_transform_name)'; \
echo gdb | sed -e "$$t"` ; \
if test "x$$transformed_name" = x; then \

View File

@ -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)
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,
val1 [, val2, ...]
Search memory for a sequence of bytes.

View File

@ -35,6 +35,10 @@
#include "amd64-tdep.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 "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>. */
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_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. */
set_gdbarch_fetch_tls_load_module_address (gdbarch,
svr4_fetch_objfile_link_map);

View File

@ -60,6 +60,7 @@
#include "wrapper.h"
#include "valprint.h"
#include "jit.h"
#include "xml-syscall.h"
/* readline include files */
#include "readline/readline.h"
@ -204,6 +205,8 @@ static int is_hardware_watchpoint (struct breakpoint *bpt);
static void insert_breakpoint_locations (void);
static int syscall_catchpoint_p (struct breakpoint *b);
static void tracepoints_info (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->forked_inferior_pid = null_ptid;
b->exec_pathname = NULL;
b->syscalls_to_be_caught = NULL;
b->ops = NULL;
b->condition_not_parsed = 0;
@ -4939,7 +4943,266 @@ static struct breakpoint_ops catch_vfork_breakpoint_ops =
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 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. */
static struct breakpoint *
create_catchpoint (struct gdbarch *gdbarch, int tempflag,
char *cond_string, struct breakpoint_ops *ops)
create_catchpoint_without_mention (struct gdbarch *gdbarch, int tempflag,
char *cond_string,
struct breakpoint_ops *ops)
{
struct symtab_and_line sal;
struct breakpoint *b;
init_sal (&sal);
sal.pc = 0;
sal.symtab = NULL;
sal.line = 0;
b = set_raw_breakpoint (gdbarch, sal, bp_catchpoint);
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->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);
update_global_location_list (1);
@ -5055,6 +5333,22 @@ static struct breakpoint_ops catch_exec_breakpoint_ops =
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
hw_breakpoint_used_count (void)
{
@ -7150,6 +7444,113 @@ catch_ada_exception_command (char *arg, int 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. */
static void
@ -7616,6 +8017,7 @@ delete_breakpoint (struct breakpoint *bpt)
xfree (bpt->source_file);
if (bpt->exec_pathname != NULL)
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. */
/* FIXME, how can we find all bpstat's?
@ -8552,6 +8954,60 @@ single_step_breakpoint_inserted_here_p (CORE_ADDR pc)
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. */
/* Set tracepoint count to NUM. */
@ -8903,6 +9359,8 @@ static void
add_catch_command (char *name, char *docstring,
void (*sfunc) (char *args, int from_tty,
struct cmd_list_element *command),
char **(*completer) (struct cmd_list_element *cmd,
char *text, char *word),
void *user_data_catch,
void *user_data_tcatch)
{
@ -8912,11 +9370,13 @@ add_catch_command (char *name, char *docstring,
&catch_cmdlist);
set_cmd_sfunc (command, sfunc);
set_cmd_context (command, user_data_catch);
set_cmd_completer (command, completer);
command = add_cmd (name, class_breakpoint, NULL, docstring,
&tcatch_cmdlist);
set_cmd_sfunc (command, sfunc);
set_cmd_context (command, user_data_tcatch);
set_cmd_completer (command, completer);
}
void
@ -9190,36 +9650,53 @@ Set temporary catchpoints to catch events."),
Catch an exception, when caught.\n\
With an argument, catch only exceptions with the given name."),
catch_catch_command,
NULL,
CATCH_PERMANENT,
CATCH_TEMPORARY);
add_catch_command ("throw", _("\
Catch an exception, when thrown.\n\
With an argument, catch only exceptions with the given name."),
catch_throw_command,
NULL,
CATCH_PERMANENT,
CATCH_TEMPORARY);
add_catch_command ("fork", _("Catch calls to fork."),
catch_fork_command_1,
NULL,
(void *) (uintptr_t) catch_fork_permanent,
(void *) (uintptr_t) catch_fork_temporary);
add_catch_command ("vfork", _("Catch calls to vfork."),
catch_fork_command_1,
NULL,
(void *) (uintptr_t) catch_vfork_permanent,
(void *) (uintptr_t) catch_vfork_temporary);
add_catch_command ("exec", _("Catch calls to exec."),
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_TEMPORARY);
add_catch_command ("exception", _("\
Catch Ada exceptions, when raised.\n\
With an argument, catch only exceptions with the given name."),
catch_ada_exception_command,
NULL,
CATCH_PERMANENT,
CATCH_TEMPORARY);
add_catch_command ("assert", _("\
Catch failed Ada assertions, when raised.\n\
With an argument, catch only exceptions with the given name."),
catch_assert_command,
NULL,
CATCH_PERMANENT,
CATCH_TEMPORARY);

View File

@ -33,7 +33,8 @@ struct block;
#define BREAKPOINT_MAX 16
/* Type of breakpoint. */
/* Type of breakpoint. */
/* FIXME In the future, we should fold all other breakpoint-like things into
here. This includes:
@ -359,6 +360,9 @@ enum watchpoint_triggered
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;
DEF_VEC_P(bp_location_p);
@ -469,6 +473,12 @@ struct breakpoint
triggered. */
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. */
struct breakpoint_ops *ops;
@ -924,6 +934,15 @@ extern int breakpoints_always_inserted_mode (void);
in our opinion won't ever trigger. */
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. */
extern void make_breakpoint_silent (struct breakpoint *);

View File

@ -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>
* gdbint.texinfo (Unwinding the Frame ID): Reference outer_frame_id.

View File

@ -3685,6 +3685,137 @@ A failed Ada assertion.
A call to @code{exec}. This is currently only available for HP-UX
and @sc{gnu}/Linux.
@item syscall
@itemx syscall @r{[}@var{name} @r{|} @var{number}@r{]} @r{...}
@cindex break on a system call.
A call to or return from a system call, a.k.a.@: @dfn{syscall}. A
syscall is a mechanism for application programs to request a service
from the operating system (OS) or one of the OS system services.
@value{GDBN} can catch some or all of the syscalls issued by the
debuggee, and show the related information for each syscall. If no
argument is specified, calls to and returns from all system calls
will be caught.
@var{name} can be any system call name that is valid for the
underlying OS. Just what syscalls are valid depends on the OS. On
GNU and Unix systems, you can find the full list of valid syscall
names on @file{/usr/include/asm/unistd.h}.
@c For MS-Windows, the syscall names and the corresponding numbers
@c can be found, e.g., on this URL:
@c http://www.metasploit.com/users/opcode/syscalls.html
@c but we don't support Windows syscalls yet.
Normally, @value{GDBN} knows in advance which syscalls are valid for
each OS, so you can use the @value{GDBN} command-line completion
facilities (@pxref{Completion,, command completion}) to list the
available choices.
You may also specify the system call numerically. A syscall's
number is the value passed to the OS's syscall dispatcher to
identify the requested service. When you specify the syscall by its
name, @value{GDBN} uses its database of syscalls to convert the name
into the corresponding numeric code, but using the number directly
may be useful if @value{GDBN}'s database does not have the complete
list of syscalls on your system (e.g., because @value{GDBN} lags
behind the OS upgrades).
The example below illustrates how this command works if you don't provide
arguments to it:
@smallexample
(@value{GDBP}) catch syscall
Catchpoint 1 (syscall)
(@value{GDBP}) r
Starting program: /tmp/catch-syscall
Catchpoint 1 (call to syscall 'close'), \
0xffffe424 in __kernel_vsyscall ()
(@value{GDBP}) c
Continuing.
Catchpoint 1 (returned from syscall 'close'), \
0xffffe424 in __kernel_vsyscall ()
(@value{GDBP})
@end smallexample
Here is an example of catching a system call by name:
@smallexample
(@value{GDBP}) catch syscall chroot
Catchpoint 1 (syscall 'chroot' [61])
(@value{GDBP}) r
Starting program: /tmp/catch-syscall
Catchpoint 1 (call to syscall 'chroot'), \
0xffffe424 in __kernel_vsyscall ()
(@value{GDBP}) c
Continuing.
Catchpoint 1 (returned from syscall 'chroot'), \
0xffffe424 in __kernel_vsyscall ()
(@value{GDBP})
@end smallexample
An example of specifying a system call numerically. In the case
below, the syscall number has a corresponding entry in the XML
file, so @value{GDBN} finds its name and prints it:
@smallexample
(@value{GDBP}) catch syscall 252
Catchpoint 1 (syscall(s) 'exit_group')
(@value{GDBP}) r
Starting program: /tmp/catch-syscall
Catchpoint 1 (call to syscall 'exit_group'), \
0xffffe424 in __kernel_vsyscall ()
(@value{GDBP}) c
Continuing.
Program exited normally.
(@value{GDBP})
@end smallexample
However, there can be situations when there is no corresponding name
in XML file for that syscall number. In this case, @value{GDBN} prints
a warning message saying that it was not able to find the syscall name,
but the catchpoint will be set anyway. See the example below:
@smallexample
(@value{GDBP}) catch syscall 764
warning: The number '764' does not represent a known syscall.
Catchpoint 2 (syscall 764)
(@value{GDBP})
@end smallexample
If you configure @value{GDBN} using the @samp{--without-expat} option,
it will not be able to display syscall names. Also, if your
architecture does not have an XML file describing its system calls,
you will not be able to see the syscall names. It is important to
notice that these two features are used for accessing the syscall
name database. In either case, you will see a warning like this:
@smallexample
(@value{GDBP}) catch syscall
warning: Could not open "syscalls/i386-linux.xml"
warning: Could not load the syscall XML file 'syscalls/i386-linux.xml'.
GDB will not be able to display syscall names.
Catchpoint 1 (syscall)
(@value{GDBP})
@end smallexample
Of course, the file name will change depending on your architecture and system.
Still using the example above, you can also try to catch a syscall by its
number. In this case, you would see something like:
@smallexample
(@value{GDBP}) catch syscall 252
Catchpoint 1 (syscall(s) 252)
@end smallexample
Again, in this case @value{GDBN} would not be able to display syscall's names.
@item fork
A call to @code{fork}. This is currently only available for HP-UX
and @sc{gnu}/Linux.

View File

@ -244,6 +244,7 @@ struct gdbarch
gdbarch_target_signal_to_host_ftype *target_signal_to_host;
gdbarch_get_siginfo_type_ftype *get_siginfo_type;
gdbarch_record_special_symbol_ftype *record_special_symbol;
gdbarch_get_syscall_number_ftype *get_syscall_number;
int has_global_solist;
int has_global_breakpoints;
};
@ -381,6 +382,7 @@ struct gdbarch startup_gdbarch =
default_target_signal_to_host, /* target_signal_to_host */
0, /* get_siginfo_type */
0, /* record_special_symbol */
0, /* get_syscall_number */
0, /* has_global_solist */
0, /* has_global_breakpoints */
/* startup_gdbarch() */
@ -637,6 +639,7 @@ verify_gdbarch (struct gdbarch *gdbarch)
/* Skip verify of target_signal_to_host, invalid_p == 0 */
/* Skip verify of get_siginfo_type, 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_breakpoints, invalid_p == 0 */
buf = ui_file_xstrdup (log, &length);
@ -865,6 +868,12 @@ gdbarch_dump (struct gdbarch *gdbarch, struct ui_file *file)
fprintf_unfiltered (file,
"gdbarch_dump: get_siginfo_type = <%s>\n",
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,
"gdbarch_dump: has_global_breakpoints = %s\n",
plongest (gdbarch->has_global_breakpoints));
@ -3380,6 +3389,30 @@ set_gdbarch_record_special_symbol (struct gdbarch *gdbarch,
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
gdbarch_has_global_solist (struct gdbarch *gdbarch)
{

View File

@ -52,6 +52,7 @@ struct bp_target_info;
struct target_desc;
struct displaced_step_closure;
struct core_regset_section;
struct syscall;
/* 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 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
processes, as opposed to a list of shared libraries per inferior.
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 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);

View File

@ -724,6 +724,11 @@ M:struct type *:get_siginfo_type:void:
# Record architecture-specific information from the symbol table.
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
# processes, as opposed to a list of shared libraries per inferior.
# This usually means that all processes, although may or may not share
@ -848,6 +853,7 @@ struct bp_target_info;
struct target_desc;
struct displaced_step_closure;
struct core_regset_section;
struct syscall;
/* The architecture associated with the connection to the target.
@ -926,6 +932,9 @@ done
# close it off
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);

View File

@ -752,7 +752,12 @@ i386_linux_resume (struct target_ops *ops,
{
int pid = PIDGET (ptid);
int request = PTRACE_CONT;
int request;
if (catch_syscall_enabled () > 0)
request = PTRACE_SYSCALL;
else
request = PTRACE_CONT;
if (step)
{

View File

@ -37,6 +37,10 @@
#include "symtab.h"
#include "arch-utils.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 "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 in `struct user' that are used for a.out
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,
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);
}

View File

@ -147,6 +147,15 @@ inf_child_remove_exec_catchpoint (int pid)
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
inf_child_can_run (void)
{
@ -190,6 +199,7 @@ inf_child_target (void)
t->to_follow_fork = inf_child_follow_fork;
t->to_insert_exec_catchpoint = inf_child_insert_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_pid_to_exec_file = inf_child_pid_to_exec_file;
t->to_stratum = process_stratum;

View File

@ -332,13 +332,18 @@ inf_ptrace_resume (struct target_ops *ops,
ptid_t ptid, int step, enum target_signal signal)
{
pid_t pid = ptid_get_pid (ptid);
int request = PT_CONTINUE;
int request;
if (pid == -1)
/* Resume all threads. Traditionally ptrace() only supports
single-threaded processes, so simply resume the inferior. */
pid = ptid_get_pid (inferior_ptid);
if (catch_syscall_enabled () > 0)
request = PT_SYSCALL;
else
request = PT_CONTINUE;
if (step)
{
/* If this system does not support PT_STEP, a higher level

View File

@ -425,6 +425,20 @@ struct inferior
/* Private data used by the target vector implementation. */
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. */

View File

@ -2042,6 +2042,10 @@ wait_for_inferior (int treat_exec_as_sigtrap)
state. */
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. */
handle_inferior_event (ecs);
@ -2378,6 +2382,56 @@ stepped_in_from (struct frame_info *frame, struct frame_id step_frame_id)
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
by an event from the inferior, figure out what it means and take
appropriate action. */
@ -2698,9 +2752,11 @@ handle_inferior_event (struct execution_control_state *ecs)
case TARGET_WAITKIND_SYSCALL_ENTRY:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_ENTRY\n");
resume (0, TARGET_SIGNAL_0);
prepare_to_wait (ecs);
return;
/* Getting the current syscall number */
if (deal_with_syscall_event (ecs) != 0)
return;
goto process_event_stop_test;
break;
/* Before examining the threads further, step this thread to
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:
if (debug_infrun)
fprintf_unfiltered (gdb_stdlog, "infrun: TARGET_WAITKIND_SYSCALL_RETURN\n");
target_resume (ecs->ptid, 1, TARGET_SIGNAL_0);
prepare_to_wait (ecs);
return;
if (deal_with_syscall_event (ecs) != 0)
return;
goto process_event_stop_test;
break;
case TARGET_WAITKIND_STOPPED:
if (debug_infrun)
@ -5626,6 +5683,25 @@ inferior_has_execd (ptid_t pid, char **execd_pathname)
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 */
ptid_t null_ptid;
ptid_t minus_one_ptid;

View File

@ -67,6 +67,10 @@
# endif
#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.
Waiting for events in sync mode
@ -279,6 +283,11 @@ struct simple_pid_list *stopped_pids;
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
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. */
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
event loop. */
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);
}
/* 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.
This function also sets linux_supports_tracefork_flag. */
@ -544,12 +593,27 @@ linux_supports_tracevforkdone (int pid)
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
linux_enable_event_reporting (ptid_t ptid)
{
int pid = ptid_get_lwp (ptid);
int options;
if (pid == 0)
pid = ptid_get_pid (ptid);
@ -557,15 +621,16 @@ linux_enable_event_reporting (ptid_t ptid)
if (! linux_supports_tracefork (pid))
return;
options = PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK | PTRACE_O_TRACEEXEC
| PTRACE_O_TRACECLONE;
current_ptrace_options |= PTRACE_O_TRACEFORK | PTRACE_O_TRACEVFORK
| PTRACE_O_TRACEEXEC | PTRACE_O_TRACECLONE;
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
read-only process state. */
ptrace (PTRACE_SETOPTIONS, pid, 0, options);
ptrace (PTRACE_SETOPTIONS, pid, 0, current_ptrace_options);
}
static void
@ -573,6 +638,7 @@ linux_child_post_attach (int pid)
{
linux_enable_event_reporting (pid_to_ptid (pid));
check_for_thread_db ();
linux_enable_tracesysgood (pid_to_ptid (pid));
}
static void
@ -580,6 +646,7 @@ linux_child_post_startup_inferior (ptid_t ptid)
{
linux_enable_event_reporting (ptid);
check_for_thread_db ();
linux_enable_tracesysgood (ptid);
}
static int
@ -810,6 +877,20 @@ linux_child_insert_exec_catchpoint (int pid)
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
are processes sharing the same VM space. A multi-threaded process
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;
}
/* 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__,
_("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. */
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP)
if (WIFSTOPPED (status)
&& (WSTOPSIG (status) == SIGTRAP || WSTOPSIG (status) == TRAP_IS_SYSCALL))
save_siginfo (lp);
/* Handle GNU/Linux's extended waitstatus for trace events. */
if (WIFSTOPPED (status) && WSTOPSIG (status) == SIGTRAP && status >> 16 != 0)
/* Handle GNU/Linux's extended waitstatus for trace events.
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)
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_vfork_catchpoint = linux_child_insert_vfork_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_post_startup_inferior = linux_child_post_startup_inferior;
t->to_post_attach = linux_child_post_attach;

View File

@ -70,6 +70,13 @@ struct lwp_info
or to a local variable in lin_lwp_wait. */
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. */
struct lwp_info *next;
};

View File

@ -47,6 +47,7 @@
#include "exceptions.h"
#include "arch-utils.h"
#include "spu-tdep.h"
#include "xml-syscall.h"
#include "features/rs6000/powerpc-32l.c"
#include "features/rs6000/powerpc-altivec32l.c"
@ -64,6 +65,9 @@
#include "features/rs6000/powerpc-isa205-vsx64l.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
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;
}
/* 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
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. */
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)
{
/* 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
(gdbarch, svr4_ilp32_fetch_link_map_offsets);
/* Setting the correct XML syscall filename. */
set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC);
/* Trampolines. */
tramp_frame_prepend_unwinder (gdbarch, &ppc32_linux_sigaction_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
(gdbarch, svr4_lp64_fetch_link_map_offsets);
/* Setting the correct XML syscall filename. */
set_xml_syscall_file_name (XML_SYSCALL_FILENAME_PPC64);
/* Trampolines. */
tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sigaction_tramp_frame);
tramp_frame_prepend_unwinder (gdbarch, &ppc64_linux_sighandler_tramp_frame);

View File

@ -647,6 +647,7 @@ update_current_target (void)
/* Do not inherit to_follow_fork. */
INHERIT (to_insert_exec_catchpoint, t);
INHERIT (to_remove_exec_catchpoint, t);
INHERIT (to_set_syscall_catchpoint, t);
INHERIT (to_has_exited, t);
/* Do not inherit to_mourn_inferiour. */
INHERIT (to_can_run, t);
@ -789,6 +790,9 @@ update_current_target (void)
de_fault (to_remove_exec_catchpoint,
(int (*) (int))
tcomplain);
de_fault (to_set_syscall_catchpoint,
(int (*) (int, int, int, int, int *))
tcomplain);
de_fault (to_has_exited,
(int (*) (int, int, int *))
return_zero);
@ -2866,9 +2870,9 @@ target_waitstatus_to_string (const struct target_waitstatus *ws)
case TARGET_WAITKIND_EXECD:
return xstrprintf ("%sexecd", kind_str);
case TARGET_WAITKIND_SYSCALL_ENTRY:
return xstrprintf ("%ssyscall-entry", kind_str);
return xstrprintf ("%sentered syscall", kind_str);
case TARGET_WAITKIND_SYSCALL_RETURN:
return xstrprintf ("%ssyscall-return", kind_str);
return xstrprintf ("%sexited syscall", kind_str);
case TARGET_WAITKIND_SPURIOUS:
return xstrprintf ("%sspurious", kind_str);
case TARGET_WAITKIND_IGNORE:

View File

@ -142,14 +142,15 @@ struct target_waitstatus
{
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
{
int integer;
enum target_signal sig;
ptid_t related_pid;
char *execd_pathname;
int syscall_id;
int syscall_number;
}
value;
};
@ -161,6 +162,21 @@ struct target_waitstatus
event. */
#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.
Space for the result is malloc'd, caller must free. */
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);
void (*to_insert_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 *);
void (*to_mourn_inferior) (struct target_ops *);
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_called_syscall (ptid_t pid, int *syscall_number);
/* Print a line about the current target. */
#define target_files_info() \
@ -900,6 +919,27 @@ int target_follow_fork (int follow_child);
#define target_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
exit code of PID, if any. */

View File

@ -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>
* gdb.reverse/step-reverse.exp: Explicitly check for targets

View File

@ -12,7 +12,7 @@ EXECUTABLES = all-types annota1 bitfields break \
scope section_command setshow setvar shmain sigall signals \
solib solib_sl so-impl-ld so-indr-cl \
step-line step-test structs structs2 \
twice-tmp varargs vforked-prog watchpoint whatis
twice-tmp varargs vforked-prog watchpoint whatis catch-syscall
MISCELLANEOUS = coremmap.data ../foobar.baz \
shr1.sl shr2.sl solib_sl.sl solib1.sl solib2.sl

View File

@ -1036,6 +1036,66 @@ obstack_xml_printf (struct obstack *obstack, const char *format, ...)
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

View File

@ -240,4 +240,10 @@ extern void obstack_xml_printf (struct obstack *obstack,
const char *format, ...)
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

View File

@ -426,69 +426,6 @@ tdesc_parse_xml (const char *document, xml_fetch_another fetcher,
#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
the parsed description. */
@ -500,7 +437,7 @@ file_read_description_xml (const char *filename)
struct cleanup *back_to;
char *dirname;
tdesc_str = fetch_xml_from_file (filename, NULL);
tdesc_str = xml_fetch_content_from_file (filename, NULL);
if (tdesc_str == NULL)
{
warning (_("Could not open \"%s\""), filename);
@ -513,7 +450,7 @@ file_read_description_xml (const char *filename)
if (dirname != NULL)
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);
return tdesc;