X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fxml-syscall.c;h=3830faa43652fdce9e09efeaa2c0629ab7c8d46e;hb=7190276c52b9d86a52aae73d3a0f8b56e7a1f4f1;hp=5d4a405273acaca10f445e93337e9ef1126e9b63;hpb=7b6bb8daaceb9ecf3f42dea57ae82733d6a3b2f6;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/xml-syscall.c b/gdb/xml-syscall.c index 5d4a405273..3830faa436 100644 --- a/gdb/xml-syscall.c +++ b/gdb/xml-syscall.c @@ -1,7 +1,7 @@ /* Functions that provide the mechanism to parse a syscall XML file and get its values. - Copyright (C) 2009, 2010, 2011 Free Software Foundation, Inc. + Copyright (C) 2009-2019 Free Software Foundation, Inc. This file is part of GDB. @@ -22,14 +22,13 @@ #include "gdbtypes.h" #include "xml-support.h" #include "xml-syscall.h" +#include "gdbarch.h" /* For the struct syscall definition. */ #include "target.h" #include "filenames.h" -#include "gdb_assert.h" - #ifndef HAVE_LIBEXPAT /* Dummy functions to indicate that there's no support for fetching @@ -48,154 +47,220 @@ syscall_warn_user (void) } void -set_xml_syscall_file_name (const char *name) +set_xml_syscall_file_name (struct gdbarch *gdbarch, const char *name) { return; } void -get_syscall_by_number (int syscall_number, - struct syscall *s) +get_syscall_by_number (struct gdbarch *gdbarch, + int syscall_number, struct syscall *s) { syscall_warn_user (); s->number = syscall_number; s->name = NULL; } -void -get_syscall_by_name (const char *syscall_name, - struct syscall *s) +bool +get_syscalls_by_name (struct gdbarch *gdbarch, const char *syscall_name, + std::vector *syscall_numbers) { syscall_warn_user (); - s->number = UNKNOWN_SYSCALL; - s->name = syscall_name; + return false; } const char ** -get_syscall_names (void) +get_syscall_names (struct gdbarch *gdbarch) { syscall_warn_user (); return NULL; } -#else /* ! HAVE_LIBEXPAT */ +bool +get_syscalls_by_group (struct gdbarch *gdbarch, const char *group, + std::vector *syscall_numbers) +{ + syscall_warn_user (); + return false; +} -/* 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. */ -static char *my_gdb_datadir = NULL; +const char ** +get_syscall_group_names (struct gdbarch *gdbarch) +{ + syscall_warn_user (); + return NULL; +} + +#else /* ! HAVE_LIBEXPAT */ /* Structure which describes a syscall. */ -typedef struct syscall_desc +struct syscall_desc { + syscall_desc (int number_, std::string name_, std::string alias_) + : number (number_), name (name_), alias (alias_) + {} + /* The syscall number. */ int number; /* The syscall name. */ - char *name; -} *syscall_desc_p; -DEF_VEC_P(syscall_desc_p); + std::string name; + + /* An optional alias. */ + + std::string alias; +}; + +typedef std::unique_ptr syscall_desc_up; + +/* Structure of a syscall group. */ +struct syscall_group_desc +{ + syscall_group_desc (const std::string &name_) + : name (name_) + {} + + /* The group name. */ + + std::string name; + + /* The syscalls that are part of the group. This is a non-owning + reference. */ + + std::vector syscalls; +}; + +typedef std::unique_ptr syscall_group_desc_up; /* Structure that represents syscalls information. */ struct syscalls_info { /* The syscalls. */ - VEC(syscall_desc_p) *syscalls; + std::vector syscalls; + + /* The syscall groups. */ + + std::vector 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. */ + + std::string my_gdb_datadir; }; +typedef std::unique_ptr syscalls_info_up; + /* Callback data for syscall information parsing. */ struct syscall_parsing_data { /* The syscalls_info we are building. */ - struct syscalls_info *sysinfo; + struct syscalls_info *syscalls_info; }; -/* Structure used to store information about the available syscalls in - the system. */ -static const struct syscalls_info *sysinfo = NULL; +/* Create a new syscall group. Return pointer to the + syscall_group_desc structure that represents the new group. */ -/* A flag to tell if we already initialized the structure above. */ -static int have_initialized_sysinfo = 0; +static struct syscall_group_desc * +syscall_group_create_syscall_group_desc (struct syscalls_info *syscalls_info, + const char *group) +{ + syscall_group_desc *groupdesc = new syscall_group_desc (group); -/* The filename of the syscall's XML. */ -static const char *xml_syscall_file = NULL; + syscalls_info->groups.emplace_back (groupdesc); -static struct syscalls_info * -allocate_syscalls_info (void) -{ - return XZALLOC (struct syscalls_info); + return groupdesc; } -static void -sysinfo_free_syscalls_desc (struct syscall_desc *sd) -{ - xfree (sd->name); -} +/* Add a syscall to the group. If group doesn't exist, create it. */ static void -free_syscalls_info (void *arg) +syscall_group_add_syscall (struct syscalls_info *syscalls_info, + struct syscall_desc *syscall, + const char *group) { - struct syscalls_info *sysinfo = arg; - struct syscall_desc *sysdesc; - int i; + /* Search for an existing group. */ + std::vector::iterator it + = syscalls_info->groups.begin (); - for (i = 0; - VEC_iterate (syscall_desc_p, sysinfo->syscalls, i, sysdesc); - i++) - sysinfo_free_syscalls_desc (sysdesc); - VEC_free (syscall_desc_p, sysinfo->syscalls); + for (; it != syscalls_info->groups.end (); it++) + { + if ((*it)->name == group) + break; + } - xfree (sysinfo); -} + syscall_group_desc *groupdesc; -struct cleanup * -make_cleanup_free_syscalls_info (struct syscalls_info *sysinfo) -{ - return make_cleanup (free_syscalls_info, sysinfo); + if (it != syscalls_info->groups.end ()) + groupdesc = it->get (); + else + { + /* No group was found with this name. We must create a new + one. */ + groupdesc = syscall_group_create_syscall_group_desc (syscalls_info, + group); + } + + groupdesc->syscalls.push_back (syscall); } static void -syscall_create_syscall_desc (struct syscalls_info *sysinfo, - const char *name, int number) +syscall_create_syscall_desc (struct syscalls_info *syscalls_info, + const char *name, int number, const char *alias, + char *groups) { - struct syscall_desc *sysdesc = XZALLOC (struct syscall_desc); + syscall_desc *sysdesc = new syscall_desc (number, name, + alias != NULL ? alias : ""); - sysdesc->name = xstrdup (name); - sysdesc->number = number; + syscalls_info->syscalls.emplace_back (sysdesc); - VEC_safe_push (syscall_desc_p, sysinfo->syscalls, sysdesc); + /* Add syscall to its groups. */ + if (groups != NULL) + { + char *saveptr; + for (char *group = strtok_r (groups, ",", &saveptr); + group != NULL; + group = strtok_r (NULL, ",", &saveptr)) + syscall_group_add_syscall (syscalls_info, sysdesc, group); + } } /* Handle the start of a element. */ static void syscall_start_syscall (struct gdb_xml_parser *parser, const struct gdb_xml_element *element, - void *user_data, VEC(gdb_xml_value_s) *attributes) + void *user_data, + std::vector &attributes) { - struct syscall_parsing_data *data = user_data; - struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); - int len, i; + struct syscall_parsing_data *data = (struct syscall_parsing_data *) user_data; /* syscall info. */ char *name = NULL; int number = 0; + char *alias = NULL; + char *groups = NULL; - len = VEC_length (gdb_xml_value_s, attributes); - - for (i = 0; i < len; i++) + for (const gdb_xml_value &attr : attributes) { - if (strcmp (attrs[i].name, "name") == 0) - name = attrs[i].value; - else if (strcmp (attrs[i].name, "number") == 0) - number = * (ULONGEST *) attrs[i].value; + if (strcmp (attr.name, "name") == 0) + name = (char *) attr.value.get (); + else if (strcmp (attr.name, "number") == 0) + number = * (ULONGEST *) attr.value.get (); + else if (strcmp (attr.name, "alias") == 0) + alias = (char *) attr.value.get (); + else if (strcmp (attr.name, "groups") == 0) + groups = (char *) attr.value.get (); else internal_error (__FILE__, __LINE__, - _("Unknown attribute name '%s'."), attrs[i].name); + _("Unknown attribute name '%s'."), attr.name); } - syscall_create_syscall_desc (data->sysinfo, name, number); + gdb_assert (name); + syscall_create_syscall_desc (data->syscalls_info, name, number, alias, + groups); } @@ -203,6 +268,8 @@ 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 }, + { "alias", GDB_XML_AF_OPTIONAL, NULL, NULL }, + { "groups", GDB_XML_AF_OPTIONAL, NULL, NULL }, { NULL, GDB_XML_AF_NONE, NULL, NULL } }; @@ -223,27 +290,20 @@ static struct syscalls_info * syscall_parse_xml (const char *document, xml_fetch_another fetcher, void *fetcher_baton) { - struct cleanup *result_cleanup; - struct gdb_xml_parser *parser; struct syscall_parsing_data data; + syscalls_info_up sysinfo (new syscalls_info ()); - parser = gdb_xml_create_parser_and_cleanup (_("syscalls info"), - syselements, &data); - - memset (&data, 0, sizeof (struct syscall_parsing_data)); - data.sysinfo = allocate_syscalls_info (); - result_cleanup = make_cleanup_free_syscalls_info (data.sysinfo); + data.syscalls_info = sysinfo.get (); - if (gdb_xml_parse (parser, document) == 0) + if (gdb_xml_parse_quick (_("syscalls info"), NULL, + syselements, document, &data) == 0) { /* Parsed successfully. */ - discard_cleanups (result_cleanup); - return data.sysinfo; + return sysinfo.release (); } else { warning (_("Could not load XML syscalls info; ignoring")); - do_cleanups (result_cleanup); return NULL; } } @@ -253,132 +313,193 @@ syscall_parse_xml (const char *document, xml_fetch_another fetcher, struct syscalls_info with the values. Returns the struct syscalls_info if the file is valid, NULL otherwise. */ -static const struct syscalls_info * +static struct syscalls_info * xml_init_syscalls_info (const char *filename) { - char *full_file; - char *dirname; - struct syscalls_info *sysinfo; - struct cleanup *back_to; - - full_file = xml_fetch_content_from_file (filename, gdb_datadir); - if (full_file == NULL) + gdb::optional full_file + = xml_fetch_content_from_file (filename, + const_cast(gdb_datadir.c_str ())); + if (!full_file) return NULL; - back_to = make_cleanup (xfree, full_file); - - dirname = ldirname (filename); - if (dirname != NULL) - make_cleanup (xfree, dirname); - - sysinfo = syscall_parse_xml (full_file, xml_fetch_content_from_file, dirname); - do_cleanups (back_to); - - return sysinfo; + return syscall_parse_xml (full_file->data (), + xml_fetch_content_from_file, + (void *) ldirname (filename).c_str ()); } /* Initializes the syscalls_info structure according to the architecture. */ static void -init_sysinfo (void) +init_syscalls_info (struct gdbarch *gdbarch) { + struct syscalls_info *syscalls_info = gdbarch_syscalls_info (gdbarch); + const char *xml_syscall_file = gdbarch_xml_syscall_file (gdbarch); + /* Should we re-read the XML info for this target? */ - if (my_gdb_datadir && strcmp (my_gdb_datadir, gdb_datadir) != 0) + if (syscalls_info != NULL && !syscalls_info->my_gdb_datadir.empty () + && filename_cmp (syscalls_info->my_gdb_datadir.c_str (), + gdb_datadir.c_str ()) != 0) { /* The data-directory changed from the last time we used it. It means that we have to re-read the XML info. */ - have_initialized_sysinfo = 0; - xfree (my_gdb_datadir); - my_gdb_datadir = NULL; - if (sysinfo) - free_syscalls_info ((void *) sysinfo); + delete syscalls_info; + syscalls_info = NULL; + set_gdbarch_syscalls_info (gdbarch, NULL); } - /* Did we already try to initialize the structure? */ - if (have_initialized_sysinfo) + /* Did we succeed at initializing this? */ + if (syscalls_info != NULL) return; - sysinfo = xml_init_syscalls_info (xml_syscall_file); + syscalls_info = xml_init_syscalls_info (xml_syscall_file); - have_initialized_sysinfo = 1; + /* If there was some error reading the XML file, we initialize + gdbarch->syscalls_info anyway, in order to store information + about our attempt. */ + if (syscalls_info == NULL) + syscalls_info = new struct syscalls_info (); - if (sysinfo == NULL) + if (syscalls_info->syscalls.empty ()) { - if (xml_syscall_file) - warning (_("\ -Could not load the syscall XML file `%s/%s'."), - gdb_datadir, xml_syscall_file); + if (xml_syscall_file != NULL) + warning (_("Could not load the syscall XML file `%s/%s'."), + gdb_datadir.c_str (), xml_syscall_file); else - warning (_("\ -There is no XML file to open.")); + warning (_("There is no XML file to open.")); - warning (_("\ -GDB will not be able to display syscall names nor to verify if\n\ -any provided syscall numbers are valid.")); + warning (_("GDB will not be able to display " + "syscall names nor to verify if\n" + "any provided syscall numbers are valid.")); } /* Saving the data-directory used to read this XML info. */ - my_gdb_datadir = xstrdup (gdb_datadir); + syscalls_info->my_gdb_datadir.assign (gdb_datadir); + + set_gdbarch_syscalls_info (gdbarch, syscalls_info); } -static int -xml_get_syscall_number (const struct syscalls_info *sysinfo, - const char *syscall_name) +/* 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_desc *sysdesc; - int i; + if (syscalls_info == NULL) + return NULL; + + if (group == NULL) + return NULL; - if (sysinfo == NULL - || syscall_name == NULL) - return UNKNOWN_SYSCALL; + /* Search for existing group. */ + for (const syscall_group_desc_up &groupdesc : syscalls_info->groups) + { + if (groupdesc->name == group) + return groupdesc.get (); + } - for (i = 0; - VEC_iterate(syscall_desc_p, sysinfo->syscalls, i, sysdesc); - i++) - if (strcmp (sysdesc->name, syscall_name) == 0) - return sysdesc->number; + return NULL; +} - return UNKNOWN_SYSCALL; +static bool +xml_get_syscalls_by_name (struct gdbarch *gdbarch, const char *syscall_name, + std::vector *syscall_numbers) +{ + struct syscalls_info *syscalls_info = gdbarch_syscalls_info (gdbarch); + + bool found = false; + if (syscalls_info != NULL && syscall_name != NULL && syscall_numbers != NULL) + for (const syscall_desc_up &sysdesc : syscalls_info->syscalls) + if (sysdesc->name == syscall_name || sysdesc->alias == syscall_name) + { + syscall_numbers->push_back (sysdesc->number); + found = true; + } + + return found; } static const char * -xml_get_syscall_name (const struct syscalls_info *sysinfo, +xml_get_syscall_name (struct gdbarch *gdbarch, int syscall_number) { - struct syscall_desc *sysdesc; - int i; + struct syscalls_info *syscalls_info = gdbarch_syscalls_info (gdbarch); - if (sysinfo == NULL + if (syscalls_info == NULL || syscall_number < 0) return NULL; - for (i = 0; - VEC_iterate(syscall_desc_p, sysinfo->syscalls, i, sysdesc); - i++) + for (const syscall_desc_up &sysdesc : syscalls_info->syscalls) if (sysdesc->number == syscall_number) - return sysdesc->name; + return sysdesc->name.c_str (); return NULL; } static const char ** -xml_list_of_syscalls (const struct syscalls_info *sysinfo) +xml_list_of_syscalls (struct gdbarch *gdbarch) { - struct syscall_desc *sysdesc; + struct syscalls_info *syscalls_info = gdbarch_syscalls_info (gdbarch); + + if (syscalls_info == NULL) + return NULL; + + int nsyscalls = syscalls_info->syscalls.size (); + const char **names = XNEWVEC (const char *, nsyscalls + 1); + + int i; + for (i = 0; i < syscalls_info->syscalls.size (); i++) + names[i] = syscalls_info->syscalls[i]->name.c_str (); + + names[i] = NULL; + + return names; +} + +/* Iterate over the syscall_group_desc element to return a list of + syscalls that are part of the given group. If the syscall group + doesn't exist, return false. */ + +static bool +xml_list_syscalls_by_group (struct gdbarch *gdbarch, const char *group, + std::vector *syscalls) +{ + struct syscalls_info *syscalls_info = gdbarch_syscalls_info (gdbarch); + struct syscall_group_desc *groupdesc; + + if (syscalls_info == NULL || syscalls == NULL) + return false; + + groupdesc = syscall_group_get_group_by_name (syscalls_info, group); + if (groupdesc == NULL) + return false; + + for (const syscall_desc *sysdesc : groupdesc->syscalls) + syscalls->push_back (sysdesc->number); + + return true; +} + +/* 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); const char **names = NULL; - int nsyscalls; + int ngroups; int i; - if (sysinfo == NULL) + if (syscalls_info == NULL) return NULL; - nsyscalls = VEC_length (syscall_desc_p, sysinfo->syscalls); - names = xmalloc ((nsyscalls + 1) * sizeof (char *)); + ngroups = syscalls_info->groups.size (); + names = (const char**) xmalloc ((ngroups + 1) * sizeof (char *)); - for (i = 0; - VEC_iterate (syscall_desc_p, sysinfo->syscalls, i, sysdesc); - i++) - names[i] = sysdesc->name; + for (i = 0; i < syscalls_info->groups.size (); i++) + names[i] = syscalls_info->groups[i]->name.c_str (); names[i] = NULL; @@ -386,37 +507,57 @@ xml_list_of_syscalls (const struct syscalls_info *sysinfo) } void -set_xml_syscall_file_name (const char *name) +set_xml_syscall_file_name (struct gdbarch *gdbarch, const char *name) { - xml_syscall_file = name; + set_gdbarch_xml_syscall_file (gdbarch, name); } void -get_syscall_by_number (int syscall_number, - struct syscall *s) +get_syscall_by_number (struct gdbarch *gdbarch, + int syscall_number, struct syscall *s) { - init_sysinfo (); + init_syscalls_info (gdbarch); s->number = syscall_number; - s->name = xml_get_syscall_name (sysinfo, syscall_number); + s->name = xml_get_syscall_name (gdbarch, syscall_number); } -void -get_syscall_by_name (const char *syscall_name, - struct syscall *s) +bool +get_syscalls_by_name (struct gdbarch *gdbarch, const char *syscall_name, + std::vector *syscall_numbers) +{ + init_syscalls_info (gdbarch); + + return xml_get_syscalls_by_name (gdbarch, syscall_name, syscall_numbers); +} + +const char ** +get_syscall_names (struct gdbarch *gdbarch) { - init_sysinfo (); + init_syscalls_info (gdbarch); - s->number = xml_get_syscall_number (sysinfo, syscall_name); - s->name = syscall_name; + return xml_list_of_syscalls (gdbarch); } +/* See comment in xml-syscall.h. */ + +bool +get_syscalls_by_group (struct gdbarch *gdbarch, const char *group, + std::vector *syscall_numbers) +{ + init_syscalls_info (gdbarch); + + return xml_list_syscalls_by_group (gdbarch, group, syscall_numbers); +} + +/* See comment in xml-syscall.h. */ + const char ** -get_syscall_names (void) +get_syscall_group_names (struct gdbarch *gdbarch) { - init_sysinfo (); + init_syscalls_info (gdbarch); - return xml_list_of_syscalls (sysinfo); + return xml_list_of_groups (gdbarch); } #endif /* ! HAVE_LIBEXPAT */