Index: lit/SymbolFile/DWARF/debug-types-missing-signature.test =================================================================== --- lit/SymbolFile/DWARF/debug-types-missing-signature.test +++ lit/SymbolFile/DWARF/debug-types-missing-signature.test @@ -22,5 +22,5 @@ RUN: %lldb %t -b -o "target variable a e ec" | FileCheck --check-prefix=VARS %s VARS: (const (anonymous struct)) a = {} -VARS: (const (anonymous enum)) e = 1 -VARS: (const (anonymous enum)) ec = 1 +VARS: (const (anonymous enum)) e = 0x1 +VARS: (const (anonymous enum)) ec = 0x1 Index: packages/Python/lldbsuite/test/lang/c/enum_types/TestEnumTypes.py =================================================================== --- packages/Python/lldbsuite/test/lang/c/enum_types/TestEnumTypes.py +++ packages/Python/lldbsuite/test/lang/c/enum_types/TestEnumTypes.py @@ -25,11 +25,26 @@ exe = self.getBuildArtifact("a.out") self.runCmd("file " + exe, CURRENT_EXECUTABLE_SET) + lldbutil.run_to_source_breakpoint( + self, '// Breakpoint for bitfield', lldb.SBFileSpec("main.c")) + + self.expect("fr var a", DATA_TYPES_DISPLAYED_CORRECTLY, + patterns=[' = A$']) + 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 all", DATA_TYPES_DISPLAYED_CORRECTLY, + patterns=[' = ALL$']) + # Break inside the main. bkpt_id = lldbutil.run_break_set_by_file_and_line( self, "main.c", self.line, num_expected_locations=1, loc_exact=True) - - self.runCmd("run", RUN_SUCCEEDED) + self.runCmd("c", RUN_SUCCEEDED) # The stop reason of the thread should be breakpoint. self.expect("thread list", STOPPED_DUE_TO_BREAKPOINT, Index: packages/Python/lldbsuite/test/lang/c/enum_types/main.c =================================================================== --- packages/Python/lldbsuite/test/lang/c/enum_types/main.c +++ packages/Python/lldbsuite/test/lang/c/enum_types/main.c @@ -18,6 +18,17 @@ int main (int argc, char const *argv[]) { + enum bitfield { + A = 1 << 0, + B = 1 << 1, + C = 1 << 2, + AB = A | B, + ALL = A | B | C, + }; + + enum bitfield a = A, b = B, c = C, ab = AB, ac = A | C, all = ALL; + int nonsense = a + b + c + ab + ac + all; // Breakpoint for bitfield + enum days { Monday = -3, Tuesday, Index: source/Symbol/ClangASTContext.cpp =================================================================== --- source/Symbol/ClangASTContext.cpp +++ source/Symbol/ClangASTContext.cpp @@ -9471,6 +9471,82 @@ } } +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) { + const clang::EnumType *enutype = + llvm::cast(qual_type.getTypePtr()); + const clang::EnumDecl *enum_decl = enutype->getDecl(); + assert(enum_decl); + lldb::offset_t offset = byte_offset; + const uint64_t enum_svalue = data.GetMaxS64Bitfield( + &offset, byte_size, bitfield_bit_size, bitfield_bit_offset); + bool can_be_bitfield = true; + uint64_t covered_bits = 0; + int num_enumerators = 0; + + // Try to find an exact match for the value. + // At the same time, we're applying a heuristic to determine whether we want + // to print this enum as a bitfield. We're likely dealing with a bitfield if + // every enumrator is either a one bit value or a superset of the previous + // enumerators. Also 0 doesn't make sense when the enumerators are used as + // flags. + for (auto enumerator : enum_decl->enumerators()) { + uint64_t val = enumerator->getInitVal().getSExtValue(); + if ((llvm::countPopulation(val) != 1 && (val & ~covered_bits) != 0) || + val == 0) + can_be_bitfield = false; + covered_bits |= val; + ++num_enumerators; + if (val == enum_svalue) { + s->PutCString(enumerator->getNameAsString()); + return true; + } + } + + // No exact match, but we don't think this is a bitfield. Print the value as + // decimal. + if (!can_be_bitfield) { + s->Printf("%" PRIi64, enum_svalue); + return true; + } + + // Unsigned values make more sense for flags. + offset = byte_offset; + const uint64_t enum_uvalue = data.GetMaxU64Bitfield( + &offset, byte_size, bitfield_bit_size, bitfield_bit_offset); + + uint64_t remaining_value = enum_uvalue; + std::vector> values; + values.reserve(num_enumerators); + for (auto enumerator : enum_decl->enumerators()) + values.emplace_back(enumerator->getInitVal().getZExtValue(), + enumerator->getName()); + + // Sort in reverse order of the number of set bits. This is so that + // in `enum {A, B, ALL = A|B }` we visit ALL first. + std::stable_sort( + values.begin(), values.end(), [](const auto &a, const auto &b) { + return llvm::countPopulation(a.first) > llvm::countPopulation(b.first); + }); + + for (const auto &val : values) { + if ((remaining_value & val.first) != val.first) + continue; + remaining_value &= ~val.first; + s->PutCString(val.second); + if (remaining_value) + s->PutCString(" | "); + } + + // If there is a remainder that is not covered by the value, print it as hex. + if (remaining_value) + s->Printf("0x%" PRIx64, remaining_value); + + return true; +} + bool ClangASTContext::DumpTypeValue( lldb::opaque_compiler_type_t type, Stream *s, lldb::Format format, const DataExtractor &data, lldb::offset_t byte_offset, size_t byte_size, @@ -9514,45 +9590,9 @@ // 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) && - GetCompleteType(type)) { - const clang::EnumType *enutype = - llvm::cast(qual_type.getTypePtr()); - const clang::EnumDecl *enum_decl = enutype->getDecl(); - assert(enum_decl); - clang::EnumDecl::enumerator_iterator enum_pos, enum_end_pos; - const bool is_signed = qual_type->isSignedIntegerOrEnumerationType(); - lldb::offset_t offset = byte_offset; - if (is_signed) { - const int64_t enum_svalue = data.GetMaxS64Bitfield( - &offset, byte_size, bitfield_bit_size, bitfield_bit_offset); - for (enum_pos = enum_decl->enumerator_begin(), - enum_end_pos = enum_decl->enumerator_end(); - enum_pos != enum_end_pos; ++enum_pos) { - if (enum_pos->getInitVal().getSExtValue() == enum_svalue) { - s->PutCString(enum_pos->getNameAsString()); - return true; - } - } - // If we have gotten here we didn't get find the enumerator in the - // enum decl, so just print the integer. - s->Printf("%" PRIi64, enum_svalue); - } else { - const uint64_t enum_uvalue = data.GetMaxU64Bitfield( - &offset, byte_size, bitfield_bit_size, bitfield_bit_offset); - for (enum_pos = enum_decl->enumerator_begin(), - enum_end_pos = enum_decl->enumerator_end(); - enum_pos != enum_end_pos; ++enum_pos) { - if (enum_pos->getInitVal().getZExtValue() == enum_uvalue) { - s->PutCString(enum_pos->getNameAsString()); - return true; - } - } - // If we have gotten here we didn't get find the enumerator in the - // enum decl, so just print the integer. - s->Printf("%" PRIu64, enum_uvalue); - } - return true; - } + GetCompleteType(type)) + return DumpEnumValue(qual_type, s, data, byte_offset, byte_size, + bitfield_bit_offset, bitfield_bit_size); // format was not enum, just fall through and dump the value as // requested.... LLVM_FALLTHROUGH;