/* XML target description support for GDB.
- Copyright (C) 2006
- Free Software Foundation, Inc.
+ Copyright (C) 2006, 2008-2012 Free Software Foundation, Inc.
Contributed by CodeSourcery.
This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
- the Free Software Foundation; either version 2 of the License, or
+ the Free Software Foundation; either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
- along with this program; if not, write to the Free Software
- Foundation, Inc., 51 Franklin Street, Fifth Floor,
- Boston, MA 02110-1301, USA. */
+ along with this program. If not, see <http://www.gnu.org/licenses/>. */
#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"
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. */
+ struct tdesc_type *current_type;
+
+ /* The byte size of the current struct type, if specified. Zero
+ if not specified. */
+ int current_type_size;
+
+ /* Whether the current type is a flags type. */
+ int current_type_is_flags;
};
/* Handle the end of an <architecture> element and its value. */
set_tdesc_architecture (data->tdesc, arch);
}
+/* Handle the end of an <osabi> 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 = 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 <compatible> 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 = 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 <target> element. */
static void
const struct gdb_xml_element *element,
void *user_data, VEC(gdb_xml_value_s) *attributes)
{
- struct tdesc_parsing_data *data = user_data;
- char *version = VEC_index (gdb_xml_value_s, attributes, 0)->value;
+ char *version = xml_find_attribute (attributes, "version")->value;
if (strcmp (version, "1.0") != 0)
gdb_xml_error (parser,
void *user_data, VEC(gdb_xml_value_s) *attributes)
{
struct tdesc_parsing_data *data = user_data;
- char *name = VEC_index (gdb_xml_value_s, attributes, 0)->value;
+ char *name = xml_find_attribute (attributes, "name")->value;
data->current_feature = tdesc_create_feature (data->tdesc, name);
}
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);
void *user_data, VEC(gdb_xml_value_s) *attributes)
{
struct tdesc_parsing_data *data = user_data;
- char *id = VEC_index (gdb_xml_value_s, attributes, 0)->value;
- struct type *type;
+ char *id = xml_find_attribute (attributes, "id")->value;
- type = init_composite_type (NULL, TYPE_CODE_UNION);
- TYPE_NAME (type) = xstrdup (id);
- tdesc_record_type (data->current_feature, type);
- data->current_union = type;
+ data->current_type = tdesc_create_union (data->current_feature, id);
+ data->current_type_size = 0;
+ data->current_type_is_flags = 0;
}
-/* Handle the end of a <union> element. */
+/* Handle the start of a <struct> 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, VEC(gdb_xml_value_s) *attributes)
{
struct tdesc_parsing_data *data = user_data;
- int i;
+ char *id = xml_find_attribute (attributes, "id")->value;
+ struct tdesc_type *type;
+ struct gdb_xml_value *attr;
- /* 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_FLAGS (data->current_union) |= TYPE_FLAG_VECTOR;
- break;
- }
+ type = tdesc_create_struct (data->current_feature, id);
+ data->current_type = type;
+ data->current_type_size = 0;
+ data->current_type_is_flags = 0;
+
+ attr = xml_find_attribute (attributes, "size");
+ if (attr != NULL)
+ {
+ int size = (int) * (ULONGEST *) attr->value;
+
+ tdesc_set_struct_size (type, 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, VEC(gdb_xml_value_s) *attributes)
+{
+ struct tdesc_parsing_data *data = user_data;
+ char *id = xml_find_attribute (attributes, "id")->value;
+ int length = (int) * (ULONGEST *)
+ xml_find_attribute (attributes, "size")->value;
+ struct tdesc_type *type;
+
+ type = tdesc_create_flags (data->current_feature, id, length);
+
+ data->current_type = type;
+ data->current_type_size = 0;
+ data->current_type_is_flags = 1;
}
/* Handle the start of a <field> element. Attach the field to the
- current union. */
+ current struct or union. */
static void
tdesc_start_field (struct gdb_xml_parser *parser,
void *user_data, VEC(gdb_xml_value_s) *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 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 = xml_find_attribute (attributes, "name")->value;
- 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 = attr->value;
+ else
+ field_type_id = NULL;
+
+ attr = xml_find_attribute (attributes, "start");
+ if (attr != NULL)
+ start = * (ULONGEST *) attr->value;
+ else
+ start = -1;
- append_composite_type_field (data->current_union, xstrdup (field_name),
- field_type);
+ attr = xml_find_attribute (attributes, "end");
+ if (attr != NULL)
+ end = * (ULONGEST *) attr->value;
+ else
+ end = -1;
+
+ if (field_type_id != NULL)
+ {
+ if (data->current_type_is_flags)
+ gdb_xml_error (parser, _("Cannot add typed field \"%s\" to flags"),
+ field_name);
+ if (data->current_type_size != 0)
+ gdb_xml_error (parser,
+ _("Explicitly sized type can not "
+ "contain non-bitfield \"%s\""),
+ field_name);
+
+ field_type = tdesc_named_type (data->current_feature, field_type_id);
+ 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 if (start != -1 && end != -1)
+ {
+ struct tdesc_type *t = data->current_type;
+
+ if (data->current_type_is_flags)
+ tdesc_add_flag (t, start, field_name);
+ else
+ {
+ if (data->current_type_size == 0)
+ gdb_xml_error (parser,
+ _("Implicitly sized type can "
+ "not contain bitfield \"%s\""),
+ field_name);
+
+ 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"));
+
+ tdesc_add_bitfield (t, field_name, start, end);
+ }
+ }
+ else
+ gdb_xml_error (parser, _("Field \"%s\" has neither type nor bit position"),
+ field_name);
}
/* Handle the start of a <vector> element. Initialize the type and
{
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_type *field_type;
char *id, *field_type_id;
int count;
gdb_xml_error (parser, _("Vector \"%s\" references undefined type \"%s\""),
id, field_type_id);
- /* A vector is just an array plus a special flag. */
- range_type = create_range_type (NULL, builtin_type_int, 0, count - 1);
- type = create_array_type (NULL, field_type, range_type);
- TYPE_NAME (type) = xstrdup (id);
-
- TYPE_FLAGS (type) |= TYPE_FLAG_VECTOR;
-
- 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_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 }
{ 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 }
};
{ "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, tdesc_end_union },
+ tdesc_start_union, NULL },
+ { "flags", flags_attributes, struct_union_children,
+ GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
+ tdesc_start_flags, NULL },
{ "vector", vector_attributes, NULL,
GDB_XML_EF_OPTIONAL | GDB_XML_EF_REPEATABLE,
tdesc_start_vector, NULL },
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 },
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;
}
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");
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);
- if (gdb_xml_parse (parser, expanded_text) == 0)
+ if (gdb_xml_parse_quick (_("target description"), "gdb-target.dtd",
+ tdesc_elements, expanded_text, &data) == 0)
{
/* Parsed successfully. */
struct tdesc_xml_cache new_cache;
#endif /* HAVE_LIBEXPAT */
\f
-/* Close FILE. */
-
-static void
-do_cleanup_fclose (void *file)
-{
- fclose (file);
-}
-
-/* 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, 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 (do_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. */
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);
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;