Skip to content
This repository was archived by the owner on Apr 2, 2020. It is now read-only.

Commit f025416

Browse files
authored
Merge pull request #2037 from fredriss/display-enum-bitfields
2 parents 07e08c1 + f93e313 commit f025416

File tree

4 files changed

+134
-44
lines changed

4 files changed

+134
-44
lines changed

lit/SymbolFile/DWARF/debug-types-missing-signature.test

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -22,5 +22,5 @@ PRINTEC: use of undeclared identifier 'EC'
2222

2323
RUN: %lldb %t -b -o "target variable a e ec" | FileCheck --check-prefix=VARS %s
2424
VARS: (const (anonymous struct)) a = {}
25-
VARS: (const (anonymous enum)) e = 1
26-
VARS: (const (anonymous enum)) ec = 1
25+
VARS: (const (anonymous enum)) e = 0x1
26+
VARS: (const (anonymous enum)) ec = 0x1

packages/Python/lldbsuite/test/lang/c/enum_types/TestEnumTypes.py

Lines changed: 26 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,35 @@ def test(self):
2525
exe = self.getBuildArtifact("a.out")
2626
self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET)
2727

28+
lldbutil.run_to_source_breakpoint(
29+
self, '// Breakpoint for bitfield', lldb.SBFileSpec("main.c"))
30+
31+
self.expect("fr var a", DATA_TYPES_DISPLAYED_CORRECTLY,
32+
patterns=[' = A$'])
33+
self.expect("fr var b", DATA_TYPES_DISPLAYED_CORRECTLY,
34+
patterns=[' = B$'])
35+
self.expect("fr var c", DATA_TYPES_DISPLAYED_CORRECTLY,
36+
patterns=[' = C$'])
37+
self.expect("fr var ab", DATA_TYPES_DISPLAYED_CORRECTLY,
38+
patterns=[' = AB$'])
39+
self.expect("fr var ac", DATA_TYPES_DISPLAYED_CORRECTLY,
40+
patterns=[' = A | C$'])
41+
self.expect("fr var all", DATA_TYPES_DISPLAYED_CORRECTLY,
42+
patterns=[' = ALL$'])
43+
# Test that an enum that doesn't match the heuristic we use in
44+
# ClangASTContext::DumpEnumValue, gets printed as a raw integer.
45+
self.expect("fr var omega", DATA_TYPES_DISPLAYED_CORRECTLY,
46+
patterns=[' = 7$'])
47+
# Test the behavior in case have a variable of a type considered
48+
# 'bitfield' by the heuristic, but the value isn't actually fully
49+
# covered by the enumerators.
50+
self.expect("p (enum bitfield)nonsense", DATA_TYPES_DISPLAYED_CORRECTLY,
51+
patterns=[' = B | C | 0x10$'])
52+
2853
# Break inside the main.
2954
bkpt_id = lldbutil.run_break_set_by_file_and_line(
3055
self, "main.c", self.line, num_expected_locations=1, loc_exact=True)
31-
32-
self.runCmd("run", RUN_SUCCEEDED)
56+
self.runCmd("c", RUN_SUCCEEDED)
3357

3458
# The stop reason of the thread should be breakpoint.
3559
self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT,

packages/Python/lldbsuite/test/lang/c/enum_types/main.c

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,20 @@ struct foo {
1818

1919
int main (int argc, char const *argv[])
2020
{
21+
enum bitfield {
22+
None = 0,
23+
A = 1 << 0,
24+
B = 1 << 1,
25+
C = 1 << 2,
26+
AB = A | B,
27+
ALL = A | B | C,
28+
};
29+
30+
enum non_bitfield {
31+
Alpha = 3,
32+
Beta = 4
33+
};
34+
2135
enum days {
2236
Monday = -3,
2337
Tuesday,
@@ -28,9 +42,14 @@ int main (int argc, char const *argv[])
2842
Sunday,
2943
kNumDays
3044
};
45+
46+
enum bitfield a = A, b = B, c = C, ab = AB, ac = A | C, all = ALL;
47+
int nonsense = a + b + c + ab + ac + all;
48+
enum non_bitfield omega = Alpha | Beta;
49+
3150
enum days day;
3251
struct foo f;
33-
f.op = NULL;
52+
f.op = NULL; // Breakpoint for bitfield
3453
for (day = Monday - 1; day <= kNumDays + 1; day++)
3554
{
3655
printf("day as int is %i\n", (int)day); // Set break point at this line.

source/Symbol/ClangASTContext.cpp

Lines changed: 86 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -9486,6 +9486,82 @@ void ClangASTContext::DumpValue(
94869486
}
94879487
}
94889488

9489+
static bool DumpEnumValue(const clang::QualType &qual_type, Stream *s,
9490+
const DataExtractor &data, lldb::offset_t byte_offset,
9491+
size_t byte_size, uint32_t bitfield_bit_offset,
9492+
uint32_t bitfield_bit_size) {
9493+
const clang::EnumType *enutype =
9494+
llvm::cast<clang::EnumType>(qual_type.getTypePtr());
9495+
const clang::EnumDecl *enum_decl = enutype->getDecl();
9496+
assert(enum_decl);
9497+
lldb::offset_t offset = byte_offset;
9498+
const uint64_t enum_svalue = data.GetMaxS64Bitfield(
9499+
&offset, byte_size, bitfield_bit_size, bitfield_bit_offset);
9500+
bool can_be_bitfield = true;
9501+
uint64_t covered_bits = 0;
9502+
int num_enumerators = 0;
9503+
9504+
// Try to find an exact match for the value.
9505+
// At the same time, we're applying a heuristic to determine whether we want
9506+
// to print this enum as a bitfield. We're likely dealing with a bitfield if
9507+
// every enumrator is either a one bit value or a superset of the previous
9508+
// enumerators. Also 0 doesn't make sense when the enumerators are used as
9509+
// flags.
9510+
for (auto enumerator : enum_decl->enumerators()) {
9511+
uint64_t val = enumerator->getInitVal().getSExtValue();
9512+
if (llvm::countPopulation(val) != 1 && (val & ~covered_bits) != 0)
9513+
can_be_bitfield = false;
9514+
covered_bits |= val;
9515+
++num_enumerators;
9516+
if (val == enum_svalue) {
9517+
// Found an exact match, that's all we need to do.
9518+
s->PutCString(enumerator->getNameAsString());
9519+
return true;
9520+
}
9521+
}
9522+
9523+
// No exact match, but we don't think this is a bitfield. Print the value as
9524+
// decimal.
9525+
if (!can_be_bitfield) {
9526+
s->Printf("%" PRIi64, enum_svalue);
9527+
return true;
9528+
}
9529+
9530+
// Unsigned values make more sense for flags.
9531+
offset = byte_offset;
9532+
const uint64_t enum_uvalue = data.GetMaxU64Bitfield(
9533+
&offset, byte_size, bitfield_bit_size, bitfield_bit_offset);
9534+
9535+
uint64_t remaining_value = enum_uvalue;
9536+
std::vector<std::pair<uint64_t, llvm::StringRef>> values;
9537+
values.reserve(num_enumerators);
9538+
for (auto enumerator : enum_decl->enumerators())
9539+
if (auto val = enumerator->getInitVal().getZExtValue())
9540+
values.emplace_back(val, enumerator->getName());
9541+
9542+
// Sort in reverse order of the number of the population count, so that in
9543+
// `enum {A, B, ALL = A|B }` we visit ALL first. Use a stable sort so that
9544+
// A | C where A is declared before C is displayed in this order.
9545+
std::stable_sort(values.begin(), values.end(), [](const auto &a, const auto &b) {
9546+
return llvm::countPopulation(a.first) > llvm::countPopulation(b.first);
9547+
});
9548+
9549+
for (const auto &val : values) {
9550+
if ((remaining_value & val.first) != val.first)
9551+
continue;
9552+
remaining_value &= ~val.first;
9553+
s->PutCString(val.second);
9554+
if (remaining_value)
9555+
s->PutCString(" | ");
9556+
}
9557+
9558+
// If there is a remainder that is not covered by the value, print it as hex.
9559+
if (remaining_value)
9560+
s->Printf("0x%" PRIx64, remaining_value);
9561+
9562+
return true;
9563+
}
9564+
94899565
bool ClangASTContext::DumpTypeValue(
94909566
lldb::opaque_compiler_type_t type, Stream *s, lldb::Format format,
94919567
const DataExtractor &data, lldb::offset_t byte_offset, size_t byte_size,
@@ -9500,6 +9576,13 @@ bool ClangASTContext::DumpTypeValue(
95009576
clang::QualType qual_type(GetQualType(type));
95019577

95029578
const clang::Type::TypeClass type_class = qual_type->getTypeClass();
9579+
9580+
if (type_class == clang::Type::Elaborated) {
9581+
qual_type = llvm::cast<clang::ElaboratedType>(qual_type)->getNamedType();
9582+
return DumpTypeValue(qual_type.getAsOpaquePtr(), s, format, data, byte_offset, byte_size,
9583+
bitfield_bit_size, bitfield_bit_offset, exe_scope, is_base_class);
9584+
}
9585+
95039586
switch (type_class) {
95049587
case clang::Type::Typedef: {
95059588
clang::QualType typedef_qual_type =
@@ -9530,45 +9613,9 @@ bool ClangASTContext::DumpTypeValue(
95309613
// If our format is enum or default, show the enumeration value as its
95319614
// enumeration string value, else just display it as requested.
95329615
if ((format == eFormatEnum || format == eFormatDefault) &&
9533-
GetCompleteType(type)) {
9534-
const clang::EnumType *enutype =
9535-
llvm::cast<clang::EnumType>(qual_type.getTypePtr());
9536-
const clang::EnumDecl *enum_decl = enutype->getDecl();
9537-
assert(enum_decl);
9538-
clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos;
9539-
const bool is_signed = qual_type->isSignedIntegerOrEnumerationType();
9540-
lldb::offset_t offset = byte_offset;
9541-
if (is_signed) {
9542-
const int64_t enum_svalue = data.GetMaxS64Bitfield(
9543-
&offset, byte_size, bitfield_bit_size, bitfield_bit_offset);
9544-
for (enum_pos = enum_decl->enumerator_begin(),
9545-
enum_end_pos = enum_decl->enumerator_end();
9546-
enum_pos != enum_end_pos; ++enum_pos) {
9547-
if (enum_pos->getInitVal().getSExtValue() == enum_svalue) {
9548-
s->PutCString(enum_pos->getNameAsString());
9549-
return true;
9550-
}
9551-
}
9552-
// If we have gotten here we didn't get find the enumerator in the
9553-
// enum decl, so just print the integer.
9554-
s->Printf("%" PRIi64, enum_svalue);
9555-
} else {
9556-
const uint64_t enum_uvalue = data.GetMaxU64Bitfield(
9557-
&offset, byte_size, bitfield_bit_size, bitfield_bit_offset);
9558-
for (enum_pos = enum_decl->enumerator_begin(),
9559-
enum_end_pos = enum_decl->enumerator_end();
9560-
enum_pos != enum_end_pos; ++enum_pos) {
9561-
if (enum_pos->getInitVal().getZExtValue() == enum_uvalue) {
9562-
s->PutCString(enum_pos->getNameAsString());
9563-
return true;
9564-
}
9565-
}
9566-
// If we have gotten here we didn't get find the enumerator in the
9567-
// enum decl, so just print the integer.
9568-
s->Printf("%" PRIu64, enum_uvalue);
9569-
}
9570-
return true;
9571-
}
9616+
GetCompleteType(type))
9617+
return DumpEnumValue(qual_type, s, data, byte_offset, byte_size,
9618+
bitfield_bit_offset, bitfield_bit_size);
95729619
// format was not enum, just fall through and dump the value as
95739620
// requested....
95749621
LLVM_FALLTHROUGH;

0 commit comments

Comments
 (0)