diff options
author | Gabriel Krisman Bertazi <gabriel@krisman.be> | 2016-07-23 18:38:24 -0300 |
---|---|---|
committer | Gabriel Krisman Bertazi <gabriel@krisman.be> | 2016-07-23 18:38:24 -0300 |
commit | e34879080d8935792ef3942efa5f25b4c3169b5a (patch) | |
tree | daab863d91a6bb66ab2c10f1f4ef50b52dab66ea /gdb/xml-syscall.c | |
parent | 49ecef2a7da2ee9df4ae675f99b70518fbf1bb23 (diff) | |
download | gdb-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.c | 234 |
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 */ |