Author: David Spickett Date: 2023-10-26T08:33:30+01:00 New Revision: d1556e5efbf0cb671c0f6e403fc1eaf9153f8713
URL: https://github.com/llvm/llvm-project/commit/d1556e5efbf0cb671c0f6e403fc1eaf9153f8713 DIFF: https://github.com/llvm/llvm-project/commit/d1556e5efbf0cb671c0f6e403fc1eaf9153f8713.diff LOG: [lldb][lldb-server] Enable sending RegisterFlags as XML (#69951) This adds ToXML methods to encode RegisterFlags and its fields into XML according to GDB's target XML format: https://sourceware.org/gdb/onlinedocs/gdb/Target-Description-Format.html#Target-Description-Format lldb-server does not use libXML to build XML, so this follows the existing code that uses strings. Indentation is used so the result is still human readable. ``` <flags id=\"Foo\" size=\"4\"> <field name=\"abc\" start=\"0\" end=\"0\"/> </flags> ``` This is used by lldb-server when building target XML, though no one sets any fields yet. That'll come in a later commit. Added: Modified: lldb/include/lldb/Target/RegisterFlags.h lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp lldb/source/Target/RegisterFlags.cpp lldb/unittests/Target/RegisterFlagsTest.cpp Removed: ################################################################################ diff --git a/lldb/include/lldb/Target/RegisterFlags.h b/lldb/include/lldb/Target/RegisterFlags.h index d98bc0263e35e23..7c5b97c2265fda3 100644 --- a/lldb/include/lldb/Target/RegisterFlags.h +++ b/lldb/include/lldb/Target/RegisterFlags.h @@ -9,20 +9,21 @@ #ifndef LLDB_TARGET_REGISTERFLAGS_H #define LLDB_TARGET_REGISTERFLAGS_H -#include "lldb/Utility/Log.h" +#include <string> +#include <vector> namespace lldb_private { +class StreamString; +class Log; + class RegisterFlags { public: class Field { public: /// Where start is the least significant bit and end is the most /// significant bit. The start bit must be <= the end bit. - Field(std::string name, unsigned start, unsigned end) - : m_name(std::move(name)), m_start(start), m_end(end) { - assert(m_start <= m_end && "Start bit must be <= end bit."); - } + Field(std::string name, unsigned start, unsigned end); /// Construct a field that occupies a single bit. Field(std::string name, unsigned bit_position) @@ -51,6 +52,11 @@ class RegisterFlags { /// covered by either field. unsigned PaddingDistance(const Field &other) const; + /// Output XML that describes this field, to be inserted into a target XML + /// file. Reserved characters in field names like "<" are replaced with + /// their XML safe equivalents like ">". + void ToXML(StreamString &strm) const; + bool operator<(const Field &rhs) const { return GetStart() < rhs.GetStart(); } @@ -106,6 +112,9 @@ class RegisterFlags { /// be split into many tables as needed. std::string AsTable(uint32_t max_width) const; + // Output XML that describes this set of flags. + void ToXML(StreamString &strm) const; + private: const std::string m_id; /// Size in bytes diff --git a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp index 23c2f18cd388a86..187c23a206094c0 100644 --- a/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp +++ b/lldb/source/Plugins/Process/gdb-remote/GDBRemoteCommunicationServerLLGS.cpp @@ -3094,6 +3094,12 @@ GDBRemoteCommunicationServerLLGS::BuildTargetXml() { continue; } + if (reg_info->flags_type) { + response.IndentMore(); + reg_info->flags_type->ToXML(response); + response.IndentLess(); + } + response.Indent(); response.Printf("<reg name=\"%s\" bitsize=\"%" PRIu32 "\" regnum=\"%d\" ", @@ -3113,6 +3119,9 @@ GDBRemoteCommunicationServerLLGS::BuildTargetXml() { if (!format.empty()) response << "format=\"" << format << "\" "; + if (reg_info->flags_type) + response << "type=\"" << reg_info->flags_type->GetID() << "\" "; + const char *const register_set_name = reg_context.GetRegisterSetNameForRegisterAtIndex(reg_index); if (register_set_name) diff --git a/lldb/source/Target/RegisterFlags.cpp b/lldb/source/Target/RegisterFlags.cpp index 06fb45d777ec36f..49974718ccb514a 100644 --- a/lldb/source/Target/RegisterFlags.cpp +++ b/lldb/source/Target/RegisterFlags.cpp @@ -7,13 +7,21 @@ //===----------------------------------------------------------------------===// #include "lldb/Target/RegisterFlags.h" +#include "lldb/Utility/Log.h" #include "lldb/Utility/StreamString.h" +#include "llvm/ADT/StringExtras.h" + #include <numeric> #include <optional> using namespace lldb_private; +RegisterFlags::Field::Field(std::string name, unsigned start, unsigned end) + : m_name(std::move(name)), m_start(start), m_end(end) { + assert(m_start <= m_end && "Start bit must be <= end bit."); +} + void RegisterFlags::Field::log(Log *log) const { LLDB_LOG(log, " Name: \"{0}\" Start: {1} End: {2}", m_name.c_str(), m_start, m_end); @@ -175,3 +183,41 @@ std::string RegisterFlags::AsTable(uint32_t max_width) const { return table; } + +void RegisterFlags::ToXML(StreamString &strm) const { + // Example XML: + // <flags id="cpsr_flags" size="4"> + // <field name="incorrect" start="0" end="0"/> + // </flags> + strm.Indent(); + strm << "<flags id=\"" << GetID() << "\" "; + strm.Printf("size=\"%d\"", GetSize()); + strm << ">"; + for (const Field &field : m_fields) { + // Skip padding fields. + if (field.GetName().empty()) + continue; + + strm << "\n"; + strm.IndentMore(); + field.ToXML(strm); + strm.IndentLess(); + } + strm.PutChar('\n'); + strm.Indent("</flags>\n"); +} + +void RegisterFlags::Field::ToXML(StreamString &strm) const { + // Example XML: + // <field name="correct" start="0" end="0"/> + strm.Indent(); + strm << "<field name=\""; + + std::string escaped_name; + llvm::raw_string_ostream escape_strm(escaped_name); + llvm::printHTMLEscaped(GetName(), escape_strm); + strm << escaped_name << "\" "; + + strm.Printf("start=\"%d\" end=\"%d\"", GetStart(), GetEnd()); + strm << "/>"; +} diff --git a/lldb/unittests/Target/RegisterFlagsTest.cpp b/lldb/unittests/Target/RegisterFlagsTest.cpp index 167e28d0cecb3bd..c7a419203165538 100644 --- a/lldb/unittests/Target/RegisterFlagsTest.cpp +++ b/lldb/unittests/Target/RegisterFlagsTest.cpp @@ -7,6 +7,7 @@ //===----------------------------------------------------------------------===// #include "lldb/Target/RegisterFlags.h" +#include "lldb/Utility/StreamString.h" #include "gmock/gmock.h" #include "gtest/gtest.h" @@ -258,3 +259,52 @@ TEST(RegisterFlagsTest, AsTable) { "| really long name |", max_many_columns.AsTable(23)); } + +TEST(RegisterFieldsTest, ToXML) { + StreamString strm; + + // RegisterFlags requires that some fields be given, so no testing of empty + // input. + + // Unnamed fields are padding that are ignored. This applies to fields passed + // in, and those generated to fill the other bits (31-1 here). + RegisterFlags("Foo", 4, {RegisterFlags::Field("", 0, 0)}).ToXML(strm); + ASSERT_EQ(strm.GetString(), "<flags id=\"Foo\" size=\"4\">\n" + "</flags>\n"); + + strm.Clear(); + RegisterFlags("Foo", 4, {RegisterFlags::Field("abc", 0, 0)}).ToXML(strm); + ASSERT_EQ(strm.GetString(), "<flags id=\"Foo\" size=\"4\">\n" + " <field name=\"abc\" start=\"0\" end=\"0\"/>\n" + "</flags>\n"); + + strm.Clear(); + // Should use the current indentation level as a starting point. + strm.IndentMore(); + RegisterFlags( + "Bar", 5, + {RegisterFlags::Field("f1", 25, 32), RegisterFlags::Field("f2", 10, 24)}) + .ToXML(strm); + ASSERT_EQ(strm.GetString(), + " <flags id=\"Bar\" size=\"5\">\n" + " <field name=\"f1\" start=\"25\" end=\"32\"/>\n" + " <field name=\"f2\" start=\"10\" end=\"24\"/>\n" + " </flags>\n"); + + strm.Clear(); + strm.IndentLess(); + // Should replace any XML unsafe characters in field names. + RegisterFlags("Safe", 8, + {RegisterFlags::Field("A<", 4), RegisterFlags::Field("B>", 3), + RegisterFlags::Field("C'", 2), RegisterFlags::Field("D\"", 1), + RegisterFlags::Field("E&", 0)}) + .ToXML(strm); + ASSERT_EQ(strm.GetString(), + "<flags id=\"Safe\" size=\"8\">\n" + " <field name=\"A<\" start=\"4\" end=\"4\"/>\n" + " <field name=\"B>\" start=\"3\" end=\"3\"/>\n" + " <field name=\"C'\" start=\"2\" end=\"2\"/>\n" + " <field name=\"D"\" start=\"1\" end=\"1\"/>\n" + " <field name=\"E&\" start=\"0\" end=\"0\"/>\n" + "</flags>\n"); +} _______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits