Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[lldb][lldb-server] Enable sending RegisterFlags as XML #69951

Merged
merged 6 commits into from
Oct 26, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
19 changes: 14 additions & 5 deletions lldb/include/lldb/Target/RegisterFlags.h
Original file line number Diff line number Diff line change
Expand Up @@ -9,20 +9,21 @@
#ifndef LLDB_TARGET_REGISTERFLAGS_H
#define LLDB_TARGET_REGISTERFLAGS_H

#include "lldb/Utility/Log.h"
#include <string>
#include <vector>
DavidSpickett marked this conversation as resolved.
Show resolved Hide resolved

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)
Expand Down Expand Up @@ -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 "&gt;".
void ToXML(StreamString &strm) const;

bool operator<(const Field &rhs) const {
return GetStart() < rhs.GetStart();
}
Expand Down Expand Up @@ -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
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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\" ",
Expand All @@ -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)
Expand Down
46 changes: 46 additions & 0 deletions lldb/source/Target/RegisterFlags.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down Expand Up @@ -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 << "/>";
}
50 changes: 50 additions & 0 deletions lldb/unittests/Target/RegisterFlagsTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@
//===----------------------------------------------------------------------===//

#include "lldb/Target/RegisterFlags.h"
#include "lldb/Utility/StreamString.h"
#include "gmock/gmock.h"
#include "gtest/gtest.h"

Expand Down Expand Up @@ -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&lt;\" start=\"4\" end=\"4\"/>\n"
" <field name=\"B&gt;\" start=\"3\" end=\"3\"/>\n"
" <field name=\"C&apos;\" start=\"2\" end=\"2\"/>\n"
" <field name=\"D&quot;\" start=\"1\" end=\"1\"/>\n"
" <field name=\"E&amp;\" start=\"0\" end=\"0\"/>\n"
"</flags>\n");
}