Create xml from target descriptions

Add a print_xml_feature visitor class which turns a
target description into xml. Both gdb and gdbserver can do this.

gdb/
	* common/tdesc.c (print_xml_feature::visit_pre): Add xml parsing.
	(print_xml_feature::visit_post): Likewise.
	(print_xml_feature::visit): Likewise.
	* common/tdesc.h (tdesc_get_features_xml): Use const tdesc.
	(print_xml_feature): Add new class.
	* regformats/regdat.sh: Null xmltarget on feature targets.
	* target-descriptions.c (struct target_desc): Add xmltarget.
	(maintenance_check_tdesc_xml_convert): Add unittest function.
	(tdesc_get_features_xml): Add function to get xml.
	(maintenance_check_xml_descriptions): Test xml generation.
	* xml-tdesc.c (string_read_description_xml): Add function.
	* xml-tdesc.h (string_read_description_xml): Add declaration.

gdbserver/
	* gdb/gdbserver/server.c (get_features_xml): Remove cast.
	* tdesc.c (void target_desc::accept): Fill in function.
	(tdesc_get_features_xml): Remove old xml creation.
	(print_xml_feature::visit_pre): Add xml vistor.
	* tdesc.h (struct target_desc): Make xmltarget mutable.
	(tdesc_get_features_xml): Remove declaration.
This commit is contained in:
Alan Hayward
2018-04-18 20:09:12 +01:00
parent ad7fc756d1
commit e98577a9dc
11 changed files with 260 additions and 38 deletions

View File

@ -1,3 +1,18 @@
2018-04-18 Alan Hayward <alan.hayward@arm.com>
* common/tdesc.c (print_xml_feature::visit_pre): Add xml parsing.
(print_xml_feature::visit_post): Likewise.
(print_xml_feature::visit): Likewise.
* common/tdesc.h (tdesc_get_features_xml): Use const tdesc.
(print_xml_feature): Add new class.
* regformats/regdat.sh: Null xmltarget on feature targets.
* target-descriptions.c (struct target_desc): Add xmltarget.
(maintenance_check_tdesc_xml_convert): Add unittest function.
(tdesc_get_features_xml): Add function to get xml.
(maintenance_check_xml_descriptions): Test xml generation.
* xml-tdesc.c (string_read_description_xml): Add function.
* xml-tdesc.h (string_read_description_xml): Add declaration.
2018-04-18 Alan Hayward <alan.hayward@arm.com>
* features/Makefile: Add feature marker to targets with new style

View File

@ -290,3 +290,112 @@ tdesc_add_enum_value (tdesc_type_with_fields *type, int value,
tdesc_predefined_type (TDESC_TYPE_INT32),
value, -1);
}
void print_xml_feature::visit_pre (const tdesc_feature *e)
{
string_appendf (*m_buffer, "<feature name=\"%s\">\n", e->name.c_str ());
}
void print_xml_feature::visit_post (const tdesc_feature *e)
{
string_appendf (*m_buffer, "</feature>\n");
}
void print_xml_feature::visit (const tdesc_type_builtin *t)
{
error (_("xml output is not supported for type \"%s\"."), t->name.c_str ());
}
void print_xml_feature::visit (const tdesc_type_vector *t)
{
string_appendf (*m_buffer, "<vector id=\"%s\" type=\"%s\" count=\"%d\"/>\n",
t->name.c_str (), t->element_type->name.c_str (), t->count);
}
void print_xml_feature::visit (const tdesc_type_with_fields *t)
{
struct tdesc_type_field *f;
const static char *types[] = { "struct", "union", "flags", "enum" };
gdb_assert (t->kind >= TDESC_TYPE_STRUCT && t->kind <= TDESC_TYPE_ENUM);
string_appendf (*m_buffer,
"<%s id=\"%s\"", types[t->kind - TDESC_TYPE_STRUCT],
t->name.c_str ());
switch (t->kind)
{
case TDESC_TYPE_STRUCT:
case TDESC_TYPE_FLAGS:
if (t->size > 0)
string_appendf (*m_buffer, " size=\"%d\"", t->size);
string_appendf (*m_buffer, ">\n");
for (const tdesc_type_field &f : t->fields)
{
string_appendf (*m_buffer, " <field name=\"%s\" ", f.name.c_str ());
if (f.start == -1)
string_appendf (*m_buffer, "type=\"%s\"/>\n",
f.type->name.c_str ());
else
string_appendf (*m_buffer, "start=\"%d\" end=\"%d\"/>\n", f.start,
f.end);
}
break;
case TDESC_TYPE_ENUM:
string_appendf (*m_buffer, ">\n");
for (const tdesc_type_field &f : t->fields)
string_appendf (*m_buffer, " <field name=\"%s\" start=\"%d\"/>\n",
f.name.c_str (), f.start);
break;
case TDESC_TYPE_UNION:
string_appendf (*m_buffer, ">\n");
for (const tdesc_type_field &f : t->fields)
string_appendf (*m_buffer, " <field name=\"%s\" type=\"%s\"/>\n",
f.name.c_str (), f.type->name.c_str ());
break;
default:
error (_("xml output is not supported for type \"%s\"."),
t->name.c_str ());
}
string_appendf (*m_buffer, "</%s>\n", types[t->kind - TDESC_TYPE_STRUCT]);
}
void print_xml_feature::visit (const tdesc_reg *r)
{
string_appendf (*m_buffer,
"<reg name=\"%s\" bitsize=\"%d\" type=\"%s\" regnum=\"%ld\"",
r->name.c_str (), r->bitsize, r->type.c_str (),
r->target_regnum);
if (r->group.length () > 0)
string_appendf (*m_buffer, " group=\"%s\"", r->group.c_str ());
if (r->save_restore == 0)
string_appendf (*m_buffer, " save-restore=\"no\"");
string_appendf (*m_buffer, "/>\n");
}
void print_xml_feature::visit_pre (const target_desc *e)
{
#ifndef IN_PROCESS_AGENT
string_appendf (*m_buffer, "<?xml version=\"1.0\"?>\n");
string_appendf (*m_buffer, "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">\n");
string_appendf (*m_buffer, "<target>\n<architecture>%s</architecture>\n",
tdesc_architecture_name (e));
const char *osabi = tdesc_osabi_name (e);
if (osabi != nullptr)
string_appendf (*m_buffer, "<osabi>%s</osabi>", osabi);
#endif
}
void print_xml_feature::visit_post (const target_desc *e)
{
string_appendf (*m_buffer, "</target>\n");
}

View File

@ -380,4 +380,30 @@ void tdesc_create_reg (struct tdesc_feature *feature, const char *name,
int regnum, int save_restore, const char *group,
int bitsize, const char *type);
/* Return the tdesc in string XML format. */
const char *tdesc_get_features_xml (const target_desc *tdesc);
/* Print target description as xml. */
class print_xml_feature : public tdesc_element_visitor
{
public:
print_xml_feature (std::string *buffer_)
: m_buffer (buffer_)
{}
void visit_pre (const target_desc *e) override;
void visit_post (const target_desc *e) override;
void visit_pre (const tdesc_feature *e) override;
void visit_post (const tdesc_feature *e) override;
void visit (const tdesc_type_builtin *type) override;
void visit (const tdesc_type_vector *type) override;
void visit (const tdesc_type_with_fields *type) override;
void visit (const tdesc_reg *reg) override;
private:
std::string *m_buffer;
};
#endif /* ARCH_TDESC_H */

View File

@ -1,3 +1,12 @@
2018-04-18 Alan Hayward <alan.hayward@arm.com>
* server.c (get_features_xml): Remove cast.
* tdesc.c (void target_desc::accept): Fill in function.
(tdesc_get_features_xml): Remove old xml creation.
(print_xml_feature::visit_pre): Add xml vistor.
* tdesc.h (struct target_desc): Make xmltarget mutable.
(tdesc_get_features_xml): Remove declaration.
2018-04-18 Alan Hayward <alan.hayward@arm.com>
* tdesc.c (tdesc_architecture_name): Add new function.

View File

@ -940,7 +940,7 @@ get_features_xml (const char *annex)
if (strcmp (annex, "target.xml") == 0)
{
const char *ret = tdesc_get_features_xml ((target_desc*) desc);
const char *ret = tdesc_get_features_xml (desc);
if (*ret == '@')
return ret + 1;

View File

@ -47,6 +47,18 @@ bool target_desc::operator== (const target_desc &other) const
#endif
void target_desc::accept (tdesc_element_visitor &v) const
{
#ifndef IN_PROCESS_AGENT
v.visit_pre (this);
for (const tdesc_feature_up &feature : features)
feature->accept (v);
v.visit_post (this);
#endif
}
void
init_target_desc (struct target_desc *tdesc)
{
@ -138,11 +150,10 @@ set_tdesc_osabi (struct target_desc *target_desc, const char *name)
target_desc->osabi = xstrdup (name);
}
/* Return a string which is of XML format, including XML target
description to be sent to GDB. */
/* See common/tdesc.h. */
const char *
tdesc_get_features_xml (target_desc *tdesc)
tdesc_get_features_xml (const target_desc *tdesc)
{
/* Either .xmltarget or .features is not NULL. */
gdb_assert (tdesc->xmltarget != NULL
@ -151,31 +162,9 @@ tdesc_get_features_xml (target_desc *tdesc)
if (tdesc->xmltarget == NULL)
{
std::string buffer ("@<?xml version=\"1.0\"?>");
buffer += "<!DOCTYPE target SYSTEM \"gdb-target.dtd\">";
buffer += "<target>";
buffer += "<architecture>";
buffer += tdesc_architecture_name (tdesc);
buffer += "</architecture>";
const char *osabi = tdesc_osabi_name (tdesc);
if (osabi != nullptr)
{
buffer += "<osabi>";
buffer += osabi;
buffer += "</osabi>";
}
for (const tdesc_feature_up &feature : tdesc->features)
{
buffer += "<xi:include href=\"";
buffer += feature->name;
buffer += "\"/>";
}
buffer += "</target>";
std::string buffer ("@");
print_xml_feature v (&buffer);
tdesc->accept (v);
tdesc->xmltarget = xstrdup (buffer.c_str ());
}

View File

@ -27,7 +27,7 @@
/* A target description. Inherit from tdesc_feature so that target_desc
can be used as tdesc_feature. */
struct target_desc
struct target_desc : tdesc_element
{
/* A vector of elements of register definitions that
describe the inferior's register set. */
@ -49,9 +49,9 @@ struct target_desc
verbatim XML code (prefixed with a '@') or else the name of the
actual XML file to be used in place of "target.xml".
It can be NULL, then, its content is got from the following three
fields features, arch, and osabi in tdesc_get_features_xml. */
const char *xmltarget = NULL;
If NULL then its content will be generated by parsing the target
description into xml. */
mutable const char *xmltarget = NULL;
/* The value of <architecture> element in the XML, replying GDB. */
const char *arch = NULL;
@ -73,6 +73,8 @@ public:
return !(*this == other);
}
#endif
void accept (tdesc_element_visitor &v) const override;
};
/* Copy target description SRC to DEST. */
@ -89,8 +91,4 @@ void init_target_desc (struct target_desc *tdesc);
const struct target_desc *current_target_desc (void);
#ifndef IN_PROCESS_AGENT
const char *tdesc_get_features_xml (struct target_desc *tdesc);
#endif
#endif /* TDESC_H */

View File

@ -163,7 +163,9 @@ done
echo
echo "static const char *expedite_regs_${name}[] = { \"`echo ${expedite} | sed 's/,/", "/g'`\", 0 };"
if test "${xmltarget}" = x; then
if test "${feature}" != x; then
echo "static const char *xmltarget_${name} = 0;"
elif test "${xmltarget}" = x; then
if test "${xmlarch}" = x && test "${xmlosabi}" = x; then
echo "static const char *xmltarget_${name} = 0;"
else

View File

@ -333,6 +333,9 @@ struct target_desc : tdesc_element
/* The features associated with this target. */
std::vector<tdesc_feature_up> features;
/* Used to cache the generated xml version of the target description. */
mutable char *xmltarget = nullptr;
void accept (tdesc_element_visitor &v) const override
{
v.visit_pre (this);
@ -1667,6 +1670,21 @@ private:
int m_next_regnum = 0;
};
/* See common/tdesc.h. */
const char *
tdesc_get_features_xml (const target_desc *tdesc)
{
if (tdesc->xmltarget == nullptr)
{
std::string buffer ("@");
print_xml_feature v (&buffer);
tdesc->accept (v);
tdesc->xmltarget = xstrdup (buffer.c_str ());
}
return tdesc->xmltarget;
}
static void
maint_print_c_tdesc_cmd (const char *args, int from_tty)
{
@ -1739,6 +1757,39 @@ record_xml_tdesc (const char *xml_file, const struct target_desc *tdesc)
}
/* Test the convesion process of a target description to/from xml: Take a target
description TDESC, convert to xml, back to a description, and confirm the new
tdesc is identical to the original. */
static bool
maintenance_check_tdesc_xml_convert (const target_desc *tdesc, const char *name)
{
const char *xml = tdesc_get_features_xml (tdesc);
if (xml == nullptr || *xml != '@')
{
printf_filtered (_("Could not convert description for %s to xml.\n"),
name);
return false;
}
const target_desc *tdesc_trans = string_read_description_xml (xml + 1);
if (tdesc_trans == nullptr)
{
printf_filtered (_("Could not convert description for %s from xml.\n"),
name);
return false;
}
else if (*tdesc != *tdesc_trans)
{
printf_filtered (_("Converted description for %s does not match.\n"),
name);
return false;
}
return true;
}
/* Check that the target descriptions created dynamically by
architecture-specific code equal the descriptions created from XML files
found in the specified directory DIR. */
@ -1760,6 +1811,12 @@ maintenance_check_xml_descriptions (const char *dir, int from_tty)
= file_read_description_xml (tdesc_xml.data ());
if (tdesc == NULL || *tdesc != *e.second)
{
printf_filtered ( _("Descriptions for %s do not match.\n"), e.first);
failed++;
}
else if (!maintenance_check_tdesc_xml_convert (tdesc, e.first)
|| !maintenance_check_tdesc_xml_convert (e.second, e.first))
failed++;
}
printf_filtered (_("Tested %lu XML files, %d failed\n"),

View File

@ -752,3 +752,15 @@ target_fetch_description_xml (struct target_ops *ops)
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<gdb::char_vector> ();
}, nullptr);
}

View File

@ -44,5 +44,10 @@ const struct target_desc *target_read_description_xml (struct target_ops *);
otherwise. */
gdb::optional<std::string> target_fetch_description_xml (target_ops *ops);
/* Take an xml string, parse it, and return the parsed description. Does not
handle a string containing includes. */
const struct target_desc *string_read_description_xml (const char *xml);
#endif /* XML_TDESC_H */