From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from mail-wr1-x42c.google.com (mail-wr1-x42c.google.com [IPv6:2a00:1450:4864:20::42c]) by sourceware.org (Postfix) with ESMTPS id 8A7E5393C891 for ; Thu, 11 Jun 2020 10:41:54 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.3.2 sourceware.org 8A7E5393C891 Authentication-Results: sourceware.org; dmarc=none (p=none dis=none) header.from=embecosm.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=andrew.burgess@embecosm.com Received: by mail-wr1-x42c.google.com with SMTP id y17so5610648wrn.11 for ; Thu, 11 Jun 2020 03:41:54 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=embecosm.com; s=google; h=from:to:cc:subject:date:message-id:in-reply-to:references :mime-version:content-transfer-encoding; bh=glVaqXuwslK1gqBSqCQrKOcXMuH0EkIABt0DWDDAlHg=; b=BxUtN+yRoqrrS3Ne3fhD6lQSCDgJOHln6rdQ6sIBNYT/870sbYLY+B7bqaTCUo8jlt dIG7LvptulKXEoVsjJg+jWibe0BzRL71j1Gv3x2rzpkSlSsTc17NZOYlXcz+65piIE2D YjKKymTxA6piH8J/JxW2BbgyPm3ynHQW85M+RHnH/oy/i2+URc4GpvdX13/YZHbio2+1 2aiT/t95tX0UkgRh8yD1MJzz6i9ik4oDFRmwYeRztykzTHKM/V9IfaHe0yviauOpIEST Xr6aA0v1gTNWGqMCoZ8phAjq8a06/AVw6m2mlz+i0V0lOG1ISOMZ7COJbiTsqB9LhE+w 8bbA== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20161025; h=x-gm-message-state:from:to:cc:subject:date:message-id:in-reply-to :references:mime-version:content-transfer-encoding; bh=glVaqXuwslK1gqBSqCQrKOcXMuH0EkIABt0DWDDAlHg=; b=gDYVyMw8VD01sKLsN4pfdlVHFazXP9r4XNBfRvfNMRFMRJ/HD0LAI+xiNLBSe6hoDi oKu1UcbZ8b3/hZBZCstrzL4+LIDF/kiywiylpNd6HWs5P5kXCwLdCMhJr9Q6wCXYLTLV DLIUIk5wwSN6Sl85tSvmNc81WbM/5yN37XyocvzwgCtzm4WXAUUf55Wy3MskhwNA9GFp U2+lU/csHG6IwdpUrPJmmWTBTxVkzvm+gP3ccYLrSzIRn7EgSB7bmQuZbpbzU4VO7XP7 Z/vUiY4w6/EvBgPWr3QOE4ZRm2lervVCPwLMWerOW5b8WUXfYIhUWW42FRqy3M/b7PE3 jFbw== X-Gm-Message-State: AOAM530WTEGkkQwBFguN8s0EwDaRwzSvgSKv7bkWWxk/N9i58pNgwDj6 9Odim72z1RonGx0+az3M8Uqyns/3xRQ= X-Google-Smtp-Source: ABdhPJx7HHWcThDTobG6vpci8/PtdcTazUdGw1wH9TF/vkzBnrMqckYaJuvtwIIqhi1nM9IoNPUfKQ== X-Received: by 2002:adf:a34d:: with SMTP id d13mr8528693wrb.270.1591872111858; Thu, 11 Jun 2020 03:41:51 -0700 (PDT) Received: from localhost (host86-128-12-16.range86-128.btcentralplus.com. [86.128.12.16]) by smtp.gmail.com with ESMTPSA id m24sm3487087wmi.14.2020.06.11.03.41.51 (version=TLS1_3 cipher=TLS_AES_256_GCM_SHA384 bits=256/256); Thu, 11 Jun 2020 03:41:51 -0700 (PDT) From: Andrew Burgess To: gdb-patches@sourceware.org Subject: [PATCH 2/2] gdb: New maintenance command to print XML target description Date: Thu, 11 Jun 2020 11:41:31 +0100 Message-Id: <1247d74ec150f017e7ac1fea946af1d3da7ea79e.1591871818.git.andrew.burgess@embecosm.com> X-Mailer: git-send-email 2.25.4 In-Reply-To: References: MIME-Version: 1.0 Content-Transfer-Encoding: 8bit X-Spam-Status: No, score=-9.4 required=5.0 tests=BAYES_00, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, KAM_SHORT, PDS_OTHER_BAD_TLD, RCVD_IN_BARRACUDACENTRAL, RCVD_IN_DNSWL_NONE, SPF_HELO_NONE, SPF_PASS, TXREP autolearn=ham autolearn_force=no version=3.4.2 X-Spam-Checker-Version: SpamAssassin 3.4.2 (2018-09-13) on server2.sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.29 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , X-List-Received-Date: Thu, 11 Jun 2020 10:41:57 -0000 This commit adds a new maintenance command that dumps the current target description as an XML document. This is a maintenance command as I currently only see this being useful for GDB developers, or for people debugging a new remote target. By default the command will print whatever the current target description is, whether this was delivered by the remote, loaded by the user from a file, or if it is a built in target within GDB. The command can also take an optional filename argument. In this case GDB loads a target description from the file, and then reprints it. This could be useful for testing GDB's parsing of target descriptions, or to check that GDB can successfully parse a particular XML description. It is worth noting that the XML description printed will not be an exact copy of the document fed into GDB. For example this minimal input file: Will produce this output: (gdb) maint print xml-tdesc path/to/file.xml Notice that GDB filled in both the 'type' and 'regnum' fields of the . I think this is actually a positive as it means we get to really understand how GDB processed the document, if GDB made some assumptions that differ to those the user expected then hopefully this will bring those issues to the users attention. As for implementation I initially started writing a new tdesc visitor class that produced XML, but after remembering to check gdbsupport/ I found such a class already existed. However, that class produced XML which seems designed for a machine to read, with only minimal indentation. With a bit of tweaking I was able to restructure things so I could inherit from the existing XML producer and add indentation. During this tweaking I did make two changes to the original XML producing class, these are: 1. The ... tags are now not produced if the architecture name is NULL. 2. The ... tags get a newline at the end. gdbsupport/ChangeLog: * 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): Declare new member function. (print_xml_feature::add_line): Two new overloaded member functions. gdb/ChangeLog: * target-descriptions.c (tdesc_architecture_name): Protect against NULL pointer dereference. (class gdb_print_xml_feature): New class. (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. gdb/testsuite/ChangeLog: * 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. gdb/doc/ChangeLog: * gdb.texinfo (Maintenance Commands): Document new 'maint print xml-desc' command. --- gdb/ChangeLog | 10 ++ gdb/NEWS | 6 + gdb/doc/ChangeLog | 5 + gdb/doc/gdb.texinfo | 9 ++ gdb/target-descriptions.c | 90 +++++++++++++- gdb/testsuite/ChangeLog | 6 + gdb/testsuite/gdb.xml/maint-xml-dump-01.xml | 10 ++ gdb/testsuite/gdb.xml/maint-xml-dump-02.xml | 27 +++++ gdb/testsuite/gdb.xml/maint-xml-dump.exp | 124 ++++++++++++++++++++ gdbsupport/ChangeLog | 13 ++ gdbsupport/tdesc.cc | 99 +++++++++++----- gdbsupport/tdesc.h | 15 +++ 12 files changed, 383 insertions(+), 31 deletions(-) create mode 100644 gdb/testsuite/gdb.xml/maint-xml-dump-01.xml create mode 100644 gdb/testsuite/gdb.xml/maint-xml-dump-02.xml create mode 100644 gdb/testsuite/gdb.xml/maint-xml-dump.exp diff --git a/gdb/NEWS b/gdb/NEWS index 9ef85ab3ca7..491209b2772 100644 --- a/gdb/NEWS +++ b/gdb/NEWS @@ -66,6 +66,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. + * New targets GNU/Linux/RISC-V (gdbserver) riscv*-*-linux* diff --git a/gdb/doc/gdb.texinfo b/gdb/doc/gdb.texinfo index 64181628495..add14856f45 100644 --- a/gdb/doc/gdb.texinfo +++ b/gdb/doc/gdb.texinfo @@ -38397,6 +38397,15 @@ built again. This command is used by developers after they add or modify XML target descriptions. +@kindex maint print xml-tdesc @r{[}@var{file}@r{]} +@item maint print xml-tdesc +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 55ea416d69a..f86ffdeb518 100644 --- a/gdb/target-descriptions.c +++ b/gdb/target-descriptions.c @@ -639,7 +639,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; } /* Return the OSABI associated with this target description, or @@ -1717,6 +1719,87 @@ maint_print_c_tdesc_cmd (const char *args, int from_tty) } } +/* Class to format the target description XML with nesting. */ + +class gdb_print_xml_feature : public print_xml_feature +{ +public: + /* Constructor. */ + + gdb_print_xml_feature (std::string *arg) + :print_xml_feature (arg) + { /* Nothing. */ } + + /* Override this from the parent so we can add the compatibility + information. */ + + void visit_pre (const target_desc *e) override + { + print_xml_feature::visit_pre (e); + for (const bfd_arch_info_type *compatible : e->compatible) + add_line ("%s", compatible->printable_name); + }; + +protected: + + /* Pull in all copies of add_line. */ + + using print_xml_feature::add_line; + + /* Override this version of add_line to add white space for indentation + at the start of the line. */ + + void add_line (const std::string &str) override + { + std::string tmp = string_printf ("%*s", m_depth, ""); + tmp += str; + print_xml_feature::add_line (tmp); + } + + /* Increase our nesting by ADJUST. We use two spaces for every level of + indentation. */ + + void indent (int adjust) override + { + m_depth += (adjust * 2); + } + +private: + + /* The current level of indentation. */ + int m_depth = 0; +}; + +/* 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 C + 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; + gdb_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). */ @@ -1854,6 +1937,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/gdb.xml/maint-xml-dump-01.xml b/gdb/testsuite/gdb.xml/maint-xml-dump-01.xml new file mode 100644 index 00000000000..dd4f9251676 --- /dev/null +++ b/gdb/testsuite/gdb.xml/maint-xml-dump-01.xml @@ -0,0 +1,10 @@ + + + + + + + + + + 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 00000000000..c192294ca10 --- /dev/null +++ b/gdb/testsuite/gdb.xml/maint-xml-dump-02.xml @@ -0,0 +1,27 @@ + + Solaris + + + + + + + + + + + + + + + + + + + + + + + + + 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 00000000000..163996450eb --- /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 . + +# 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 and 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): +# | +# Will actually look for the following output: +# | +# +# 4. Indentation of lines will be preserved so your input file needs +# to follow the expected indentation. +if {[gdb_skip_xml_test]} { + unsupported "maint-xml-dump.exp" + 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 {} + set doc_type_line {} + + set linenum 0 + set ifd [open "$filename" r] + while {[gets $ifd line] >= 0} { + incr linenum + + # The 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 then add a default + # DOCTYPE line, otherwise, if the XML file includes a DOCTYPE + # line, use that. + if {$doc_type_line != "" } { + if {[regexp {^[ \t]*} $line]} { + set pattern [multi_line $pattern \ + [string_to_regexp $doc_type_line]] + set doc_type_line "" + } 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 handling the 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/gdbsupport/tdesc.cc b/gdbsupport/tdesc.cc index aaea8e0d8a8..cc11d3013c3 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, "\n", e->name.c_str ()); + add_line ("", e->name.c_str ()); + indent (1); } void print_xml_feature::visit_post (const tdesc_feature *e) { - string_appendf (*m_buffer, "\n"); + indent (-1); + add_line (""); } 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, "\n", - t->name.c_str (), t->element_type->name.c_str (), t->count); + add_line ("", + 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, " \n", - f.type->name.c_str ()); - else - string_appendf (*m_buffer, "start=\"%d\" end=\"%d\"/>\n", f.start, + tmp.clear (); + string_appendf (tmp, " ", + 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, " \n", - f.name.c_str (), f.start); + add_line (" ", + 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, " \n", - f.name.c_str (), f.type->name.c_str ()); + add_line (" ", + f.name.c_str (), f.type->name.c_str ()); break; default: @@ -362,40 +370,71 @@ void print_xml_feature::visit (const tdesc_type_with_fields *t) t->name.c_str ()); } - string_appendf (*m_buffer, "\n", types[t->kind - TDESC_TYPE_STRUCT]); + add_line ("", 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, "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, "\n"); - string_appendf (*m_buffer, "\n"); - string_appendf (*m_buffer, "\n%s\n", - tdesc_architecture_name (e)); + add_line (""); + add_line (""); + add_line (""); + indent (1); + if (tdesc_architecture_name (e)) + add_line ("%s", + tdesc_architecture_name (e)); const char *osabi = tdesc_osabi_name (e); if (osabi != nullptr) - string_appendf (*m_buffer, "%s", osabi); + add_line ("%s", osabi); #endif } void print_xml_feature::visit_post (const target_desc *e) { - string_appendf (*m_buffer, "\n"); + indent (-1); + add_line (""); +} + +/* See gdbsupport/tdesc.h. */ + +void +print_xml_feature::add_line (const std::string &str) +{ + 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 3b1f1f57ff8..009710e736b 100644 --- a/gdbsupport/tdesc.h +++ b/gdbsupport/tdesc.h @@ -401,6 +401,21 @@ class print_xml_feature : public tdesc_element_visitor void visit (const tdesc_type_with_fields *type) override; void visit (const tdesc_reg *reg) override; +protected: + + /* Called with a positive value of ADJUST we move inside an element, for + example inside , 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. */ + virtual void indent (int adjust) + { /* Nothing. */ } + + /* Functions to add lines to the output buffer M_BUFFER. Each of these + functions appends a newline, so don't include one the strings being + sent. */ + virtual void add_line (const std::string &str); + virtual void add_line (const char *fmt, ...); + private: std::string *m_buffer; }; -- 2.25.4