diff options
-rw-r--r-- | gdb/ChangeLog | 9 | ||||
-rw-r--r-- | gdb/NEWS | 6 | ||||
-rw-r--r-- | gdb/doc/ChangeLog | 5 | ||||
-rw-r--r-- | gdb/doc/gdb.texinfo | 9 | ||||
-rw-r--r-- | gdb/target-descriptions.c | 39 | ||||
-rw-r--r-- | gdb/testsuite/ChangeLog | 8 | ||||
-rw-r--r-- | gdb/testsuite/gdb.xml/maint-xml-dump-01.xml | 10 | ||||
-rw-r--r-- | gdb/testsuite/gdb.xml/maint-xml-dump-02.xml | 27 | ||||
-rw-r--r-- | gdb/testsuite/gdb.xml/maint-xml-dump.exp | 124 | ||||
-rw-r--r-- | gdb/testsuite/gdb.xml/tdesc-reload.c | 22 | ||||
-rw-r--r-- | gdb/testsuite/gdb.xml/tdesc-reload.exp | 83 | ||||
-rw-r--r-- | gdbsupport/ChangeLog | 13 | ||||
-rw-r--r-- | gdbsupport/tdesc.cc | 104 | ||||
-rw-r--r-- | gdbsupport/tdesc.h | 23 |
14 files changed, 448 insertions, 34 deletions
diff --git a/gdb/ChangeLog b/gdb/ChangeLog index 0784e82..57bd323 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,5 +1,14 @@ 2020-06-23 Andrew Burgess <andrew.burgess@embecosm.com> + * target-descriptions.c (tdesc_architecture_name): Protect against + NULL pointer dereference. + (maint_print_xml_tdesc_cmd): New function. + (_initialize_target_descriptions): Register new 'maint print + xml-tdesc' command and give it the filename completer. + * NEWS: Mention new 'maint print xml-tdesc' command. + +2020-06-23 Andrew Burgess <andrew.burgess@embecosm.com> + * target-descriptions.c (class tdesc_compatible_info): New class. (struct target_desc): Change type of compatible vector. (tdesc_compatible_p): Update for change in type of @@ -79,6 +79,12 @@ tui new-layout NAME WINDOW WEIGHT [WINDOW WEIGHT]... Define a new TUI layout, specifying its name and the windows that will be displayed. +maintenance print xml-tdesc [FILE] + Prints the current target description as an XML document. If the + optional FILE is provided (which is an XML target description) then + the target description is read from FILE into GDB, and then + reprinted. + * Changed commands alias [-a] [--] ALIAS = COMMAND [DEFAULT-ARGS...] diff --git a/gdb/doc/ChangeLog b/gdb/doc/ChangeLog index fe6bfe7..4b1a4c0 100644 --- a/gdb/doc/ChangeLog +++ b/gdb/doc/ChangeLog @@ -1,3 +1,8 @@ +2020-06-23 Andrew Burgess <andrew.burgess@embecosm.com> + + * gdb.texinfo (Maintenance Commands): Document new 'maint print + xml-desc' command. + 2020-06-22 Philippe Waroquiers <philippe.waroquiers@skynet.be> * gdb.texinfo (Command aliases default args): New node documenting diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 7f572c3..7f8c77a 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -38501,6 +38501,15 @@ The created source file is built into @value{GDBN} when @value{GDBN} is built again. This command is used by developers after they add or modify XML target descriptions. +@kindex maint print xml-tdesc +@item maint print xml-tdesc @r{[}@var{file}@r{]} +Print the target description (@pxref{Target Descriptions}) as an XML +file. By default print the target description for the current target, +but if the optional argument @var{file} is provided, then that file is +read in by GDB and then used to produce the description. The +@var{file} should be an XML document, of the form described in +@ref{Target Description Format}. + @kindex maint check xml-descriptions @item maint check xml-descriptions @var{dir} Check that the target descriptions dynamically created by @value{GDBN} diff --git a/gdb/target-descriptions.c b/gdb/target-descriptions.c index 1937e7c..1abdf51 100644 --- a/gdb/target-descriptions.c +++ b/gdb/target-descriptions.c @@ -662,7 +662,9 @@ tdesc_architecture (const struct target_desc *target_desc) const char * tdesc_architecture_name (const struct target_desc *target_desc) { - return target_desc->arch->printable_name; + if (target_desc->arch != NULL) + return target_desc->arch->printable_name; + return NULL; } /* See gdbsupport/tdesc.h. */ @@ -1755,6 +1757,36 @@ maint_print_c_tdesc_cmd (const char *args, int from_tty) } } +/* Implement the maintenance print xml-tdesc command. */ + +static void +maint_print_xml_tdesc_cmd (const char *args, int from_tty) +{ + const struct target_desc *tdesc; + + if (args == NULL) + { + /* Use the global target-supplied description, not the current + architecture's. This lets a GDB for one architecture generate XML + for another architecture's description, even though the gdbarch + initialization code will reject the new description. */ + tdesc = current_target_desc; + } + else + { + /* Use the target description from the XML file. */ + tdesc = file_read_description_xml (args); + } + + if (tdesc == NULL) + error (_("There is no target description to print.")); + + std::string buf; + print_xml_feature v (&buf); + tdesc->accept (v); + puts_unfiltered (buf.c_str ()); +} + namespace selftests { /* A reference target description, used for testing (see record_xml_tdesc). */ @@ -1892,6 +1924,11 @@ Print the current target description as a C source file."), &maintenanceprintlist); set_cmd_completer (cmd, filename_completer); + cmd = add_cmd ("xml-tdesc", class_maintenance, maint_print_xml_tdesc_cmd, _("\ +Print the current target description as an XML file."), + &maintenanceprintlist); + set_cmd_completer (cmd, filename_completer); + cmd = add_cmd ("xml-descriptions", class_maintenance, maintenance_check_xml_descriptions, _("\ Check equality of GDB target descriptions and XML created descriptions.\n\ diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog index 0864d75..26284da 100644 --- a/gdb/testsuite/ChangeLog +++ b/gdb/testsuite/ChangeLog @@ -1,3 +1,11 @@ +2020-06-23 Andrew Burgess <andrew.burgess@embecosm.com> + + * gdb.xml/tdesc-reload.c: New file. + * gdb.xml/tdesc-reload.exp: New file. + * gdb.xml/maint-xml-dump-01.xml: New file. + * gdb.xml/maint-xml-dump-02.xml: New file. + * gdb.xml/maint-xml-dump.exp: New file. + 2020-06-23 Sandra Loosemore <sandra@codesourcery.com> * lib/completion-support.exp (test_gdb_completion_offers_commands): diff --git a/gdb/testsuite/gdb.xml/maint-xml-dump-01.xml b/gdb/testsuite/gdb.xml/maint-xml-dump-01.xml new file mode 100644 index 0000000..dd4f925 --- /dev/null +++ b/gdb/testsuite/gdb.xml/maint-xml-dump-01.xml @@ -0,0 +1,10 @@ +<?xml version="1.0"?> +<!-- This is a comment before DOCTYPE --> +<!DOCTYPE target SYSTEM "gdb-target.dtd"> +<!-- This is a comment after DOCTYPE --> +<target> + <feature name="abc"> + <!-- The following is a register. --> + <reg name="r1" bitsize="32"/> <!-- <reg name="r1" bitsize="32" type="int" regnum="0"/> --> + </feature> +</target> diff --git a/gdb/testsuite/gdb.xml/maint-xml-dump-02.xml b/gdb/testsuite/gdb.xml/maint-xml-dump-02.xml new file mode 100644 index 0000000..c192294 --- /dev/null +++ b/gdb/testsuite/gdb.xml/maint-xml-dump-02.xml @@ -0,0 +1,27 @@ +<target> + <osabi>Solaris</osabi> + <feature name="abc"> + <vector id="foo" type="int32" count="4"/> + <reg name="foo" bitsize="16" /> <!-- <reg name="foo" bitsize="16" type="int" regnum="0"/> --> + </feature> + <feature name="def.xyz"> + <struct id="my_struct"> + <field name="field1" type="int8"/> + <field name="field2" type="int16"/> + <field name="field3" type="int8"/> + </struct> + <struct id="bit_field" size="8"> + <field name="bits1" start="0" end="3" type="int8"/> + <field name="bits2" start="4" end="6" type="int8"/> + <field name="bits3" start="7" end="7"/> <!-- <field name="bits3" start="7" end="7" type="bool"/> --> + </struct> + <flags id="my_flags" size="8"> + <field name="flg1" start="0" end="0"/> <!-- <field name="flg1" start="0" end="0" type="bool"/> --> + <field name="flg2" start="1" end="1"/> <!-- <field name="flg2" start="1" end="1" type="bool"/> --> + <field name="flg3" start="2" end="6"/> <!-- <field name="flg3" start="2" end="6" type="uint64"/> --> + <field name="flg4" start="7" end="7"/> <!-- <field name="flg4" start="7" end="7" type="bool"/> --> + </flags> + <reg name="r1" bitsize="8" type="my_flags"/> <!-- <reg name="r1" bitsize="8" type="my_flags" regnum="1"/> --> + <reg name="r2" bitsize="8" type="bit_field"/> <!-- <reg name="r2" bitsize="8" type="bit_field" regnum="2"/> --> + </feature> +</target> diff --git a/gdb/testsuite/gdb.xml/maint-xml-dump.exp b/gdb/testsuite/gdb.xml/maint-xml-dump.exp new file mode 100644 index 0000000..8ccfbb5 --- /dev/null +++ b/gdb/testsuite/gdb.xml/maint-xml-dump.exp @@ -0,0 +1,124 @@ +# Copyright 2020 Free Software Foundation, Inc. + +# 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# 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, see <http://www.gnu.org/licenses/>. + +# Test the 'maint print xml-tdesc' command. This file picks up every +# XML file matching the pattern maint-xml-dump-*.xml (in the same +# directory as this script) and passes each in turn to the command +# 'maint print xml-tdesc'. +# +# The expected output is generated by parsing the input XML file. The +# rules for changing an XML file into the expected output are: +# +# 1. Blank lines, and lines starting with a comment are stripped from +# the expected output. +# +# 2. The <?xml ... ?> and <!DOCTYPE ...> entities are optional, +# suitable defaults will be added if these lines are missing from +# the input file. +# +# 3. A trailing comment on a line will replace the expected output for +# that line but with the indentation of the line preserved. So +# this (The '|' marks the start of the line): +# | <reg name="r1" bitsize="32"/> <!-- <reg name="r1" bitsize="32" type="int" regnum="0"/> --> +# Will actually look for the following output: +# | <reg name="r1" bitsize="32" type="int" regnum="0"/> +# +# 4. Indentation of lines will be preserved so your input file needs +# to follow the expected indentation. +if {[gdb_skip_xml_test]} { + unsupported "xml tests not being run" + return -1 +} + +gdb_start + +# Read the XML file FILENAME and produce an output pattern that should +# match what GDB produces with the 'maint print xml-desc' command. +proc build_pattern { filename } { + set pattern {} + + set xml_version_line {<?xml version="1.0"?>} + set doc_type_line {<!DOCTYPE target SYSTEM "gdb-target.dtd">} + + set linenum 0 + set ifd [open "$filename" r] + while {[gets $ifd line] >= 0} { + incr linenum + + # The <?xml .... ?> tag can only appear as the first line in + # the file. If it is not present then add one to the expected + # output now. + if {$linenum == 1} { + if {![regexp {^<\?xml} $line]} { + set pattern [string_to_regexp $xml_version_line] + set xml_version_line "" + } + } + + # If we have not yet seen a DOCTYPE line, then maybe we should + # be adding one? If we find <target> then add a default + # DOCTYPE line, otherwise, if the XML file includes a DOCTYPE + # line, use that. + if {$doc_type_line != "" } { + if {[regexp {^[ \t]*<target>} $line]} { + set pattern [multi_line $pattern \ + [string_to_regexp $doc_type_line]] + set doc_type_line "" + } elseif {[regexp {^[ \t]*<!DOCTYPE } $line]} { + set doc_type_line "" + } + } + + if {[regexp {^[ \t]*<!--} $line]} { + # Comment line, ignore it. + } elseif {[regexp {^[ \t]+$} $line]} { + # Blank line, ignore it. + } elseif {[regexp {^([ \t]*).*<!-- (.*) -->$} $line \ + matches grp1 grp2]} { + set pattern [multi_line \ + $pattern \ + [string_to_regexp "$grp1$grp2"]] + } else { + set pattern [multi_line \ + $pattern \ + [string_to_regexp $line]] + } + } + close $ifd + + # Due to handling the <?xml ...?> tags we can end up with a stray + # '\r\n' at the start of the output pattern. Remove it here. + if {[string range $pattern 0 1] == "\r\n"} { + set pattern [string range $pattern 2 end] + } + + return $pattern +} + +# Run over every test XML file and check the output. +foreach filename [lsort [glob $srcdir/$subdir/maint-xml-dump-*.xml]] { + set pattern [build_pattern $filename] + + if {[is_remote host]} { + set test_path [remote_download host $filename] + } else { + set test_path $filename + } + + verbose -log "Looking for:\n$pattern" + + gdb_test "maint print xml-tdesc $test_path" \ + "$pattern" "check [file tail $filename]" +} diff --git a/gdb/testsuite/gdb.xml/tdesc-reload.c b/gdb/testsuite/gdb.xml/tdesc-reload.c new file mode 100644 index 0000000..f4825c8 --- /dev/null +++ b/gdb/testsuite/gdb.xml/tdesc-reload.c @@ -0,0 +1,22 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2020 Free Software Foundation, Inc. + + 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 3 of the License, or + (at your option) any later version. + + This program is distributed in the hope that it will be useful, + but WITHOUT ANY WARRANTY; without even the implied warranty of + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + 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, see <http://www.gnu.org/licenses/>. */ + +int +main () +{ + return 0; +} diff --git a/gdb/testsuite/gdb.xml/tdesc-reload.exp b/gdb/testsuite/gdb.xml/tdesc-reload.exp new file mode 100644 index 0000000..a671297 --- /dev/null +++ b/gdb/testsuite/gdb.xml/tdesc-reload.exp @@ -0,0 +1,83 @@ +# Copyright 2020 Free Software Foundation, Inc. + +# 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 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# 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, see <http://www.gnu.org/licenses/>. + +# Testing for 'maint print xml-tdesc'. Check we can print out the +# current target description and load it back in again. + +if {[gdb_skip_xml_test]} { + unsupported "xml tests not being run" + return -1 +} + +standard_testfile + +if {[prepare_for_testing "failed to prepare" $testfile $srcfile debug]} { + return -1 +} + +if ![runto_main] then { + fail "can't run to main" + return 0 +} + +# Three files we're going to write out to. +set xml_file_1 [standard_output_file outfile1.xml] +set xml_file_2 [standard_output_file outfile2.xml] +set xml_file_3 [standard_output_file outfile3.xml] + +# Write the current target description to a file. +gdb_test_no_output "pipe maint print xml-tdesc | cat > $xml_file_1" \ + "write current target description to file" + +# Read the target description back in to GDB, and the write it back +# out to a file. +gdb_test_no_output \ + "pipe maint print xml-tdesc $xml_file_1 | cat > $xml_file_2" \ + "read previous xml description, and write it out to a second file" + +# Check the two produced files are identical. +gdb_test "shell diff -s $xml_file_1 $xml_file_2" \ + "Files \[^\r\n\]* are identical" \ + "first two produced xml files are identical" + +# Restart GDB. +clean_restart + +# Change to use one of the target descriptions we wrote out earlier. +gdb_test_no_output "set tdesc filename $xml_file_1" \ + "set target description to use" + +# Load the executable. +gdb_load ${binfile} + +# Run to `main' where we begin our tests. +if ![runto_main] then { + untested "could not run to main" + return -1 +} + +# Run info registers just to check this appears to run fine with the +# new target description. +gdb_test "info all-registers" ".*" \ + "Run info registers" + +# Write out the current target description. +gdb_test_no_output "pipe maint print xml-tdesc | cat > $xml_file_3" \ + "write third target description to file" + +# And check that it matches the original file we loaded. +gdb_test "shell diff -s $xml_file_1 $xml_file_3" \ + "Files \[^\r\n\]* are identical" \ + "first and third produced xml files are identical" diff --git a/gdbsupport/ChangeLog b/gdbsupport/ChangeLog index 2e5cbba..b2fbc56 100644 --- a/gdbsupport/ChangeLog +++ b/gdbsupport/ChangeLog @@ -1,5 +1,18 @@ 2020-06-23 Andrew Burgess <andrew.burgess@embecosm.com> + * tdesc.cc (print_xml_feature::visit_pre): Use add_line to add + output content, and call indent as needed in all overloaded + variants. + (print_xml_feature::visit_post): Likewise. + (print_xml_feature::visit): Likewise. + (print_xml_feature::add_line): Two new overloaded functions. + * tdesc.h (print_xml_feature::indent): New member function. + (print_xml_feature::add_line): Two new overloaded member + functions. + (print_xml_feature::m_depth): New member variable. + +2020-06-23 Andrew Burgess <andrew.burgess@embecosm.com> + * tdesc.cc (print_xml_feature::visit_pre): Print compatible information. * tdesc.h (struct tdesc_compatible_info): Declare new struct. diff --git a/gdbsupport/tdesc.cc b/gdbsupport/tdesc.cc index 63f41cb..624588b 100644 --- a/gdbsupport/tdesc.cc +++ b/gdbsupport/tdesc.cc @@ -294,12 +294,14 @@ tdesc_add_enum_value (tdesc_type_with_fields *type, int value, void print_xml_feature::visit_pre (const tdesc_feature *e) { - string_appendf (*m_buffer, "<feature name=\"%s\">\n", e->name.c_str ()); + add_line ("<feature name=\"%s\">", e->name.c_str ()); + indent (1); } void print_xml_feature::visit_post (const tdesc_feature *e) { - string_appendf (*m_buffer, "</feature>\n"); + indent (-1); + add_line ("</feature>"); } void print_xml_feature::visit (const tdesc_type_builtin *t) @@ -309,8 +311,8 @@ void print_xml_feature::visit (const tdesc_type_builtin *t) 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); + add_line ("<vector id=\"%s\" type=\"%s\" count=\"%d\"/>", + t->name.c_str (), t->element_type->name.c_str (), t->count); } void print_xml_feature::visit (const tdesc_type_with_fields *t) @@ -319,7 +321,9 @@ void print_xml_feature::visit (const tdesc_type_with_fields *t) gdb_assert (t->kind >= TDESC_TYPE_STRUCT && t->kind <= TDESC_TYPE_ENUM); - string_appendf (*m_buffer, + std::string tmp; + + string_appendf (tmp, "<%s id=\"%s\"", types[t->kind - TDESC_TYPE_STRUCT], t->name.c_str ()); @@ -328,33 +332,37 @@ void print_xml_feature::visit (const tdesc_type_with_fields *t) 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"); + string_appendf (tmp, " size=\"%d\"", t->size); + string_appendf (tmp, ">"); + add_line (tmp); 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, + tmp.clear (); + string_appendf (tmp, " <field name=\"%s\"", f.name.c_str ()); + if (f.start != -1) + string_appendf (tmp, " start=\"%d\" end=\"%d\"", f.start, f.end); + string_appendf (tmp, " type=\"%s\"/>", + f.type->name.c_str ()); + add_line (tmp); } break; case TDESC_TYPE_ENUM: - string_appendf (*m_buffer, ">\n"); + string_appendf (tmp, ">"); + add_line (tmp); for (const tdesc_type_field &f : t->fields) - string_appendf (*m_buffer, " <field name=\"%s\" start=\"%d\"/>\n", - f.name.c_str (), f.start); + add_line (" <field name=\"%s\" start=\"%d\"/>", + f.name.c_str (), f.start); break; case TDESC_TYPE_UNION: - string_appendf (*m_buffer, ">\n"); + string_appendf (tmp, ">"); + add_line (tmp); 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 ()); + add_line (" <field name=\"%s\" type=\"%s\"/>", + f.name.c_str (), f.type->name.c_str ()); break; default: @@ -362,46 +370,78 @@ void print_xml_feature::visit (const tdesc_type_with_fields *t) t->name.c_str ()); } - string_appendf (*m_buffer, "</%s>\n", types[t->kind - TDESC_TYPE_STRUCT]); + add_line ("</%s>", types[t->kind - TDESC_TYPE_STRUCT]); } void print_xml_feature::visit (const tdesc_reg *r) { - string_appendf (*m_buffer, + std::string tmp; + + string_appendf (tmp, "<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 ()); + string_appendf (tmp, " group=\"%s\"", r->group.c_str ()); if (r->save_restore == 0) - string_appendf (*m_buffer, " save-restore=\"no\""); + string_appendf (tmp, " save-restore=\"no\""); - string_appendf (*m_buffer, "/>\n"); + string_appendf (tmp, "/>"); + + add_line (tmp); } 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)); + add_line ("<?xml version=\"1.0\"?>"); + add_line ("<!DOCTYPE target SYSTEM \"gdb-target.dtd\">"); + add_line ("<target>"); + indent (1); + if (tdesc_architecture_name (e)) + add_line ("<architecture>%s</architecture>", + tdesc_architecture_name (e)); const char *osabi = tdesc_osabi_name (e); if (osabi != nullptr) - string_appendf (*m_buffer, "<osabi>%s</osabi>", osabi); + add_line ("<osabi>%s</osabi>", osabi); const std::vector<tdesc_compatible_info_up> &compatible_list = tdesc_compatible_info_list (e); for (const auto &c : compatible_list) - string_appendf (*m_buffer, "<compatible>%s</compatible>\n", - tdesc_compatible_info_arch_name (c)); + add_line ("<compatible>%s</compatible>", + tdesc_compatible_info_arch_name (c)); #endif } void print_xml_feature::visit_post (const target_desc *e) { - string_appendf (*m_buffer, "</target>\n"); + indent (-1); + add_line ("</target>"); +} + +/* See gdbsupport/tdesc.h. */ + +void +print_xml_feature::add_line (const std::string &str) +{ + string_appendf (*m_buffer, "%*s", m_depth, ""); + string_appendf (*m_buffer, "%s", str.c_str ()); + string_appendf (*m_buffer, "\n"); +} + +/* See gdbsupport/tdesc.h. */ + +void +print_xml_feature::add_line (const char *fmt, ...) +{ + std::string tmp; + + va_list ap; + va_start (ap, fmt); + string_vappendf (tmp, fmt, ap); + va_end (ap); + add_line (tmp); } diff --git a/gdbsupport/tdesc.h b/gdbsupport/tdesc.h index 0cdcf56..73caf24 100644 --- a/gdbsupport/tdesc.h +++ b/gdbsupport/tdesc.h @@ -410,7 +410,8 @@ class print_xml_feature : public tdesc_element_visitor { public: print_xml_feature (std::string *buffer_) - : m_buffer (buffer_) + : m_buffer (buffer_), + m_depth (0) {} void visit_pre (const target_desc *e) override; @@ -423,7 +424,27 @@ public: void visit (const tdesc_reg *reg) override; private: + + /* Called with a positive value of ADJUST when we move inside an element, + for example inside <target>, and with a negative value when we leave + the element. In this class this function does nothing, but a + sub-class can override this to track the current level of nesting. */ + void indent (int adjust) + { + m_depth += (adjust * 2); + } + + /* Functions to add lines to the output buffer M_BUFFER. Each of these + functions appends a newline, so don't include one in the strings being + passed. */ + void add_line (const std::string &str); + void add_line (const char *fmt, ...); + + /* The buffer we are writing too. */ std::string *m_buffer; + + /* The current indentation depth. */ + int m_depth; }; #endif /* COMMON_TDESC_H */ |