X-Git-Url: http://git.efficios.com/?a=blobdiff_plain;f=gdb%2Fxml-tdesc.c;h=6f108a4e3ef620361b2f611efbfd251964662519;hb=873657b9e824943ae44c12966c29cbbcd21c986f;hp=1d4e12cacc59cd7ae5817db1da4b69992ac18eef;hpb=0fb0cc7590113e9b459dfcc48dc71c9d419d9580;p=deliverable%2Fbinutils-gdb.git diff --git a/gdb/xml-tdesc.c b/gdb/xml-tdesc.c index 1d4e12cacc..6f108a4e3e 100644 --- a/gdb/xml-tdesc.c +++ b/gdb/xml-tdesc.c @@ -1,6 +1,6 @@ /* XML target description support for GDB. - Copyright (C) 2006, 2008, 2009 Free Software Foundation, Inc. + Copyright (C) 2006-2020 Free Software Foundation, Inc. Contributed by CodeSourcery. @@ -20,15 +20,20 @@ along with this program. If not, see . */ #include "defs.h" -#include "gdbtypes.h" #include "target.h" #include "target-descriptions.h" #include "xml-support.h" #include "xml-tdesc.h" - +#include "osabi.h" #include "filenames.h" +#include +#include -#include "gdb_assert.h" +/* Maximum sizes. + This is just to catch obviously wrong values. */ +#define MAX_FIELD_SIZE 65536 +#define MAX_FIELD_BITSIZE (MAX_FIELD_SIZE * TARGET_CHAR_BIT) +#define MAX_VECTOR_SIZE 65536 #if !defined(HAVE_LIBEXPAT) @@ -61,15 +66,7 @@ tdesc_parse_xml (const char *document, xml_fetch_another fetcher, then we will create unnecessary duplicate gdbarches. See gdbarch_list_lookup_by_info. */ -struct tdesc_xml_cache -{ - const char *xml_document; - struct target_desc *tdesc; -}; -typedef struct tdesc_xml_cache tdesc_xml_cache_s; -DEF_VEC_O(tdesc_xml_cache_s); - -static VEC(tdesc_xml_cache_s) *xml_cache; +static std::unordered_map xml_cache; /* Callback data for target description parsing. */ @@ -85,8 +82,12 @@ struct tdesc_parsing_data it does not have its own. This starts at zero. */ int next_regnum; - /* The union we are currently parsing, or last parsed. */ - struct type *current_union; + /* The struct or union we are currently parsing, or last parsed. */ + tdesc_type_with_fields *current_type; + + /* The byte size of the current struct/flags type, if specified. Zero + if not specified. Flags values must specify a size. */ + int current_type_size; }; /* Handle the end of an element and its value. */ @@ -96,7 +97,7 @@ tdesc_end_arch (struct gdb_xml_parser *parser, const struct gdb_xml_element *element, void *user_data, const char *body_text) { - struct tdesc_parsing_data *data = user_data; + struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data; const struct bfd_arch_info *arch; arch = bfd_scan_arch (body_text); @@ -106,15 +107,47 @@ tdesc_end_arch (struct gdb_xml_parser *parser, set_tdesc_architecture (data->tdesc, arch); } +/* Handle the end of an element and its value. */ + +static void +tdesc_end_osabi (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, const char *body_text) +{ + struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data; + enum gdb_osabi osabi; + + osabi = osabi_from_tdesc_string (body_text); + if (osabi == GDB_OSABI_UNKNOWN) + warning (_("Target description specified unknown osabi \"%s\""), + body_text); + else + set_tdesc_osabi (data->tdesc, osabi); +} + +/* Handle the end of a element and its value. */ + +static void +tdesc_end_compatible (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, const char *body_text) +{ + struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data; + const struct bfd_arch_info *arch; + + arch = bfd_scan_arch (body_text); + tdesc_add_compatible (data->tdesc, arch); +} + /* Handle the start of a element. */ static void tdesc_start_target (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 tdesc_parsing_data *data = user_data; - char *version = VEC_index (gdb_xml_value_s, attributes, 0)->value; + char *version + = (char *) xml_find_attribute (attributes, "version")->value.get (); if (strcmp (version, "1.0") != 0) gdb_xml_error (parser, @@ -127,10 +160,10 @@ tdesc_start_target (struct gdb_xml_parser *parser, static void tdesc_start_feature (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 tdesc_parsing_data *data = user_data; - char *name = VEC_index (gdb_xml_value_s, attributes, 0)->value; + struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data; + char *name = (char *) xml_find_attribute (attributes, "name")->value.get (); data->current_feature = tdesc_create_feature (data->tdesc, name); } @@ -141,43 +174,41 @@ tdesc_start_feature (struct gdb_xml_parser *parser, static void tdesc_start_reg (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 tdesc_parsing_data *data = user_data; - struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); - int ix = 0, length; - char *name, *group, *type; + struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data; + int ix = 0; + char *name, *group; + const char *type; int bitsize, regnum, save_restore; - length = VEC_length (gdb_xml_value_s, attributes); + int length = attributes.size (); - name = attrs[ix++].value; - bitsize = * (ULONGEST *) attrs[ix++].value; + name = (char *) attributes[ix++].value.get (); + bitsize = * (ULONGEST *) attributes[ix++].value.get (); - if (ix < length && strcmp (attrs[ix].name, "regnum") == 0) - regnum = * (ULONGEST *) attrs[ix++].value; + if (ix < length && strcmp (attributes[ix].name, "regnum") == 0) + regnum = * (ULONGEST *) attributes[ix++].value.get (); else regnum = data->next_regnum; - if (ix < length && strcmp (attrs[ix].name, "type") == 0) - type = attrs[ix++].value; + if (ix < length && strcmp (attributes[ix].name, "type") == 0) + type = (char *) attributes[ix++].value.get (); else type = "int"; - if (ix < length && strcmp (attrs[ix].name, "group") == 0) - group = attrs[ix++].value; + if (ix < length && strcmp (attributes[ix].name, "group") == 0) + group = (char *) attributes[ix++].value.get (); else group = NULL; - if (ix < length && strcmp (attrs[ix].name, "save-restore") == 0) - save_restore = * (ULONGEST *) attrs[ix++].value; + if (ix < length && strcmp (attributes[ix].name, "save-restore") == 0) + save_restore = * (ULONGEST *) attributes[ix++].value.get (); else save_restore = 1; if (strcmp (type, "int") != 0 && strcmp (type, "float") != 0 - && strcmp (type, "code_ptr") != 0 - && strcmp (type, "data_ptr") != 0 && tdesc_named_type (data->current_feature, type) == NULL) gdb_xml_error (parser, _("Register \"%s\" has unknown type \"%s\""), name, type); @@ -194,63 +225,246 @@ tdesc_start_reg (struct gdb_xml_parser *parser, static void tdesc_start_union (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 tdesc_parsing_data *data = user_data; - char *id = VEC_index (gdb_xml_value_s, attributes, 0)->value; - struct type *type; - - type = init_composite_type (NULL, TYPE_CODE_UNION); - TYPE_NAME (type) = xstrdup (id); - tdesc_record_type (data->current_feature, type); - data->current_union = type; + struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data; + char *id = (char *) xml_find_attribute (attributes, "id")->value.get (); + + data->current_type = tdesc_create_union (data->current_feature, id); + data->current_type_size = 0; } -/* Handle the end of a element. */ +/* Handle the start of a element. Initialize the type and + record it with the current feature. */ static void -tdesc_end_union (struct gdb_xml_parser *parser, - const struct gdb_xml_element *element, - void *user_data, const char *body_text) +tdesc_start_struct (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, std::vector &attributes) { - struct tdesc_parsing_data *data = user_data; - int i; - - /* If any of the children of this union are vectors, flag the union - as a vector also. This allows e.g. a union of two vector types - to show up automatically in "info vector". */ - for (i = 0; i < TYPE_NFIELDS (data->current_union); i++) - if (TYPE_VECTOR (TYPE_FIELD_TYPE (data->current_union, i))) - { - TYPE_VECTOR (data->current_union) = 1; - break; - } + struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data; + char *id = (char *) xml_find_attribute (attributes, "id")->value.get (); + struct gdb_xml_value *attr; + + tdesc_type_with_fields *type_with_fields + = tdesc_create_struct (data->current_feature, id); + data->current_type = type_with_fields; + data->current_type_size = 0; + + attr = xml_find_attribute (attributes, "size"); + if (attr != NULL) + { + ULONGEST size = * (ULONGEST *) attr->value.get (); + + if (size > MAX_FIELD_SIZE) + { + gdb_xml_error (parser, + _("Struct size %s is larger than maximum (%d)"), + pulongest (size), MAX_FIELD_SIZE); + } + tdesc_set_struct_size (type_with_fields, size); + data->current_type_size = size; + } +} + +static void +tdesc_start_flags (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, std::vector &attributes) +{ + struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data; + char *id = (char *) xml_find_attribute (attributes, "id")->value.get (); + ULONGEST size = * (ULONGEST *) + xml_find_attribute (attributes, "size")->value.get (); + + if (size > MAX_FIELD_SIZE) + { + gdb_xml_error (parser, + _("Flags size %s is larger than maximum (%d)"), + pulongest (size), MAX_FIELD_SIZE); + } + + data->current_type = tdesc_create_flags (data->current_feature, id, size); + data->current_type_size = size; +} + +static void +tdesc_start_enum (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, std::vector &attributes) +{ + struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data; + char *id = (char *) xml_find_attribute (attributes, "id")->value.get (); + int size = * (ULONGEST *) + xml_find_attribute (attributes, "size")->value.get (); + + if (size > MAX_FIELD_SIZE) + { + gdb_xml_error (parser, + _("Enum size %s is larger than maximum (%d)"), + pulongest (size), MAX_FIELD_SIZE); + } + + data->current_type = tdesc_create_enum (data->current_feature, id, size); + data->current_type_size = 0; } /* Handle the start of a element. Attach the field to the - current union. */ + current struct, union or flags. */ static void tdesc_start_field (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 tdesc_parsing_data *data = user_data; - struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); - struct type *type, *field_type; + struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data; + struct gdb_xml_value *attr; + struct tdesc_type *field_type; char *field_name, *field_type_id; + int start, end; - field_name = attrs[0].value; - field_type_id = attrs[1].value; + field_name = (char *) xml_find_attribute (attributes, "name")->value.get (); - field_type = tdesc_named_type (data->current_feature, field_type_id); - if (field_type == NULL) - gdb_xml_error (parser, _("Union field \"%s\" references undefined " - "type \"%s\""), - field_name, field_type_id); + attr = xml_find_attribute (attributes, "type"); + if (attr != NULL) + { + field_type_id = (char *) attr->value.get (); + field_type = tdesc_named_type (data->current_feature, field_type_id); + } + else + { + field_type_id = NULL; + field_type = NULL; + } + + attr = xml_find_attribute (attributes, "start"); + if (attr != NULL) + { + ULONGEST ul_start = * (ULONGEST *) attr->value.get (); + + if (ul_start > MAX_FIELD_BITSIZE) + { + gdb_xml_error (parser, + _("Field start %s is larger than maximum (%d)"), + pulongest (ul_start), MAX_FIELD_BITSIZE); + } + start = ul_start; + } + else + start = -1; + + attr = xml_find_attribute (attributes, "end"); + if (attr != NULL) + { + ULONGEST ul_end = * (ULONGEST *) attr->value.get (); + + if (ul_end > MAX_FIELD_BITSIZE) + { + gdb_xml_error (parser, + _("Field end %s is larger than maximum (%d)"), + pulongest (ul_end), MAX_FIELD_BITSIZE); + } + end = ul_end; + } + else + end = -1; + + if (start != -1) + { + tdesc_type_with_fields *t = data->current_type; + + /* Older versions of gdb can't handle elided end values. + Stick with that for now, to help ensure backward compatibility. + E.g., If a newer gdbserver is talking to an older gdb. */ + if (end == -1) + gdb_xml_error (parser, _("Missing end value")); + + if (data->current_type_size == 0) + gdb_xml_error (parser, + _("Bitfields must live in explicitly sized types")); + + if (field_type_id != NULL + && strcmp (field_type_id, "bool") == 0 + && start != end) + { + gdb_xml_error (parser, + _("Boolean fields must be one bit in size")); + } + + if (end >= 64) + gdb_xml_error (parser, + _("Bitfield \"%s\" goes past " + "64 bits (unsupported)"), + field_name); + + /* Assume that the bit numbering in XML is "lsb-zero". Most + architectures other than PowerPC use this ordering. In the + future, we can add an XML tag to indicate "msb-zero" numbering. */ + if (start > end) + gdb_xml_error (parser, _("Bitfield \"%s\" has start after end"), + field_name); + if (end >= data->current_type_size * TARGET_CHAR_BIT) + gdb_xml_error (parser, _("Bitfield \"%s\" does not fit in struct"), + field_name); + + if (field_type != NULL) + tdesc_add_typed_bitfield (t, field_name, start, end, field_type); + else if (start == end) + tdesc_add_flag (t, start, field_name); + else + tdesc_add_bitfield (t, field_name, start, end); + } + else if (start == -1 && end != -1) + gdb_xml_error (parser, _("End specified but not start")); + else if (field_type_id != NULL) + { + /* TDESC_TYPE_FLAGS values are explicitly sized, so the following test + catches adding non-bitfield types to flags as well. */ + if (data->current_type_size != 0) + gdb_xml_error (parser, + _("Explicitly sized type cannot " + "contain non-bitfield \"%s\""), + field_name); + + if (field_type == NULL) + gdb_xml_error (parser, _("Field \"%s\" references undefined " + "type \"%s\""), + field_name, field_type_id); + + tdesc_add_field (data->current_type, field_name, field_type); + } + else + gdb_xml_error (parser, _("Field \"%s\" has neither type nor bit position"), + field_name); +} + +/* Handle the start of an element. Attach the value to the + current enum. */ + +static void +tdesc_start_enum_value (struct gdb_xml_parser *parser, + const struct gdb_xml_element *element, + void *user_data, std::vector &attributes) +{ + struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data; + struct gdb_xml_value *attr; + char *field_name; + ULONGEST ul_value; + int value; + + field_name = (char *) xml_find_attribute (attributes, "name")->value.get (); - append_composite_type_field (data->current_union, xstrdup (field_name), - field_type); + attr = xml_find_attribute (attributes, "value"); + ul_value = * (ULONGEST *) attr->value.get (); + if (ul_value > INT_MAX) + { + gdb_xml_error (parser, + _("Enum value %s is larger than maximum (%d)"), + pulongest (ul_value), INT_MAX); + } + value = ul_value; + + tdesc_add_enum_value (data->current_type, value, field_name); } /* Handle the start of a element. Initialize the type and @@ -259,43 +473,60 @@ tdesc_start_field (struct gdb_xml_parser *parser, static void tdesc_start_vector (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 tdesc_parsing_data *data = user_data; - struct gdb_xml_value *attrs = VEC_address (gdb_xml_value_s, attributes); - struct type *type, *field_type, *range_type; + struct tdesc_parsing_data *data = (struct tdesc_parsing_data *) user_data; + struct tdesc_type *field_type; char *id, *field_type_id; - int count; + ULONGEST count; - id = attrs[0].value; - field_type_id = attrs[1].value; - count = * (ULONGEST *) attrs[2].value; + id = (char *) attributes[0].value.get (); + field_type_id = (char *) attributes[1].value.get (); + count = * (ULONGEST *) attributes[2].value.get (); + + if (count > MAX_VECTOR_SIZE) + { + gdb_xml_error (parser, + _("Vector size %s is larger than maximum (%d)"), + pulongest (count), MAX_VECTOR_SIZE); + } field_type = tdesc_named_type (data->current_feature, field_type_id); if (field_type == NULL) gdb_xml_error (parser, _("Vector \"%s\" references undefined type \"%s\""), id, field_type_id); - type = init_vector_type (field_type, count); - TYPE_NAME (type) = xstrdup (id); - - tdesc_record_type (data->current_feature, type); + tdesc_create_vector (data->current_feature, id, field_type, count); } /* The elements and attributes of an XML target description. */ static const struct gdb_xml_attribute field_attributes[] = { { "name", GDB_XML_AF_NONE, NULL, NULL }, - { "type", GDB_XML_AF_NONE, NULL, NULL }, + { "type", GDB_XML_AF_OPTIONAL, NULL, NULL }, + { "start", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL }, + { "end", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL }, { NULL, GDB_XML_AF_NONE, NULL, NULL } }; -static const struct gdb_xml_element union_children[] = { +static const struct gdb_xml_attribute enum_value_attributes[] = { + { "name", GDB_XML_AF_NONE, NULL, NULL }, + { "value", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL }, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_element struct_union_children[] = { { "field", field_attributes, NULL, GDB_XML_EF_REPEATABLE, tdesc_start_field, NULL }, { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } }; +static const struct gdb_xml_element enum_children[] = { + { "evalue", enum_value_attributes, NULL, GDB_XML_EF_REPEATABLE, + tdesc_start_enum_value, NULL }, + { NULL, NULL, NULL, GDB_XML_EF_NONE, NULL, NULL } +}; + static const struct gdb_xml_attribute reg_attributes[] = { { "name", GDB_XML_AF_NONE, NULL, NULL }, { "bitsize", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL }, @@ -307,8 +538,21 @@ static const struct gdb_xml_attribute reg_attributes[] = { { NULL, GDB_XML_AF_NONE, NULL, NULL } }; -static const struct gdb_xml_attribute union_attributes[] = { +static const struct gdb_xml_attribute struct_union_attributes[] = { { "id", GDB_XML_AF_NONE, NULL, NULL }, + { "size", GDB_XML_AF_OPTIONAL, gdb_xml_parse_attr_ulongest, NULL}, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_attribute flags_attributes[] = { + { "id", GDB_XML_AF_NONE, NULL, NULL }, + { "size", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL}, + { NULL, GDB_XML_AF_NONE, NULL, NULL } +}; + +static const struct gdb_xml_attribute enum_attributes[] = { + { "id", GDB_XML_AF_NONE, NULL, NULL }, + { "size", GDB_XML_AF_NONE, gdb_xml_parse_attr_ulongest, NULL}, { NULL, GDB_XML_AF_NONE, NULL, NULL } }; @@ -328,9 +572,18 @@ static const struct gdb_xml_element feature_children[] = { { "reg", reg_attributes, NULL, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, tdesc_start_reg, NULL }, - { "union", union_attributes, union_children, + { "struct", struct_union_attributes, struct_union_children, + GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, + tdesc_start_struct, NULL }, + { "union", struct_union_attributes, struct_union_children, + GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, + tdesc_start_union, NULL }, + { "flags", flags_attributes, struct_union_children, + GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, + tdesc_start_flags, NULL }, + { "enum", enum_attributes, enum_children, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, - tdesc_start_union, tdesc_end_union }, + tdesc_start_enum, NULL }, { "vector", vector_attributes, NULL, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, tdesc_start_vector, NULL }, @@ -345,6 +598,10 @@ static const struct gdb_xml_attribute target_attributes[] = { static const struct gdb_xml_element target_children[] = { { "architecture", NULL, NULL, GDB_XML_EF_OPTIONAL, NULL, tdesc_end_arch }, + { "osabi", NULL, NULL, GDB_XML_EF_OPTIONAL, + NULL, tdesc_end_osabi }, + { "compatible", NULL, NULL, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, + NULL, tdesc_end_compatible }, { "feature", feature_attributes, feature_children, GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE, tdesc_start_feature, NULL }, @@ -363,155 +620,61 @@ static struct target_desc * tdesc_parse_xml (const char *document, xml_fetch_another fetcher, void *fetcher_baton) { - struct cleanup *back_to, *result_cleanup; - struct gdb_xml_parser *parser; struct tdesc_parsing_data data; - struct tdesc_xml_cache *cache; - char *expanded_text; - int ix; /* Expand all XInclude directives. */ - expanded_text = xml_process_xincludes (_("target description"), - document, fetcher, fetcher_baton, 0); - if (expanded_text == NULL) + std::string expanded_text; + + if (!xml_process_xincludes (expanded_text, + _("target description"), + document, fetcher, fetcher_baton, 0)) { warning (_("Could not load XML target description; ignoring")); return NULL; } /* Check for an exact match in the list of descriptions we have - previously parsed. strcmp is a slightly inefficient way to - do this; an SHA-1 checksum would work as well. */ - for (ix = 0; VEC_iterate (tdesc_xml_cache_s, xml_cache, ix, cache); ix++) - if (strcmp (cache->xml_document, expanded_text) == 0) - { - xfree (expanded_text); - return cache->tdesc; - } - - back_to = make_cleanup (null_cleanup, NULL); - parser = gdb_xml_create_parser_and_cleanup (_("target description"), - tdesc_elements, &data); - gdb_xml_use_dtd (parser, "gdb-target.dtd"); + previously parsed. */ + const auto it = xml_cache.find (expanded_text); + if (it != xml_cache.end ()) + return it->second.get (); memset (&data, 0, sizeof (struct tdesc_parsing_data)); - data.tdesc = allocate_target_description (); - result_cleanup = make_cleanup_free_target_description (data.tdesc); - make_cleanup (xfree, expanded_text); + target_desc_up description (allocate_target_description ()); + data.tdesc = description.get (); - if (gdb_xml_parse (parser, expanded_text) == 0) + if (gdb_xml_parse_quick (_("target description"), "gdb-target.dtd", + tdesc_elements, expanded_text.c_str (), &data) == 0) { /* Parsed successfully. */ - struct tdesc_xml_cache new_cache; - - new_cache.xml_document = expanded_text; - new_cache.tdesc = data.tdesc; - VEC_safe_push (tdesc_xml_cache_s, xml_cache, &new_cache); - discard_cleanups (result_cleanup); - do_cleanups (back_to); + xml_cache.emplace (std::move (expanded_text), std::move (description)); return data.tdesc; } else { warning (_("Could not load XML target description; ignoring")); - do_cleanups (back_to); return NULL; } } #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. */ const struct target_desc * file_read_description_xml (const char *filename) { - struct target_desc *tdesc; - char *tdesc_str; - struct cleanup *back_to; - char *dirname; - - tdesc_str = fetch_xml_from_file (filename, NULL); - if (tdesc_str == NULL) + gdb::optional tdesc_str + = xml_fetch_content_from_file (filename, NULL); + if (!tdesc_str) { warning (_("Could not open \"%s\""), filename); return NULL; } - back_to = make_cleanup (xfree, tdesc_str); - - dirname = ldirname (filename); - if (dirname != NULL) - make_cleanup (xfree, dirname); - - tdesc = tdesc_parse_xml (tdesc_str, fetch_xml_from_file, dirname); - do_cleanups (back_to); - - return tdesc; + return tdesc_parse_xml (tdesc_str->data (), xml_fetch_content_from_file, + (void *) ldirname (filename).c_str ()); } /* Read a string representation of available features from the target, @@ -521,10 +684,10 @@ file_read_description_xml (const char *filename) is "target.xml". Other calls may be performed for the DTD or for . */ -static char * +static gdb::optional fetch_available_features_from_target (const char *name, void *baton_) { - struct target_ops *ops = baton_; + struct target_ops *ops = (struct target_ops *) baton_; /* Read this object as a string. This ensures that a NUL terminator is added. */ @@ -540,19 +703,61 @@ fetch_available_features_from_target (const char *name, void *baton_) const struct target_desc * target_read_description_xml (struct target_ops *ops) { - struct target_desc *tdesc; - char *tdesc_str; - struct cleanup *back_to; - - tdesc_str = fetch_available_features_from_target ("target.xml", ops); - if (tdesc_str == NULL) + gdb::optional tdesc_str + = fetch_available_features_from_target ("target.xml", ops); + if (!tdesc_str) return NULL; - back_to = make_cleanup (xfree, tdesc_str); - tdesc = tdesc_parse_xml (tdesc_str, - fetch_available_features_from_target, - ops); - do_cleanups (back_to); + return tdesc_parse_xml (tdesc_str->data (), + fetch_available_features_from_target, + ops); +} + +/* Fetches an XML target description using OPS, processing + includes, but not parsing it. Used to dump whole tdesc + as a single XML file. */ + +gdb::optional +target_fetch_description_xml (struct target_ops *ops) +{ +#if !defined(HAVE_LIBEXPAT) + static int have_warned; - return tdesc; + if (!have_warned) + { + have_warned = 1; + warning (_("Can not fetch XML target description; XML support was " + "disabled at compile time")); + } + + return {}; +#else + gdb::optional + tdesc_str = fetch_available_features_from_target ("target.xml", ops); + if (!tdesc_str) + return {}; + + std::string output; + if (!xml_process_xincludes (output, + _("target description"), + tdesc_str->data (), + fetch_available_features_from_target, ops, 0)) + { + warning (_("Could not load XML target description; ignoring")); + return {}; + } + return output; +#endif +} + +/* See xml-tdesc.h. */ + +const struct target_desc * +string_read_description_xml (const char *xml) +{ + return tdesc_parse_xml (xml, [] (const char *href, void *baton) + { + error (_("xincludes are unsupported with this method")); + return gdb::optional (); + }, nullptr); }