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] Add format eFormatEnumWithValues to ensure raw enum value is always shown #90059

Closed
wants to merge 1 commit into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 8 additions & 4 deletions lldb/include/lldb/lldb-enumerations.h
Original file line number Diff line number Diff line change
Expand Up @@ -195,11 +195,15 @@ enum Format {
///< character arrays that can contain non printable
///< characters
eFormatAddressInfo, ///< Describe what an address points to (func + offset
///< with file/line, symbol + offset, data, etc)
eFormatHexFloat, ///< ISO C99 hex float string
eFormatInstruction, ///< Disassemble an opcode
eFormatVoid, ///< Do not print this
///< with file/line, symbol + offset, data, etc)
eFormatHexFloat, ///< ISO C99 hex float string
eFormatInstruction, ///< Disassemble an opcode
eFormatVoid, ///< Do not print this
eFormatUnicode8,
eFormatEnumWithValues, ///< Format as an enum but if the value matches one or
///< more enumerators, print the enumerator name and
///< value of those enumerators. For example "foo (1)"
///< instead of "foo".
Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This enum is used in the API so I've added to the end of it.

kNumFormats
};

Expand Down
1 change: 1 addition & 0 deletions lldb/source/Commands/CommandObjectMemory.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1387,6 +1387,7 @@ class CommandObjectMemoryWrite : public CommandObjectParsed {
case eFormatBytesWithASCII:
case eFormatComplex:
case eFormatEnum:
case eFormatEnumWithValues:
case eFormatUnicode8:
case eFormatUnicode16:
case eFormatUnicode32:
Expand Down
1 change: 1 addition & 0 deletions lldb/source/Core/DumpDataExtractor.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -496,6 +496,7 @@ lldb::offset_t lldb_private::DumpDataExtractor(

case eFormatEnum: // Print enum value as a signed integer when we don't get
// the enum type
case eFormatEnumWithValues:
case eFormatDecimal:
if (item_byte_size <= 8)
s->Printf("%" PRId64,
Expand Down
3 changes: 2 additions & 1 deletion lldb/source/Core/ValueObject.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1189,7 +1189,8 @@ bool ValueObject::DumpPrintableRepresentation(
return !error.Fail();
}

if (custom_format == eFormatEnum)
if (custom_format == eFormatEnum ||
custom_format == eFormatEnumWithValues)
return false;

// this only works for arrays, because I have no way to know when the
Expand Down
1 change: 1 addition & 0 deletions lldb/source/DataFormatters/FormatManager.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -71,6 +71,7 @@ static constexpr FormatInfo g_format_infos[] = {
{eFormatInstruction, 'i', "instruction"},
{eFormatVoid, 'v', "void"},
{eFormatUnicode8, 'u', "unicode8"},
{eFormatEnumWithValues, '\0', "enumeration with values"},
};

static_assert((sizeof(g_format_infos) / sizeof(g_format_infos[0])) ==
Expand Down
2 changes: 2 additions & 0 deletions lldb/source/DataFormatters/VectorType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -115,6 +115,7 @@ static CompilerType GetCompilerTypeForFormat(lldb::Format format,
case lldb::eFormatComplexInteger:
case lldb::eFormatDecimal:
case lldb::eFormatEnum:
case lldb::eFormatEnumWithValues:
case lldb::eFormatInstruction:
case lldb::eFormatOSType:
case lldb::eFormatVoid:
Expand Down Expand Up @@ -150,6 +151,7 @@ static lldb::Format GetItemFormatForFormat(lldb::Format format,
case lldb::eFormatComplexInteger:
case lldb::eFormatDecimal:
case lldb::eFormatEnum:
case lldb::eFormatEnumWithValues:
case lldb::eFormatInstruction:
case lldb::eFormatOSType:
case lldb::eFormatVoid:
Expand Down
28 changes: 21 additions & 7 deletions lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8572,7 +8572,7 @@ void TypeSystemClang::DumpFromSymbolFile(Stream &s,
static bool DumpEnumValue(const clang::QualType &qual_type, Stream &s,
const DataExtractor &data, lldb::offset_t byte_offset,
size_t byte_size, uint32_t bitfield_bit_offset,
uint32_t bitfield_bit_size) {
uint32_t bitfield_bit_size, bool always_show_value) {
const clang::EnumType *enutype =
llvm::cast<clang::EnumType>(qual_type.getTypePtr());
const clang::EnumDecl *enum_decl = enutype->getDecl();
Expand All @@ -8599,7 +8599,11 @@ static bool DumpEnumValue(const clang::QualType &qual_type, Stream &s,
++num_enumerators;
if (val == enum_svalue) {
// Found an exact match, that's all we need to do.
s.PutCString(enumerator->getNameAsString());
if (always_show_value)
s.Printf("%s (%" PRIi64 ")", enumerator->getNameAsString().c_str(),
enum_svalue);
else
s.PutCString(enumerator->getNameAsString());
return true;
}
}
Expand Down Expand Up @@ -8634,17 +8638,23 @@ static bool DumpEnumValue(const clang::QualType &qual_type, Stream &s,
return llvm::popcount(a.first) > llvm::popcount(b.first);
});

bool found_enumerator = false;
for (const auto &val : values) {
if ((remaining_value & val.first) != val.first)
continue;
found_enumerator = true;
remaining_value &= ~val.first;
s.PutCString(val.second);
if (always_show_value)
s.Printf(" (0x%" PRIx64 ")", val.first);
if (remaining_value)
s.PutCString(" | ");
}

// If there is a remainder that is not covered by the value, print it as hex.
if (remaining_value)
// If we found no matching values but were asked to always print a value,
// print it as hex.
if (remaining_value || (!found_enumerator && always_show_value))
s.Printf("0x%" PRIx64, remaining_value);

return true;
Expand All @@ -8666,8 +8676,9 @@ bool TypeSystemClang::DumpTypeValue(

if (type_class == clang::Type::Elaborated) {
qual_type = llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType();
return DumpTypeValue(qual_type.getAsOpaquePtr(), s, format, data, byte_offset, byte_size,
bitfield_bit_size, bitfield_bit_offset, exe_scope);
return DumpTypeValue(qual_type.getAsOpaquePtr(), s, format, data,
byte_offset, byte_size, bitfield_bit_size,
bitfield_bit_offset, exe_scope);
}

switch (type_class) {
Expand Down Expand Up @@ -8699,10 +8710,12 @@ bool TypeSystemClang::DumpTypeValue(
case clang::Type::Enum:
// If our format is enum or default, show the enumeration value as its
// enumeration string value, else just display it as requested.
if ((format == eFormatEnum || format == eFormatDefault) &&
if ((format == eFormatEnum || format == eFormatEnumWithValues ||
format == eFormatDefault) &&
GetCompleteType(type))
return DumpEnumValue(qual_type, s, data, byte_offset, byte_size,
bitfield_bit_offset, bitfield_bit_size);
bitfield_bit_offset, bitfield_bit_size,
format == eFormatEnumWithValues);
// format was not enum, just fall through and dump the value as
// requested....
[[fallthrough]];
Expand All @@ -8722,6 +8735,7 @@ bool TypeSystemClang::DumpTypeValue(
case eFormatCString: // NULL terminated C strings
case eFormatDecimal:
case eFormatEnum:
case eFormatEnumWithValues:
case eFormatHex:
case eFormatHexUppercase:
case eFormatFloat:
Expand Down
20 changes: 20 additions & 0 deletions lldb/test/API/lang/c/enum_types/TestEnumTypes.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,13 +23,28 @@ def test_command_line(self):
)

self.expect("fr var a", DATA_TYPES_DISPLAYED_CORRECTLY, patterns=[" = A$"])
self.expect(
'fr var --format "enumeration with values" -- a',
DATA_TYPES_DISPLAYED_CORRECTLY,
patterns=[" = A \(1\)$"],
)
self.expect("fr var b", DATA_TYPES_DISPLAYED_CORRECTLY, patterns=[" = B$"])
self.expect("fr var c", DATA_TYPES_DISPLAYED_CORRECTLY, patterns=[" = C$"])
self.expect("fr var ab", DATA_TYPES_DISPLAYED_CORRECTLY, patterns=[" = AB$"])
self.expect(
"fr var ac", DATA_TYPES_DISPLAYED_CORRECTLY, patterns=[" = A \| C$"]
)
self.expect(
'fr var --format "enumeration with values" -- ac',
DATA_TYPES_DISPLAYED_CORRECTLY,
patterns=[" = A \(0x1\) | C \(0x4\)$"],
)
self.expect("fr var all", DATA_TYPES_DISPLAYED_CORRECTLY, patterns=[" = ALL$"])
self.expect(
'fr var --format "enumeration with values" -- all',
DATA_TYPES_DISPLAYED_CORRECTLY,
patterns=[" = ALL \(7\)$"],
)
# Test that an enum that doesn't match the heuristic we use in
# TypeSystemClang::DumpEnumValue, gets printed as a raw integer.
self.expect("fr var omega", DATA_TYPES_DISPLAYED_CORRECTLY, patterns=[" = 7$"])
Expand All @@ -41,6 +56,11 @@ def test_command_line(self):
DATA_TYPES_DISPLAYED_CORRECTLY,
patterns=[" = B \| C \| 0x10$"],
)
self.expect(
'expression --format "enumeration with values" -- (enum bitfield)nonsense',
DATA_TYPES_DISPLAYED_CORRECTLY,
patterns=[" = B \(0x2\) \| C \(0x4\) \| 0x10$"],
)

# Break inside the main.
bkpt_id = lldbutil.run_break_set_by_file_and_line(
Expand Down
1 change: 1 addition & 0 deletions lldb/unittests/Core/DumpDataExtractorTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -160,6 +160,7 @@ TEST_F(DumpDataExtractorTest, Formats) {
TestDump<uint16_t>(99, lldb::Format::eFormatDecimal, "99");
// Just prints as a signed integer.
TestDump(-1, lldb::Format::eFormatEnum, "-1");
TestDump(-1, lldb::Format::eFormatEnumWithValues, "-1");
TestDump(0xcafef00d, lldb::Format::eFormatHex, "0xcafef00d");
TestDump(0xcafef00d, lldb::Format::eFormatHexUppercase, "0xCAFEF00D");
TestDump(0.456, lldb::Format::eFormatFloat, "0.45600000000000002");
Expand Down
16 changes: 16 additions & 0 deletions lldb/unittests/ValueObject/DumpValueObjectOptionsTests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -129,8 +129,12 @@ TEST_F(ValueObjectMockProcessTest, Enum) {
TestDumpValueObject(
MakeEnumType({{"test_2", 2}, {"test_3", 3}}),
{{0, {}, "(TestEnum) test_var = 0\n"},
{0, DumpValueObjectOptions().SetFormat(eFormatEnumWithValues),
"(TestEnum) test_var = 0\n"},
{1, {}, "(TestEnum) test_var = 1\n"},
{2, {}, "(TestEnum) test_var = test_2\n"},
{2, DumpValueObjectOptions().SetFormat(eFormatEnumWithValues),
"(TestEnum) test_var = test_2 (2)\n"},
{3, {}, "(TestEnum) test_var = test_3\n"},
{4, {}, "(TestEnum) test_var = 4\n"},
{5, {}, "(TestEnum) test_var = 5\n"},
Expand All @@ -141,6 +145,10 @@ TEST_F(ValueObjectMockProcessTest, Enum) {
{1, DumpValueObjectOptions().SetHideName(true), "(TestEnum) 1\n"},
{1, DumpValueObjectOptions().SetHideValue(true),
"(TestEnum) test_var =\n"},
{1,
DumpValueObjectOptions().SetHideValue(true).SetFormat(
eFormatEnumWithValues),
"(TestEnum) test_var =\n"},
{1, DumpValueObjectOptions().SetHideName(true).SetHideValue(true),
"(TestEnum) \n"}});
}
Expand All @@ -154,11 +162,19 @@ TEST_F(ValueObjectMockProcessTest, BitFieldLikeEnum) {
MakeEnumType({{"test_2", 2}, {"test_4", 4}}),
{
{0, {}, "(TestEnum) test_var =\n"},
{0, DumpValueObjectOptions().SetFormat(eFormatEnumWithValues),
"(TestEnum) test_var = 0x0\n"},
{1, {}, "(TestEnum) test_var = 0x1\n"},
{2, {}, "(TestEnum) test_var = test_2\n"},
{2, DumpValueObjectOptions().SetFormat(eFormatEnumWithValues),
"(TestEnum) test_var = test_2 (2)\n"},
{4, {}, "(TestEnum) test_var = test_4\n"},
{6, {}, "(TestEnum) test_var = test_2 | test_4\n"},
{6, DumpValueObjectOptions().SetFormat(eFormatEnumWithValues),
"(TestEnum) test_var = test_2 (0x2) | test_4 (0x4)\n"},
{7, {}, "(TestEnum) test_var = test_2 | test_4 | 0x1\n"},
{7, DumpValueObjectOptions().SetFormat(eFormatEnumWithValues),
"(TestEnum) test_var = test_2 (0x2) | test_4 (0x4) | 0x1\n"},
{8, {}, "(TestEnum) test_var = 0x8\n"},
{1, DumpValueObjectOptions().SetHideRootName(true),
"(TestEnum) 0x1\n"},
Expand Down
Loading