mirror of
https://github.com/capstone-engine/llvm-capstone.git
synced 2024-11-23 22:00:10 +00:00
[lldb] Add register field tables to the "register info" command
This teaches DumpRegisterInfo to generate a table from the register flags type. It just calls a method on RegisterFlags. As such, the extra tests are minimal and only show that the intergration works. Exhaustive formatting tests are done with RegisterFlags itself. Example: ``` (lldb) register info cpsr Name: cpsr Size: 4 bytes (32 bits) In sets: general (index 0) | 31 | 30 | 29 | 28 | 27-26 | 25 | 24 | 23 | 22 | 21 | 20 | 19-13 | 12 | 11-10 | 9 | 8 | 7 | 6 | 5 | 4 | 3-2 | 1 | 0 | |----|----|----|----|-------|-----|-----|-----|-----|----|----|-------|------|-------|---|---|---|---|---|-----|-----|---|----| | N | Z | C | V | | TCO | DIT | UAO | PAN | SS | IL | | SSBS | | D | A | I | F | | nRW | EL | | SP | ``` LLDB limits the max terminal width to 80 chars by default. So to get that full width output you will need to change the "term-width" setting to something higher. Reviewed By: jasonmolenda Differential Revision: https://reviews.llvm.org/D152918
This commit is contained in:
parent
6f7c9d1e17
commit
bcfe5a52a3
@ -18,16 +18,18 @@ namespace lldb_private {
|
||||
class Stream;
|
||||
class RegisterContext;
|
||||
struct RegisterInfo;
|
||||
class RegisterFlags;
|
||||
|
||||
void DumpRegisterInfo(Stream &strm, RegisterContext &ctx,
|
||||
const RegisterInfo &info);
|
||||
const RegisterInfo &info, uint32_t terminal_width);
|
||||
|
||||
// For testing only. Use DumpRegisterInfo instead.
|
||||
void DoDumpRegisterInfo(
|
||||
Stream &strm, const char *name, const char *alt_name, uint32_t byte_size,
|
||||
const std::vector<const char *> &invalidates,
|
||||
const std::vector<const char *> &read_from,
|
||||
const std::vector<std::pair<const char *, uint32_t>> &in_sets);
|
||||
const std::vector<std::pair<const char *, uint32_t>> &in_sets,
|
||||
const RegisterFlags *flags_type, uint32_t terminal_width);
|
||||
|
||||
} // namespace lldb_private
|
||||
|
||||
|
@ -11,6 +11,7 @@
|
||||
#include "lldb/Core/DumpRegisterInfo.h"
|
||||
#include "lldb/Core/DumpRegisterValue.h"
|
||||
#include "lldb/Host/OptionParser.h"
|
||||
#include "lldb/Interpreter/CommandInterpreter.h"
|
||||
#include "lldb/Interpreter/CommandOptionArgumentTable.h"
|
||||
#include "lldb/Interpreter/CommandReturnObject.h"
|
||||
#include "lldb/Interpreter/OptionGroupFormat.h"
|
||||
@ -418,6 +419,8 @@ Read from (*) The registers that the value of this register is constructed
|
||||
read from the wider register.
|
||||
In sets (*) The register sets that contain this register. For example the
|
||||
PC will be in the "General Purpose Register" set.
|
||||
Fields (*) A table of the names and bit positions of the values contained
|
||||
in this register.
|
||||
|
||||
Fields marked with (*) may not always be present. Some information may be
|
||||
different for the same register when connected to different debug servers.)");
|
||||
@ -453,7 +456,9 @@ protected:
|
||||
RegisterContext *reg_ctx = m_exe_ctx.GetRegisterContext();
|
||||
const RegisterInfo *reg_info = reg_ctx->GetRegisterInfoByName(reg_name);
|
||||
if (reg_info) {
|
||||
DumpRegisterInfo(result.GetOutputStream(), *reg_ctx, *reg_info);
|
||||
DumpRegisterInfo(
|
||||
result.GetOutputStream(), *reg_ctx, *reg_info,
|
||||
GetCommandInterpreter().GetDebugger().GetTerminalWidth());
|
||||
result.SetStatus(eReturnStatusSuccessFinishResult);
|
||||
} else
|
||||
result.AppendErrorWithFormat("No register found with name '%s'.\n",
|
||||
|
@ -8,6 +8,7 @@
|
||||
|
||||
#include "lldb/Core/DumpRegisterInfo.h"
|
||||
#include "lldb/Target/RegisterContext.h"
|
||||
#include "lldb/Target/RegisterFlags.h"
|
||||
#include "lldb/Utility/Stream.h"
|
||||
|
||||
using namespace lldb;
|
||||
@ -16,7 +17,8 @@ using namespace lldb_private;
|
||||
using SetInfo = std::pair<const char *, uint32_t>;
|
||||
|
||||
void lldb_private::DumpRegisterInfo(Stream &strm, RegisterContext &ctx,
|
||||
const RegisterInfo &info) {
|
||||
const RegisterInfo &info,
|
||||
uint32_t terminal_width) {
|
||||
std::vector<const char *> invalidates;
|
||||
if (info.invalidate_regs) {
|
||||
for (uint32_t *inv_regs = info.invalidate_regs;
|
||||
@ -60,7 +62,8 @@ void lldb_private::DumpRegisterInfo(Stream &strm, RegisterContext &ctx,
|
||||
}
|
||||
|
||||
DoDumpRegisterInfo(strm, info.name, info.alt_name, info.byte_size,
|
||||
invalidates, read_from, in_sets);
|
||||
invalidates, read_from, in_sets, info.flags_type,
|
||||
terminal_width);
|
||||
}
|
||||
|
||||
template <typename ElementType>
|
||||
@ -85,7 +88,8 @@ void lldb_private::DoDumpRegisterInfo(
|
||||
Stream &strm, const char *name, const char *alt_name, uint32_t byte_size,
|
||||
const std::vector<const char *> &invalidates,
|
||||
const std::vector<const char *> &read_from,
|
||||
const std::vector<SetInfo> &in_sets) {
|
||||
const std::vector<SetInfo> &in_sets, const RegisterFlags *flags_type,
|
||||
uint32_t terminal_width) {
|
||||
strm << " Name: " << name;
|
||||
if (alt_name)
|
||||
strm << " (" << alt_name << ")";
|
||||
@ -106,4 +110,7 @@ void lldb_private::DoDumpRegisterInfo(
|
||||
strm.Printf("%s (index %d)", info.first, info.second);
|
||||
};
|
||||
DumpList(strm, " In sets: ", in_sets, emit_set);
|
||||
|
||||
if (flags_type)
|
||||
strm.Printf("\n\n%s", flags_type->AsTable(terminal_width).c_str());
|
||||
}
|
||||
|
@ -587,7 +587,8 @@ class RegisterCommandsTestCase(TestBase):
|
||||
def test_info_register(self):
|
||||
# The behaviour of this command is generic but the specific registers
|
||||
# are not, so this is written for AArch64 only.
|
||||
# Text alignment and ordering are checked in the DumpRegisterInfo unit tests.
|
||||
# Text alignment and ordering are checked in the DumpRegisterInfo and
|
||||
# RegisterFlags unit tests.
|
||||
self.build()
|
||||
self.common_setup()
|
||||
|
||||
|
@ -605,3 +605,31 @@ class TestXMLRegisterFlags(GDBRemoteTestBase):
|
||||
|
||||
self.expect("register read x0", substrs=["(correct = 1)"])
|
||||
self.expect("register read x1", substrs=["(correct = 1)"])
|
||||
|
||||
@skipIfXmlSupportMissing
|
||||
@skipIfRemote
|
||||
def test_flags_in_register_info(self):
|
||||
# See RegisterFlags for comprehensive formatting tests.
|
||||
self.setup_flags_test(
|
||||
'<field name="D" start="0" end="7"/>'
|
||||
'<field name="C" start="8" end="15"/>'
|
||||
'<field name="B" start="16" end="23"/>'
|
||||
'<field name="A" start="24" end="31"/>'
|
||||
)
|
||||
|
||||
# The table should split according to terminal width.
|
||||
self.runCmd("settings set term-width 17")
|
||||
|
||||
self.expect("register info cpsr",
|
||||
substrs=[
|
||||
" Name: cpsr\n"
|
||||
" Size: 4 bytes (32 bits)\n"
|
||||
" In sets: general (index 0)\n"
|
||||
"\n"
|
||||
"| 31-24 | 23-16 |\n"
|
||||
"|-------|-------|\n"
|
||||
"| A | B |\n"
|
||||
"\n"
|
||||
"| 15-8 | 7-0 |\n"
|
||||
"|------|-----|\n"
|
||||
"| C | D |"])
|
@ -7,6 +7,7 @@
|
||||
//===----------------------------------------------------------------------===//
|
||||
|
||||
#include "lldb/Core/DumpRegisterInfo.h"
|
||||
#include "lldb/Target/RegisterFlags.h"
|
||||
#include "lldb/Utility/StreamString.h"
|
||||
#include "gtest/gtest.h"
|
||||
|
||||
@ -14,27 +15,28 @@ using namespace lldb_private;
|
||||
|
||||
TEST(DoDumpRegisterInfoTest, MinimumInfo) {
|
||||
StreamString strm;
|
||||
DoDumpRegisterInfo(strm, "foo", nullptr, 4, {}, {}, {});
|
||||
DoDumpRegisterInfo(strm, "foo", nullptr, 4, {}, {}, {}, nullptr, 0);
|
||||
ASSERT_EQ(strm.GetString(), " Name: foo\n"
|
||||
" Size: 4 bytes (32 bits)");
|
||||
}
|
||||
|
||||
TEST(DoDumpRegisterInfoTest, AltName) {
|
||||
StreamString strm;
|
||||
DoDumpRegisterInfo(strm, "foo", "bar", 4, {}, {}, {});
|
||||
DoDumpRegisterInfo(strm, "foo", "bar", 4, {}, {}, {}, nullptr, 0);
|
||||
ASSERT_EQ(strm.GetString(), " Name: foo (bar)\n"
|
||||
" Size: 4 bytes (32 bits)");
|
||||
}
|
||||
|
||||
TEST(DoDumpRegisterInfoTest, Invalidates) {
|
||||
StreamString strm;
|
||||
DoDumpRegisterInfo(strm, "foo", nullptr, 4, {"foo2"}, {}, {});
|
||||
DoDumpRegisterInfo(strm, "foo", nullptr, 4, {"foo2"}, {}, {}, nullptr, 0);
|
||||
ASSERT_EQ(strm.GetString(), " Name: foo\n"
|
||||
" Size: 4 bytes (32 bits)\n"
|
||||
"Invalidates: foo2");
|
||||
|
||||
strm.Clear();
|
||||
DoDumpRegisterInfo(strm, "foo", nullptr, 4, {"foo2", "foo3", "foo4"}, {}, {});
|
||||
DoDumpRegisterInfo(strm, "foo", nullptr, 4, {"foo2", "foo3", "foo4"}, {}, {},
|
||||
nullptr, 0);
|
||||
ASSERT_EQ(strm.GetString(), " Name: foo\n"
|
||||
" Size: 4 bytes (32 bits)\n"
|
||||
"Invalidates: foo2, foo3, foo4");
|
||||
@ -42,13 +44,14 @@ TEST(DoDumpRegisterInfoTest, Invalidates) {
|
||||
|
||||
TEST(DoDumpRegisterInfoTest, ReadFrom) {
|
||||
StreamString strm;
|
||||
DoDumpRegisterInfo(strm, "foo", nullptr, 4, {}, {"foo1"}, {});
|
||||
DoDumpRegisterInfo(strm, "foo", nullptr, 4, {}, {"foo1"}, {}, nullptr, 0);
|
||||
ASSERT_EQ(strm.GetString(), " Name: foo\n"
|
||||
" Size: 4 bytes (32 bits)\n"
|
||||
" Read from: foo1");
|
||||
|
||||
strm.Clear();
|
||||
DoDumpRegisterInfo(strm, "foo", nullptr, 4, {}, {"foo1", "foo2", "foo3"}, {});
|
||||
DoDumpRegisterInfo(strm, "foo", nullptr, 4, {}, {"foo1", "foo2", "foo3"}, {},
|
||||
nullptr, 0);
|
||||
ASSERT_EQ(strm.GetString(), " Name: foo\n"
|
||||
" Size: 4 bytes (32 bits)\n"
|
||||
" Read from: foo1, foo2, foo3");
|
||||
@ -56,14 +59,15 @@ TEST(DoDumpRegisterInfoTest, ReadFrom) {
|
||||
|
||||
TEST(DoDumpRegisterInfoTest, InSets) {
|
||||
StreamString strm;
|
||||
DoDumpRegisterInfo(strm, "foo", nullptr, 4, {}, {}, {{"set1", 101}});
|
||||
DoDumpRegisterInfo(strm, "foo", nullptr, 4, {}, {}, {{"set1", 101}}, nullptr,
|
||||
0);
|
||||
ASSERT_EQ(strm.GetString(), " Name: foo\n"
|
||||
" Size: 4 bytes (32 bits)\n"
|
||||
" In sets: set1 (index 101)");
|
||||
|
||||
strm.Clear();
|
||||
DoDumpRegisterInfo(strm, "foo", nullptr, 4, {}, {},
|
||||
{{"set1", 0}, {"set2", 1}, {"set3", 2}});
|
||||
{{"set1", 0}, {"set2", 1}, {"set3", 2}}, nullptr, 0);
|
||||
ASSERT_EQ(strm.GetString(),
|
||||
" Name: foo\n"
|
||||
" Size: 4 bytes (32 bits)\n"
|
||||
@ -73,10 +77,28 @@ TEST(DoDumpRegisterInfoTest, InSets) {
|
||||
TEST(DoDumpRegisterInfoTest, MaxInfo) {
|
||||
StreamString strm;
|
||||
DoDumpRegisterInfo(strm, "foo", nullptr, 4, {"foo2", "foo3"},
|
||||
{"foo3", "foo4"}, {{"set1", 1}, {"set2", 2}});
|
||||
{"foo3", "foo4"}, {{"set1", 1}, {"set2", 2}}, nullptr, 0);
|
||||
ASSERT_EQ(strm.GetString(), " Name: foo\n"
|
||||
" Size: 4 bytes (32 bits)\n"
|
||||
"Invalidates: foo2, foo3\n"
|
||||
" Read from: foo3, foo4\n"
|
||||
" In sets: set1 (index 1), set2 (index 2)");
|
||||
}
|
||||
|
||||
TEST(DoDumpRegisterInfoTest, FieldsTable) {
|
||||
// This is thoroughly tested in RegisterFlags itself, only checking the
|
||||
// integration here.
|
||||
StreamString strm;
|
||||
RegisterFlags flags(
|
||||
"", 4,
|
||||
{RegisterFlags::Field("A", 24, 31), RegisterFlags::Field("B", 16, 23),
|
||||
RegisterFlags::Field("C", 8, 15), RegisterFlags::Field("D", 0, 7)});
|
||||
|
||||
DoDumpRegisterInfo(strm, "foo", nullptr, 4, {}, {}, {}, &flags, 100);
|
||||
ASSERT_EQ(strm.GetString(), " Name: foo\n"
|
||||
" Size: 4 bytes (32 bits)\n"
|
||||
"\n"
|
||||
"| 31-24 | 23-16 | 15-8 | 7-0 |\n"
|
||||
"|-------|-------|------|-----|\n"
|
||||
"| A | B | C | D |");
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user