aboutsummaryrefslogtreecommitdiff
path: root/gdb/xml-syscall.c
diff options
context:
space:
mode:
authorGabriel Krisman Bertazi <gabriel@krisman.be>2016-07-23 18:38:24 -0300
committerGabriel Krisman Bertazi <gabriel@krisman.be>2016-07-23 18:38:24 -0300
commite34879080d8935792ef3942efa5f25b4c3169b5a (patch)
treedaab863d91a6bb66ab2c10f1f4ef50b52dab66ea /gdb/xml-syscall.c
parent49ecef2a7da2ee9df4ae675f99b70518fbf1bb23 (diff)
downloadgdb-e34879080d8935792ef3942efa5f25b4c3169b5a.zip
gdb-e34879080d8935792ef3942efa5f25b4c3169b5a.tar.gz
gdb-e34879080d8935792ef3942efa5f25b4c3169b5a.tar.bz2
Implement catch syscall group
Implement support to add catchpoints for a group of related syscalls using the syntax: (gdb) catch syscall group:<group> or (gdb) catch syscall g:<group> Several groups are predefined in the xml files for all architectures supported by GDB over Linux. They are based on the groups defined by strace. gdb/ * xml-syscall.c (get_syscalls_by_group): New. (get_syscall_group_names): New. (struct syscall_group_desc): New structure to store group data. (struct syscalls_info): Include field to store the group list. (sysinfo_free_syscall_group_desc): New. (free_syscalls_info): Free group list. (syscall_group_create_syscall_group_desc): New. (syscall_group_add_syscall): New. (syscall_create_syscall_desc): Add syscall to its groups. (syscall_start_syscall): Load group attribute. (syscall_group_get_group_by_name): New. (xml_list_syscalls_by_group): New. (xml_list_of_groups): New. * xml-syscall.h (get_syscalls_by_group): Export function to retrieve a list of syscalls filtered by the group name. (get_syscall_group_names): Export function to retrieve the list of syscall groups. * break-catch-syscall.c (catch_syscall_split_args): Verify if argument is a syscall group and expand it to a list of syscalls when creating catchpoints. (catch_syscall_completer): Add word completion for system call groups. * configure.ac: Include dependency for xsltproc when building in maintainer-mode. * break-catch-syscall.c (_initialize_breakpoint): Update catch syscall command documentation. * NEWS: Include section about catching groups of syscalls. * configure: Regenerate. * data-directory/Makefile.in: Generate syscall xml when building in maintainer mode. * syscalls/gdb-syscalls.dtd: Include group attribute to the syscall element. * syscalls/apply-defaults.xsl: New. * syscalls/linux-defaults.xml.in: New. * syscalls/aarch64-linux.xml: Rename to aarch64-linux.xml.in. * syscalls/amd64-linux.xml: Rename to amd64-linux.xml.in. * syscalls/arm-linux.xml: Rename to arm-linux.xml.in. * syscalls/bfin-linux.xml: Rename to bfin-linux.xml.in. * syscalls/i386-linux.xml: Rename to i386-linux.xml.in. * syscalls/mips-n32-linux.xml: Rename to mips-n32-linux.xml.in. * syscalls/mips-n64-linux.xml: Rename to mips-n64-linux.xml.in. * syscalls/mips-o32-linux.xml: Rename to mips-o32-linux.xml.in. * syscalls/ppc-linux.xml: Rename to ppc-linux.xml.in. * syscalls/ppc64-linux.xml: Rename to ppc64-linux.xml.in. * syscalls/s390-linux.xml: Rename to s390-linux.xml.in. * syscalls/s390x-linux.xml: Rename to s390x-linux.xml.in. * syscalls/sparc-linux.xml: Rename to sparc-linux.xml.in. * syscalls/sparc64-linux.xml: Rename to sparc64-linux.xml.in. * syscalls/aarch64-linux.xml: Regenerate. * syscalls/amd64-linux.xml: Regenerate. * syscalls/arm-linux.xml: Regenerate. * syscalls/i386-linux.xml: Regenerate. * syscalls/mips-n32-linux.xml: Regenerate. * syscalls/mips-n64-linux.xml: Regenerate. * syscalls/mips-o32-linux.xml: Regenerate. * syscalls/ppc-linux.xml: Regenerate. * syscalls/ppc64-linux.xml: Regenerate. * syscalls/s390-linux.xml: Regenerate. * syscalls/s390x-linux.xml: Regenerate. * syscalls/sparc-linux.xml: Regenerate. * syscalls/sparc64-linux.xml: Regenerate. gdb/testsuite/ * gdb.base/catch-syscall.exp (do_syscall_tests): Add call to test_catch_syscall_group. (test_catch_syscall_group): New. gdb/doc/ * gdb.texinfo (Set Catchpoints): Add 'group' argument to catch syscall.
Diffstat (limited to 'gdb/xml-syscall.c')
-rw-r--r--gdb/xml-syscall.c234
1 files changed, 232 insertions, 2 deletions
diff --git a/gdb/xml-syscall.c b/gdb/xml-syscall.c
index ceaf750..141ca3d 100644
--- a/gdb/xml-syscall.c
+++ b/gdb/xml-syscall.c
@@ -77,6 +77,20 @@ get_syscall_names (struct gdbarch *gdbarch)
return NULL;
}
+struct syscall *
+get_syscalls_by_group (struct gdbarch *gdbarch, const char *group)
+{
+ syscall_warn_user ();
+ return NULL;
+}
+
+const char **
+get_syscall_group_names (struct gdbarch *gdbarch)
+{
+ syscall_warn_user ();
+ return NULL;
+}
+
#else /* ! HAVE_LIBEXPAT */
/* Structure which describes a syscall. */
@@ -92,6 +106,19 @@ typedef struct syscall_desc
} *syscall_desc_p;
DEF_VEC_P(syscall_desc_p);
+/* Structure of a syscall group. */
+typedef struct syscall_group_desc
+{
+ /* The group name. */
+
+ char *name;
+
+ /* The syscalls that are part of the group. */
+
+ VEC(syscall_desc_p) *syscalls;
+} *syscall_group_desc_p;
+DEF_VEC_P(syscall_group_desc_p);
+
/* Structure that represents syscalls information. */
struct syscalls_info
{
@@ -99,6 +126,10 @@ struct syscalls_info
VEC(syscall_desc_p) *syscalls;
+ /* The syscall groups. */
+
+ VEC(syscall_group_desc_p) *groups;
+
/* Variable that will hold the last known data-directory. This is
useful to know whether we should re-read the XML info for the
target. */
@@ -126,11 +157,21 @@ syscalls_info_free_syscalls_desc (struct syscall_desc *sd)
xfree (sd->name);
}
+/* Free syscall_group_desc members but not the structure itself. */
+
+static void
+syscalls_info_free_syscall_group_desc (struct syscall_group_desc *sd)
+{
+ VEC_free (syscall_desc_p, sd->syscalls);
+ xfree (sd->name);
+}
+
static void
free_syscalls_info (void *arg)
{
struct syscalls_info *syscalls_info = (struct syscalls_info *) arg;
struct syscall_desc *sysdesc;
+ struct syscall_group_desc *groupdesc;
int i;
xfree (syscalls_info->my_gdb_datadir);
@@ -144,6 +185,17 @@ free_syscalls_info (void *arg)
VEC_free (syscall_desc_p, syscalls_info->syscalls);
}
+ if (syscalls_info->groups != NULL)
+ {
+ for (i = 0;
+ VEC_iterate (syscall_group_desc_p,
+ syscalls_info->groups, i, groupdesc);
+ i++)
+ syscalls_info_free_syscall_group_desc (groupdesc);
+
+ VEC_free (syscall_group_desc_p, syscalls_info->groups);
+ }
+
xfree (syscalls_info);
}
@@ -153,16 +205,73 @@ make_cleanup_free_syscalls_info (struct syscalls_info *syscalls_info)
return make_cleanup (free_syscalls_info, syscalls_info);
}
+/* Create a new syscall group. Return pointer to the
+ syscall_group_desc structure that represents the new group. */
+
+static struct syscall_group_desc *
+syscall_group_create_syscall_group_desc (struct syscalls_info *syscalls_info,
+ const char *group)
+{
+ struct syscall_group_desc *groupdesc = XCNEW (struct syscall_group_desc);
+
+ groupdesc->name = xstrdup (group);
+
+ VEC_safe_push (syscall_group_desc_p, syscalls_info->groups, groupdesc);
+
+ return groupdesc;
+}
+
+/* Add a syscall to the group. If group doesn't exist, create it. */
+
+static void
+syscall_group_add_syscall (struct syscalls_info *syscalls_info,
+ struct syscall_desc *syscall,
+ const char *group)
+{
+ struct syscall_group_desc *groupdesc = NULL;
+ int i;
+
+ /* Search for an existing group. */
+ for (i = 0;
+ VEC_iterate (syscall_group_desc_p, syscalls_info->groups, i, groupdesc);
+ i++)
+ {
+ if (strcmp (groupdesc->name, group) == 0)
+ break;
+ }
+
+ if (groupdesc == NULL)
+ {
+ /* No group was found with this name. We must create a new
+ one. */
+ groupdesc = syscall_group_create_syscall_group_desc (syscalls_info,
+ group);
+ }
+
+ VEC_safe_push (syscall_desc_p, groupdesc->syscalls, syscall);
+}
+
static void
syscall_create_syscall_desc (struct syscalls_info *syscalls_info,
- const char *name, int number)
+ const char *name, int number,
+ char *groups)
{
struct syscall_desc *sysdesc = XCNEW (struct syscall_desc);
+ char *group;
sysdesc->name = xstrdup (name);
sysdesc->number = number;
VEC_safe_push (syscall_desc_p, syscalls_info->syscalls, sysdesc);
+
+ /* Add syscall to its groups. */
+ if (groups != NULL)
+ {
+ for (group = strtok (groups, ",");
+ group != NULL;
+ group = strtok (NULL, ","))
+ syscall_group_add_syscall (syscalls_info, sysdesc, group);
+ }
}
/* Handle the start of a <syscall> element. */
@@ -177,6 +286,7 @@ syscall_start_syscall (struct gdb_xml_parser *parser,
/* syscall info. */
char *name = NULL;
int number = 0;
+ char *groups = NULL;
len = VEC_length (gdb_xml_value_s, attributes);
@@ -186,13 +296,15 @@ syscall_start_syscall (struct gdb_xml_parser *parser,
name = (char *) attrs[i].value;
else if (strcmp (attrs[i].name, "number") == 0)
number = * (ULONGEST *) attrs[i].value;
+ else if (strcmp (attrs[i].name, "groups") == 0)
+ groups = (char *) attrs[i].value;
else
internal_error (__FILE__, __LINE__,
_("Unknown attribute name '%s'."), attrs[i].name);
}
gdb_assert (name);
- syscall_create_syscall_desc (data->syscalls_info, name, number);
+ syscall_create_syscall_desc (data->syscalls_info, name, number, groups);
}
@@ -200,6 +312,7 @@ syscall_start_syscall (struct gdb_xml_parser *parser,
static const struct gdb_xml_attribute syscall_attr[] = {
{ "number", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL },
{ "name", GDB_XML_AF_NONE, NULL, NULL },
+ { "groups", GDB_XML_AF_OPTIONAL, NULL, NULL },
{ NULL, GDB_XML_AF_NONE, NULL, NULL }
};
@@ -321,6 +434,34 @@ init_syscalls_info (struct gdbarch *gdbarch)
set_gdbarch_syscalls_info (gdbarch, syscalls_info);
}
+/* Search for a syscall group by its name. Return syscall_group_desc
+ structure for the group if found or NULL otherwise. */
+
+static struct syscall_group_desc *
+syscall_group_get_group_by_name (const struct syscalls_info *syscalls_info,
+ const char *group)
+{
+ struct syscall_group_desc *groupdesc;
+ int i;
+
+ if (syscalls_info == NULL)
+ return NULL;
+
+ if (group == NULL)
+ return NULL;
+
+ /* Search for existing group. */
+ for (i = 0;
+ VEC_iterate (syscall_group_desc_p, syscalls_info->groups, i, groupdesc);
+ i++)
+ {
+ if (strcmp (groupdesc->name, group) == 0)
+ return groupdesc;
+ }
+
+ return NULL;
+}
+
static int
xml_get_syscall_number (struct gdbarch *gdbarch,
const char *syscall_name)
@@ -388,6 +529,75 @@ xml_list_of_syscalls (struct gdbarch *gdbarch)
return names;
}
+/* Iterate over the syscall_group_desc element to return a list of
+ syscalls that are part of the given group, terminated by an empty
+ element. If the syscall group doesn't exist, return NULL. */
+
+static struct syscall *
+xml_list_syscalls_by_group (struct gdbarch *gdbarch, const char *group)
+{
+ struct syscalls_info *syscalls_info = gdbarch_syscalls_info (gdbarch);
+ struct syscall_group_desc *groupdesc;
+ struct syscall_desc *sysdesc;
+ struct syscall *syscalls = NULL;
+ int nsyscalls;
+ int i;
+
+ if (syscalls_info == NULL)
+ return NULL;
+
+ groupdesc = syscall_group_get_group_by_name (syscalls_info, group);
+ if (groupdesc == NULL)
+ return NULL;
+
+ nsyscalls = VEC_length (syscall_desc_p, groupdesc->syscalls);
+ syscalls = (struct syscall*) xmalloc ((nsyscalls + 1)
+ * sizeof (struct syscall));
+
+ for (i = 0;
+ VEC_iterate (syscall_desc_p, groupdesc->syscalls, i, sysdesc);
+ i++)
+ {
+ syscalls[i].name = sysdesc->name;
+ syscalls[i].number = sysdesc->number;
+ }
+
+ /* Add final element marker. */
+ syscalls[i].name = NULL;
+ syscalls[i].number = 0;
+
+ return syscalls;
+}
+
+/* Return a NULL terminated list of syscall groups or an empty list, if
+ no syscall group is available. Return NULL, if there is no syscall
+ information available. */
+
+static const char **
+xml_list_of_groups (struct gdbarch *gdbarch)
+{
+ struct syscalls_info *syscalls_info = gdbarch_syscalls_info (gdbarch);
+ struct syscall_group_desc *groupdesc;
+ const char **names = NULL;
+ int i;
+ int ngroups;
+
+ if (syscalls_info == NULL)
+ return NULL;
+
+ ngroups = VEC_length (syscall_group_desc_p, syscalls_info->groups);
+ names = (const char**) xmalloc ((ngroups + 1) * sizeof (char *));
+
+ for (i = 0;
+ VEC_iterate (syscall_group_desc_p, syscalls_info->groups, i, groupdesc);
+ i++)
+ names[i] = groupdesc->name;
+
+ names[i] = NULL;
+
+ return names;
+}
+
void
set_xml_syscall_file_name (struct gdbarch *gdbarch, const char *name)
{
@@ -422,4 +632,24 @@ get_syscall_names (struct gdbarch *gdbarch)
return xml_list_of_syscalls (gdbarch);
}
+/* See comment in xml-syscall.h. */
+
+struct syscall *
+get_syscalls_by_group (struct gdbarch *gdbarch, const char *group)
+{
+ init_syscalls_info (gdbarch);
+
+ return xml_list_syscalls_by_group (gdbarch, group);
+}
+
+/* See comment in xml-syscall.h. */
+
+const char **
+get_syscall_group_names (struct gdbarch *gdbarch)
+{
+ init_syscalls_info (gdbarch);
+
+ return xml_list_of_groups (gdbarch);
+}
+
#endif /* ! HAVE_LIBEXPAT */