mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 13:50:11 +00:00
[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.
This commit is contained in:
parent
4602802240
commit
d1556e5efb
@ -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 @@ public:
|
||||
/// 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 @@ public:
|
||||
/// 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
|
||||
|
@ -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)
|
||||
|
@ -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 << "/>";
|
||||
}
|
||||
|
@ -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");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user