diff --git a/.gitignore b/.gitignore index 20c4f52cd3786..30a973aed1fab 100644 --- a/.gitignore +++ b/.gitignore @@ -70,3 +70,7 @@ pythonenv* /clang/utils/analyzer/projects/*/RefScanBuildResults # automodapi puts generated documentation files here. /lldb/docs/python_api/ + + +_install/ +build/ diff --git a/clang/include/clang/AST/Decl.h b/clang/include/clang/AST/Decl.h index 863f6ac57f2aa..602335dc42e81 100644 --- a/clang/include/clang/AST/Decl.h +++ b/clang/include/clang/AST/Decl.h @@ -3149,6 +3149,22 @@ class FieldDecl : public DeclaratorDecl, public Mergeable { // Implement isa/cast/dyncast/etc. static bool classof(const Decl *D) { return classofKind(D->getKind()); } static bool classofKind(Kind K) { return K >= firstField && K <= lastField; } + +private: + uint64_t m_variant_discr_value = UINT64_MAX; + +public: + void setVariantDiscrValue(uint64_t value) { + m_variant_discr_value = value; + } + + uint64_t getVariantDiscrValue() { + return m_variant_discr_value; + } + + bool hasVariantDiscrValue() { + return getVariantDiscrValue() != UINT64_MAX; + } }; /// An instance of this object exists for each enum constant diff --git a/clang/include/clang/AST/DeclCXX.h b/clang/include/clang/AST/DeclCXX.h index 11276c77490ce..376d779fead80 100644 --- a/clang/include/clang/AST/DeclCXX.h +++ b/clang/include/clang/AST/DeclCXX.h @@ -1835,6 +1835,27 @@ class CXXRecordDecl : public RecordDecl { return K >= firstCXXRecord && K <= lastCXXRecord; } void markAbstract() { data().Abstract = true; } + +private: + bool m_is_variant = false; + int64_t m_offset_record_from_pointer = 0; + +public: + bool isVariant() const { + return m_is_variant; + } + + void setVariant(bool is_variant) { + m_is_variant = is_variant; + } + + int64_t getOffsetRecordFromPointer() const { + return m_offset_record_from_pointer; + } + + void setOffsetRecordFromPointer(int64_t offset) { + m_offset_record_from_pointer = offset; + } }; /// Store information needed for an explicit specifier. diff --git a/clang/lib/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp index 2d06faeca1823..a65001a7bc5e1 100644 --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -544,7 +544,14 @@ void TypePrinter::printIncompleteArrayBefore(const IncompleteArrayType *T, void TypePrinter::printIncompleteArrayAfter(const IncompleteArrayType *T, raw_ostream &OS) { - OS << "[]"; + // CR sspies: If we stick with this, we should find a way to propagate the + // language information here. Once we add a type def with an explicit name + // for the top-level type, custom printing will no longer be needed. + bool is_ocaml = true; + + if (is_ocaml) OS << " array"; + else OS << "[]"; + printAfter(T->getElementType(), OS); } diff --git a/lldb/include/lldb/Core/ValueObject.h b/lldb/include/lldb/Core/ValueObject.h index a666d0bab1730..ae1c8a12ce6db 100644 --- a/lldb/include/lldb/Core/ValueObject.h +++ b/lldb/include/lldb/Core/ValueObject.h @@ -361,6 +361,10 @@ class ValueObject { virtual lldb::ValueType GetValueType() const = 0; + // XXX mshinwell: why don't any of the following three functions get + // called for displaying the type names in parameter lists and + // "frame var"? + // Subclasses can implement the functions below. virtual ConstString GetTypeName() { return GetCompilerType().GetTypeName(); } diff --git a/lldb/include/lldb/Symbol/SymbolFile.h b/lldb/include/lldb/Symbol/SymbolFile.h index 8548973bad3ff..4209835633ca2 100644 --- a/lldb/include/lldb/Symbol/SymbolFile.h +++ b/lldb/include/lldb/Symbol/SymbolFile.h @@ -205,6 +205,7 @@ class SymbolFile : public PluginInterface { /// To support variable-length array types, this function takes an /// optional \p ExecutionContext. If \c exe_ctx is non-null, the /// dynamic characteristics for that context are returned. + // CR mshinwell: maybe we could use this? virtual std::optional GetDynamicArrayInfoForUID(lldb::user_id_t type_uid, const lldb_private::ExecutionContext *exe_ctx) = 0; diff --git a/lldb/include/lldb/Utility/DataExtractor.h b/lldb/include/lldb/Utility/DataExtractor.h index dbf0bce8c8d0d..4404f209f8f93 100644 --- a/lldb/include/lldb/Utility/DataExtractor.h +++ b/lldb/include/lldb/Utility/DataExtractor.h @@ -991,6 +991,14 @@ class DataExtractor { uint8_t(GetAddressByteSize())}; } + void setDataOriginalSource(lldb::addr_t ptr) { + m_data_original_source = ptr; + } + + lldb::addr_t getDataOriginalSource() const { + return m_data_original_source; + } + protected: template T Get(lldb::offset_t *offset_ptr, T fail_value) const { constexpr size_t src_size = sizeof(T); @@ -1018,6 +1026,8 @@ class DataExtractor { lldb::DataBufferSP m_data_sp; /// Making it const would require implementation of move assignment operator. uint32_t m_target_byte_size = 1; + /// Temporary hack for reading more data from the source than is currently available. + lldb::addr_t m_data_original_source = 0; }; } // namespace lldb_private diff --git a/lldb/include/lldb/lldb-enumerations.h b/lldb/include/lldb/lldb-enumerations.h index d5cc525d2c826..1e9688bcd3e9b 100644 --- a/lldb/include/lldb/lldb-enumerations.h +++ b/lldb/include/lldb/lldb-enumerations.h @@ -1080,7 +1080,10 @@ FLAGS_ENUM(TypeFlags){ eTypeIsVector = (1u << 16), eTypeIsScalar = (1u << 17), eTypeIsInteger = (1u << 18), eTypeIsFloat = (1u << 19), eTypeIsComplex = (1u << 20), eTypeIsSigned = (1u << 21), - eTypeInstanceIsPointer = (1u << 22)}; + eTypeInstanceIsPointer = (1u << 22),eTypeIsOCaml = (1u << 23)}; + +// FIXME: The info eTypeIsOCaml is currently unused. If this information never +// becomes useful, remove the flag from the enum above. FLAGS_ENUM(CommandFlags){ /// eCommandRequiresTarget diff --git a/lldb/source/Core/DumpDataExtractor.cpp b/lldb/source/Core/DumpDataExtractor.cpp index 4f9cc54cd8b8a..a132547f16ab7 100644 --- a/lldb/source/Core/DumpDataExtractor.cpp +++ b/lldb/source/Core/DumpDataExtractor.cpp @@ -338,6 +338,92 @@ static const llvm::fltSemantics &GetFloatSemantics(const TargetSP &target_sp, return llvm::APFloat::Bogus(); } + +static std::optional ReadAPIntFromMemory(const DataExtractor &data, Process * process, + lldb::addr_t load_addr, + size_t byte_size) { + if (byte_size == 0) + return std::nullopt; + + llvm::SmallVector uint64_array; + size_t bytes_left = byte_size; + uint64_t u64; + Status error; + const lldb::ByteOrder byte_order = data.GetByteOrder(); + if (byte_order == lldb::eByteOrderLittle) { + while (bytes_left > 0) { + if (bytes_left >= 8) { + u64 = process->ReadUnsignedIntegerFromMemory(load_addr, 8, 0, error); + bytes_left -= 8; + load_addr += 8; + if (error.Fail()) + return std::nullopt; + } else { + u64 = process->ReadUnsignedIntegerFromMemory(load_addr, bytes_left, 0, error); + if (error.Fail()) + return std::nullopt; + bytes_left = 0; + } + uint64_array.push_back(u64); + } + return llvm::APInt(byte_size * 8, llvm::ArrayRef(uint64_array)); + } + // CR sspies: big endian not supported + return std::nullopt; +} + + + +void PrintAPIntAsFloat(Stream *s, llvm::APInt apint, + const llvm::fltSemantics &semantics, + std::optional format_max_padding, + std::string prefix = "", std::string suffix = "") { + + llvm::APFloat apfloat(semantics, apint); + llvm::SmallVector sv; + if (format_max_padding) + apfloat.toPossiblyShortString(sv, *format_max_padding); + else + apfloat.toPossiblyShortString(sv); + + s->AsRawOstream() << prefix; + s->AsRawOstream() << sv; + // OCaml Specific: + // Following OCaml conventions, print the trailing "." to + // identify that the integer is in fact a float, but don't + // print any trailing zeros. + bool print_trailing_dot = true; + for (char c : sv) { + switch (c) { + case '-': + case '0': + case '1': + case '2': + case '3': + case '4': + case '5': + case '6': + case '7': + case '8': + case '9': + continue; + default: + // if we find something that is not a number such as 'e' or 'E' or '.' + // there is no need to print the trailing ".". + print_trailing_dot = false; + } + break; // we found something that is not a number, so we will not print + // the trailing "." + } + if (print_trailing_dot){ + s->AsRawOstream() << "."; + } + + s->AsRawOstream() << suffix; + +} + + static offset_t FormatOCamlValue(const DataExtractor &DE, Stream *s, offset_t start_offset, uint64_t base_addr, ExecutionContextScope *exe_ctx_scope, @@ -365,6 +451,16 @@ static offset_t FormatOCamlValue(const DataExtractor &DE, Stream *s, exe_ctx_scope->CalculateExecutionContext(exe_ctx); Process *process = exe_ctx.GetProcessPtr(); + // max padding for floating point numbers + TargetSP target_sp; + if (exe_ctx_scope) + target_sp = exe_ctx_scope->CalculateTarget(); + + std::optional format_max_padding; + if (target_sp) + format_max_padding = target_sp->GetMaxZeroPaddingInFloatFormat(); + + if (process) { Status error; lldb::addr_t header = process->ReadPointerFromMemory(value - 8, error); @@ -497,51 +593,40 @@ static offset_t FormatOCamlValue(const DataExtractor &DE, Stream *s, } case 253: { // Double_tag - union { - double f; - uint64_t i; - } u; - u.i = process->ReadUnsignedIntegerFromMemory(value, 8, 0, error); - if (error.Fail()) { + std::optional apint = ReadAPIntFromMemory(DE, process, value, 8); + if (!apint) { s->Printf("@"); - } else { - // CR mshinwell: should probably use proper float printing code - // elsewhere in this file - s->Printf("%g", u.f); - print_default = false; + break; } + const llvm::fltSemantics &semantics = llvm::APFloat::IEEEdouble(); + PrintAPIntAsFloat(s, *apint, semantics, format_max_padding); + print_default = false; break; } case 254: { // Double_array_tag // N.B. Empty float arrays have tag zero uint64_t wosize_to_print = wosize <= 10 ? wosize : 10; - s->Printf("[|"); + print_default = false; // we still print the default if one of the fields fails + s->Printf("[| "); for (uint64_t field = 0; field < wosize_to_print; field++) { - union { - double f; - uint64_t i; - } u; - u.i = process->ReadUnsignedIntegerFromMemory(value, 8, 0, error); - if (error.Fail()) { + std::optional apint = ReadAPIntFromMemory(DE, process, value + field * 8, 8); + if (!apint) { s->Printf("", field); + print_default = true; } else { - // CR mshinwell: should probably use proper float printing code - // elsewhere in this file - s->Printf("%g", u.f); + const llvm::fltSemantics &semantics = llvm::APFloat::IEEEdouble(); + PrintAPIntAsFloat(s, *apint, semantics, format_max_padding); } if (field < wosize_to_print - 1) - s->Printf(", "); + s->Printf("; "); } if (wosize_to_print < wosize) { - s->Printf(", <%" PRIu64 " more elements in floatarray>", + s->Printf("; <%" PRIu64 " more elements in floatarray>", wosize - wosize_to_print); } - s->Printf("|]"); - - if (!error.Fail()) - print_default = false; + s->Printf(" |]"); break; } @@ -612,7 +697,17 @@ static offset_t FormatOCamlValue(const DataExtractor &DE, Stream *s, (void *)bigarray_data_ptr); print_default = false; } - } else { + } else if (identifier_str == "_f32") { + std::optional apint = ReadAPIntFromMemory(DE, process, value + 8, 4); + if (!apint) { + s->Printf("@"); + break; + } + const llvm::fltSemantics &semantics = llvm::APFloat::IEEEsingle(); + PrintAPIntAsFloat(s, *apint, semantics, format_max_padding, "", "s"); + print_default = false; + } + else { // CR mshinwell: check about converting Address.t to (void*) s->Printf("@", identifier_str.c_str()); } @@ -987,9 +1082,6 @@ lldb::offset_t lldb_private::DumpDataExtractor( if (target_sp) format_max_padding = target_sp->GetMaxZeroPaddingInFloatFormat(); - // Show full precision when printing float values - const unsigned format_precision = 0; - const llvm::fltSemantics &semantics = GetFloatSemantics(target_sp, item_byte_size); @@ -1001,13 +1093,12 @@ lldb::offset_t lldb_private::DumpDataExtractor( std::optional apint = GetAPInt(DE, &offset, semantics_byte_size); if (apint) { - llvm::APFloat apfloat(semantics, *apint); - llvm::SmallVector sv; - if (format_max_padding) - apfloat.toString(sv, format_precision, *format_max_padding); - else - apfloat.toString(sv, format_precision); - s->AsRawOstream() << sv; + std::string suffix = ""; + if (semantics_byte_size == 4){ + suffix = "s"; + } + PrintAPIntAsFloat(s, *apint, semantics, + format_max_padding, "#", suffix); } else { s->Format("error: unsupported byte size ({0}) for float format", item_byte_size); diff --git a/lldb/source/Core/ValueObject.cpp b/lldb/source/Core/ValueObject.cpp index 38645b087435d..f389ef4e2082b 100644 --- a/lldb/source/Core/ValueObject.cpp +++ b/lldb/source/Core/ValueObject.cpp @@ -515,6 +515,10 @@ bool ValueObject::MightHaveChildren() { bool has_children = false; const uint32_t type_info = GetTypeInfo(); if (type_info) { + // FIXME: Previous versions of this code have disabled children for pointers + // and references. This did not seem to have any effect. If this becomes + // necessary again, information about OCaml can be propagated here via the + // the type info, to which we can add `eTypeIsOCaml`. if (type_info & (eTypeHasChildren | eTypeIsPointer | eTypeIsReference)) has_children = true; } else { @@ -1147,6 +1151,7 @@ bool ValueObject::HasSpecialPrintableRepresentation( return true; if (flags.Test(eTypeIsArray)) { + // XXX mshinwell: this should be disabled for OCaml if ((custom_format == eFormatBytes) || (custom_format == eFormatBytesWithASCII)) return true; @@ -1362,12 +1367,28 @@ bool ValueObject::DumpPrintableRepresentation( if (val_obj_display == eValueObjectRepresentationStyleValue) str = GetSummaryAsCString(); else if (val_obj_display == eValueObjectRepresentationStyleSummary) { + // XXX mshinwell: need to test for OCaml language here. + // CR sspies: We transform the type here. This becomes obsolete, once + // we equip the top-level types with a type alias. + std::string type_name_str(GetTypeName().AsCString()); + for (std::string to_erase : {"(&) ", " &"}) { + for (auto iter = type_name_str.find(to_erase); iter != std::string::npos; + iter = type_name_str.find(to_erase)) { + type_name_str.erase(iter, to_erase.size()); + } + } + // CR sspies: We print types where LLDB does not printing them usually. + // Perhaps we should only print the value, not the type? if (!CanProvideValue()) { - strm.Printf("%s @ %s", GetTypeName().AsCString(), - GetLocationAsCString()); + strm.Printf(" : %s", type_name_str.c_str()); + // strm.Printf("%s @ %s", GetTypeName().AsCString(), + // GetLocationAsCString()); str = strm.GetString(); - } else - str = GetValueAsCString(); + } else { + strm.Printf("%s : %s", GetValueAsCString(), type_name_str.c_str()); + str = strm.GetString(); +// str = GetValueAsCString(); + } } } diff --git a/lldb/source/DataFormatters/ValueObjectPrinter.cpp b/lldb/source/DataFormatters/ValueObjectPrinter.cpp index 6fd6308ded5d9..b47fe228bd43f 100644 --- a/lldb/source/DataFormatters/ValueObjectPrinter.cpp +++ b/lldb/source/DataFormatters/ValueObjectPrinter.cpp @@ -257,6 +257,8 @@ void ValueObjectPrinter::PrintDecl() { type_name_str.erase(iter, 2); } } + // FIXME: Previous versions of this code removed ampersands here. But we + // probably do not need to do that. typeName << type_name_str.c_str(); } } @@ -672,6 +674,7 @@ void ValueObjectPrinter::PrintChildren( bool any_children_printed = false; for (size_t idx = 0; idx < num_children; ++idx) { + // mshinwell: maybe we could use synthetic children for array printing? if (ValueObjectSP child_sp = GenerateChild(synth_m_valobj, idx)) { if (!any_children_printed) { PrintChildrenPreamble(); @@ -685,15 +688,24 @@ void ValueObjectPrinter::PrintChildren( PrintChildrenPostamble(print_dotdotdot); else { if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) { + // CR sspies: Is this still relevant? We do or will introduce lots of + // type aliases with the names, so getting the printing from the DWARF + // right should not be important anymore. + /* XXX don't want {} after arrays if (ShouldPrintValueObject()) m_stream->PutCString(" {}\n"); else + */ m_stream->EOL(); } else m_stream->EOL(); } } else if (ShouldPrintEmptyBrackets(value_printed, summary_printed)) { // Aggregate, no children... + m_stream->PutCString("\n"); +// XXX mshinwell +// CR sspies: Same here. +/* if (ShouldPrintValueObject()) { // if it has a synthetic value, then don't print {}, the synthetic // children are probably only being used to vend a value @@ -703,6 +715,7 @@ void ValueObjectPrinter::PrintChildren( else m_stream->PutCString(" {}\n"); } +*/ } else { if (ShouldPrintValueObject()) m_stream->EOL(); @@ -760,6 +773,7 @@ void ValueObjectPrinter::PrintChildrenIfNeeded(bool value_printed, DumpValueObjectOptions::PointerDepth curr_ptr_depth = m_ptr_depth; const bool print_children = + m_valobj->MightHaveChildren() && ShouldPrintChildren(is_failed_description, curr_ptr_depth); const bool print_oneline = (curr_ptr_depth.CanAllowExpansion() || m_options.m_show_types || diff --git a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp index 58e81fb1cd745..e6e4de9191fce 100644 --- a/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp +++ b/lldb/source/Plugins/ExpressionParser/Clang/ClangExpressionParser.cpp @@ -703,7 +703,7 @@ ClangExpressionParser::ClangExpressionParser( clang::ASTContext &ast_context = m_compiler->getASTContext(); m_ast_context = std::make_shared( - "Expression ASTContext for '" + m_filename + "'", ast_context); + "Expression ASTContext for '" + m_filename + "'", ast_context, language); std::string module_name("$__lldb_module"); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp index 56bd089b86a1e..abce38d1af344 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp @@ -396,6 +396,9 @@ ParsedDWARFTypeAttributes::ParsedDWARFTypeAttributes(const DWARFDIE &die) { case DW_AT_reference: ref_qual = clang::RQ_LValue; break; + case DW_AT_offset_record_from_pointer: + offset_record_from_pointer = form_value.Signed(); + break; } } } @@ -1910,6 +1913,13 @@ DWARFASTParserClang::ParseStructureLikeDIE(const SymbolContext &sc, record_decl->setArgPassingRestrictions( clang::RecordDecl::APK_CannotPassInRegs); } + + clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl(clang_type.GetOpaqueQualType()); + if (record_decl) { + record_decl->setImplicit(); + record_decl->setOffsetRecordFromPointer(attrs.offset_record_from_pointer); + } return type_sp; } @@ -2726,7 +2736,7 @@ void DWARFASTParserClang::ParseSingleMember( const lldb_private::CompilerType &class_clang_type, lldb::AccessType default_accessibility, lldb_private::ClangASTImporter::LayoutInfo &layout_info, - FieldInfo &last_field_info) { + FieldInfo &last_field_info, uint64_t variant_discr_value) { Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups); // This function can only parse DW_TAG_member. assert(die.Tag() == DW_TAG_member); @@ -2936,8 +2946,11 @@ void DWARFASTParserClang::ParseSingleMember( // artificial member with (unnamed bitfield) padding. // FIXME: This check should verify that this is indeed an artificial member // we are supposed to ignore. - if (attrs.is_artificial) - return; + // if (attrs.is_artificial) + // return; + // CR sspies: For some reason, a previous version added + // if (!attrs.is_artificial) only for the next if instruction. We should + // figure out how to get back to the right behavior for artificial fields. if (!member_clang_type.IsCompleteType()) member_clang_type.GetCompleteType(); @@ -2981,7 +2994,7 @@ void DWARFASTParserClang::ParseSingleMember( clang::FieldDecl *field_decl = TypeSystemClang::AddFieldToRecordType( class_clang_type, attrs.name, member_clang_type, attrs.accessibility, - attrs.bit_size); + attrs.bit_size, variant_discr_value, attrs.is_artificial); m_ast.SetMetadataAsUserID(field_decl, die.GetID()); @@ -2989,6 +3002,67 @@ void DWARFASTParserClang::ParseSingleMember( std::make_pair(field_decl, field_bit_offset)); } +void DWARFASTParserClang::ParseVariantPart( + const DWARFDIE &die, const DWARFDIE &parent_die, + const lldb_private::CompilerType &class_clang_type, + lldb::AccessType default_accessibility, + lldb_private::ClangASTImporter::LayoutInfo &layout_info, + FieldInfo &last_field_info) { + Log *log = GetLog(DWARFLog::TypeCompletion | DWARFLog::Lookups); + assert(die.Tag() == DW_TAG_variant_part); + + // Getting the type of DW_AT_discr in the DW_TAG_variant_part die. + DWARFAttributes attributes; + const size_t num_attributes = die.GetAttributes(attributes); + DWARFFormValue encoding_form; + for (std::size_t i = 0; i < num_attributes; ++i) { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attr == DW_AT_discr && attributes.ExtractFormValueAtIndex(i, form_value)) + encoding_form = form_value; + } + const DWARFDIE &discr_member_die = encoding_form.Reference(); + + // Adding the DW_TAG_member of the DW_AT_discr directly under the struct. + ParseSingleMember(discr_member_die, parent_die, class_clang_type, + default_accessibility, layout_info, last_field_info); + + // Under DW_TAG_variant_part there are multiple DW_TAG_variant, each + // has a DW_TAG_member. We're adding all of the members directly under the struct + // with the DW_AT_discr_value of the DW_TAG_variant. + for (DWARFDIE variant_die : die.children()) + if (variant_die.Tag() == DW_TAG_variant) { + + // Getting the DW_AT_discr_value. + uint64_t uval64 = UINT64_MAX; + DWARFAttributes attributes; + const size_t num_attributes = variant_die.GetAttributes(attributes); + for (std::size_t i = 0; i < num_attributes; ++i) { + const dw_attr_t attr = attributes.AttributeAtIndex(i); + DWARFFormValue form_value; + if (attr == DW_AT_discr_value && + attributes.ExtractFormValueAtIndex(i, form_value)) { + uval64 = form_value.Unsigned(); + } + } + // For now, we don't support default variants, which don't have the DW_AT_discr_value. + if (uval64 == UINT64_MAX) + LLDB_LOG(log, "Failed to find a discriminant member in a variant."); + + // Adding each DW_TAG_member directly under the struct. + for (DWARFDIE member_child_die : variant_die.children()) + if (member_child_die.Tag() == DW_TAG_member) + ParseSingleMember(member_child_die, parent_die, class_clang_type, + default_accessibility, layout_info, last_field_info, uval64); + } + + // Setting a flag in CXXRecordDecl for custom printing of the variant. + clang::CXXRecordDecl *record_decl = + m_ast.GetAsCXXRecordDecl(class_clang_type.GetOpaqueQualType()); + if (record_decl) + record_decl->setVariant(true); +} + bool DWARFASTParserClang::ParseChildMembers( const DWARFDIE &parent_die, CompilerType &class_clang_type, std::vector> &base_classes, @@ -3020,6 +3094,11 @@ bool DWARFASTParserClang::ParseChildMembers( default_accessibility, layout_info, last_field_info); break; + case DW_TAG_variant_part: + ParseVariantPart(die, parent_die, class_clang_type, + default_accessibility, layout_info, last_field_info); + break; + case DW_TAG_subprogram: // Let the type parsing code handle this one for us. member_function_dies.push_back(die); diff --git a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h index 0733d22a0069b..6955e4ba6eba1 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.h @@ -243,6 +243,13 @@ class DWARFASTParserClang : public DWARFASTParser { void ParseSingleMember(const DWARFDIE &die, const DWARFDIE &parent_die, + const lldb_private::CompilerType &class_clang_type, + lldb::AccessType default_accessibility, + lldb_private::ClangASTImporter::LayoutInfo &layout_info, + FieldInfo &last_field_info, uint64_t variant_discr_value = UINT64_MAX); + + void + ParseVariantPart(const DWARFDIE &die, const DWARFDIE &parent_die, const lldb_private::CompilerType &class_clang_type, lldb::AccessType default_accessibility, lldb_private::ClangASTImporter::LayoutInfo &layout_info, @@ -325,6 +332,7 @@ struct ParsedDWARFTypeAttributes { clang::RQ_None; ///< Indicates ref-qualifier of ///< C++ member function if present. ///< Is RQ_None otherwise. + int64_t offset_record_from_pointer = 0; }; #endif // LLDB_SOURCE_PLUGINS_SYMBOLFILE_DWARF_DWARFASTPARSERCLANG_H diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp index fed616914b824..3cbc56e5f43a3 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp @@ -8,6 +8,7 @@ #include "TypeSystemClang.h" +#include "clang/AST/DeclCXX.h" #include "llvm/Support/FormatAdapters.h" #include "llvm/Support/FormatVariadic.h" @@ -75,6 +76,7 @@ #include "Plugins/SymbolFile/DWARF/DWARFASTParserClang.h" #include "Plugins/SymbolFile/PDB/PDBASTParser.h" #include "Plugins/SymbolFile/NativePDB/PdbAstBuilder.h" +#include "lldb/lldb-types.h" #include @@ -556,8 +558,10 @@ static void ParseLangArgs(LangOptions &Opts, InputKind IK, const char *triple) { } TypeSystemClang::TypeSystemClang(llvm::StringRef name, - llvm::Triple target_triple) { + llvm::Triple target_triple, + lldb::LanguageType language) { m_display_name = name.str(); + m_language = language; if (!target_triple.str().empty()) SetTargetTriple(target_triple.str()); // The caller didn't pass an ASTContext so create a new one for this @@ -566,8 +570,10 @@ TypeSystemClang::TypeSystemClang(llvm::StringRef name, } TypeSystemClang::TypeSystemClang(llvm::StringRef name, - ASTContext &existing_ctxt) { + ASTContext &existing_ctxt, + lldb::LanguageType language) { m_display_name = name.str(); + m_language = language; SetTargetTriple(existing_ctxt.getTargetInfo().getTriple().str()); m_ast_up.reset(&existing_ctxt); @@ -609,7 +615,7 @@ lldb::TypeSystemSP TypeSystemClang::CreateInstance(lldb::LanguageType language, if (module) { std::string ast_name = "ASTContext for '" + module->GetFileSpec().GetPath() + "'"; - return std::make_shared(ast_name, triple); + return std::make_shared(ast_name, triple, language); } else if (target && target->IsValid()) return std::make_shared(*target, triple); return lldb::TypeSystemSP(); @@ -2850,7 +2856,6 @@ bool TypeSystemClang::IsAggregateType(lldb::opaque_compiler_type_t type) { case clang::Type::ConstantArray: case clang::Type::ExtVector: case clang::Type::Vector: - case clang::Type::Record: case clang::Type::ObjCObject: case clang::Type::ObjCInterface: return true; @@ -3992,14 +3997,18 @@ TypeSystemClang::GetTypeInfo(lldb::opaque_compiler_type_t type, return 0; case clang::Type::LValueReference: - case clang::Type::RValueReference: + case clang::Type::RValueReference: { if (pointee_or_element_clang_type) pointee_or_element_clang_type->SetCompilerType( weak_from_this(), llvm::cast(qual_type.getTypePtr()) ->getPointeeType() .getAsOpaquePtr()); - return eTypeHasChildren | eTypeIsReference | eTypeHasValue; + if (isLanguageOCaml()) + return eTypeHasValue | eTypeIsOCaml; + else + return eTypeHasChildren | eTypeIsReference | eTypeHasValue; + } break; case clang::Type::MemberPointer: return eTypeIsPointer | eTypeIsMember | eTypeHasValue; @@ -4023,8 +4032,12 @@ TypeSystemClang::GetTypeInfo(lldb::opaque_compiler_type_t type, return eTypeHasChildren | eTypeIsPointer | eTypeHasValue; case clang::Type::Record: - if (qual_type->getAsCXXRecordDecl()) - return eTypeHasChildren | eTypeIsClass | eTypeIsCPlusPlus; + if (clang::CXXRecordDecl *record_decl = qual_type->getAsCXXRecordDecl()) { + if (isLanguageOCaml()) + return eTypeHasValue | eTypeIsClass | eTypeIsCPlusPlus | eTypeIsOCaml; + else + return eTypeHasChildren | eTypeIsClass | eTypeIsCPlusPlus; + } else return eTypeHasChildren | eTypeIsStructUnion; break; @@ -5311,7 +5324,8 @@ lldb::Format TypeSystemClang::GetFormat(lldb::opaque_compiler_type_t type) { case clang::Type::ObjCInterface: break; case clang::Type::Record: - break; + // CR sspies: Behavior changed here to use default formatting. + return lldb::eFormatDefault; case clang::Type::Enum: return lldb::eFormatEnum; case clang::Type::DependentSizedArray: @@ -7398,7 +7412,7 @@ TypeSystemClang::GetAsObjCInterfaceDecl(const CompilerType &type) { clang::FieldDecl *TypeSystemClang::AddFieldToRecordType( const CompilerType &type, llvm::StringRef name, const CompilerType &field_clang_type, AccessType access, - uint32_t bitfield_bit_size) { + uint32_t bitfield_bit_size, uint64_t variant_discr_value, bool is_artificial) { if (!type.IsValid() || !field_clang_type.IsValid()) return nullptr; auto ts = type.GetTypeSystem(); @@ -7429,6 +7443,9 @@ clang::FieldDecl *TypeSystemClang::AddFieldToRecordType( field->setType(ClangUtil::GetQualType(field_clang_type)); if (bit_width) field->setBitWidth(bit_width); + field->setVariantDiscrValue(variant_discr_value); + if (is_artificial) + record_decl->setImplicit(false); SetMemberOwningModule(field, record_decl); if (name.empty()) { @@ -8657,7 +8674,8 @@ void TypeSystemClang::DumpValue( field_byte_offset = field_bit_offset / 8; assert(field_bit_offset % 8 == 0); if (child_idx == 0) - s->PutChar('{'); + s->PutChar('!'); + // CR sspies: Not sure why we changed this one from { else s->PutChar(','); @@ -8703,7 +8721,8 @@ void TypeSystemClang::DumpValue( // Print the starting squiggly bracket (if this is the first member) or // comma (for member 2 and beyond) for the struct/union/class member. if (child_idx == 0) - s->PutChar('{'); + s->PutChar('$'); + // CR sspies: Not sure why we changed this one from { else s->PutChar(','); @@ -8825,7 +8844,8 @@ void TypeSystemClang::DumpValue( // Print the starting squiggly bracket (if this is the first member) or // comman (for member 2 and beyong) for the struct/union/class member. if (element_idx == 0) - s->PutChar('{'); + s->PutChar('^'); + // CR sspies: Not sure why we changed this one from { else s->PutChar(','); @@ -9060,6 +9080,300 @@ static bool DumpEnumValue(const clang::QualType &qual_type, Stream *s, return true; } +#define ASSERT_USE_FALLBACK_PRINTING(boolean, data, byte_offset) \ + if (!(boolean)) { \ + LLDB_LOG(GetLog(LLDBLog::Target), "Failure in DumpTypeValue(): " #boolean); \ + DumpDataExtractor(data, s, byte_offset, eFormatOCamlValue, 8, 1, \ + UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0, \ + exe_scope); \ + return true; \ + } + +bool DumpTypeVariant(const clang::QualType &qual_type, Stream *s, + const DataExtractor &data, lldb::offset_t byte_offset, + size_t byte_size, ExecutionContextScope *exe_scope, + TypeSystemClang *type_system_clang, + const clang::RecordDecl *record_decl, + const clang::CXXRecordDecl *cxx_record_decl, + Process *process) { + // At this point, we know that the record represents a variant. + // We first retrieve the CXXRecordDecl in which are the member fields + // that contains the DW_AT_discr_value. + // Finding the {pointer, idx of child} of the field which contains the discriminant. + std::pair discr_field = {nullptr, 0}; + for (clang::FieldDecl *field_decl : cxx_record_decl->fields()) { + if (!field_decl->hasVariantDiscrValue()) { + ASSERT_USE_FALLBACK_PRINTING(discr_field.first == nullptr, data, byte_offset); + discr_field.first = field_decl; + break; + } + ++discr_field.second; + } + ASSERT_USE_FALLBACK_PRINTING(discr_field.first != nullptr, data, byte_offset); + + auto get_bit_size = [&](clang::FieldDecl *field, uint32_t field_idx) { + clang::QualType field_type = field->getType(); + CompilerType field_clang_type = type_system_clang->GetType(field_type); + unsigned int field_bit_size; + if (field->isBitField()) { + field_bit_size = field->getBitWidthValue(type_system_clang->getASTContext()); + } + else { + std::optional size = field_clang_type.GetByteSize(exe_scope); + assert(size && *size < UINT32_MAX); + field_bit_size = 8 * (unsigned int) *size; + } + return field_bit_size; + }; + + // Getting the discriminant value. + const clang::ASTRecordLayout &record_layout = + type_system_clang->getASTContext().getASTRecordLayout(record_decl); + unsigned int discr_bit_size = get_bit_size(discr_field.first, discr_field.second); + unsigned int discr_bit_offset = record_layout.getFieldOffset(discr_field.second); + lldb::offset_t discr_byte_offset = byte_offset; + const uint64_t discr_value = data.GetMaxU64Bitfield(&discr_byte_offset, byte_size, discr_bit_size, discr_bit_offset); + + auto print_field = [&](clang::FieldDecl *field, uint32_t field_idx) { + clang::QualType field_type = field->getType(); + CompilerType field_clang_type = type_system_clang->GetType(field_type); + const clang::ASTRecordLayout &record_layout = + type_system_clang->getASTContext().getASTRecordLayout(record_decl); + + unsigned int field_bit_size = get_bit_size(field, field_idx); + unsigned int field_bit_offset = record_layout.getFieldOffset(field_idx); + unsigned int field_byte_size = (field_bit_size + 8 - 1) / 8; + DataExtractor field_data_extractor; + lldb::offset_t data_offset; + std::vector buffer; + + if (data.getDataOriginalSource()) { + lldb::addr_t field_addr = data.getDataOriginalSource() + (byte_offset + field_bit_offset / 8); + buffer.resize(field_byte_size); + size_t bytes_read; + Status error; + bytes_read = + process->ReadMemory(field_addr, + &buffer.front(), buffer.size(), error); + ASSERT_USE_FALLBACK_PRINTING(bytes_read == buffer.size() && !error.Fail(), + data, byte_offset + field_bit_offset / 8); + field_data_extractor = DataExtractor(&buffer.front(), buffer.size(), + data.GetByteOrder(), data.GetAddressByteSize()); + data_offset = 0; + } else { + field_data_extractor = data; + data_offset = byte_offset; + } + field_clang_type.DumpTypeValue(s, field_clang_type.GetFormat(), field_data_extractor, data_offset, + field_byte_size, field_bit_size, field_bit_offset, + exe_scope); + return true; + }; + bool is_artificial = !cxx_record_decl->isImplicit(); + if (!is_artificial) { + // We're assuming that the discriminant is an enum, so we're printing it. + s->PutChar('('); + print_field(discr_field.first, discr_field.second); + s->PutChar(' '); + } + + // First checking whether the variant's arguments are a tuple or a record. + bool is_tuple = true; + int cnt_found_children = 0; + for (clang::FieldDecl *field_decl : cxx_record_decl->fields()) { + if (field_decl->getVariantDiscrValue() == discr_value) { + if (!field_decl->getName().empty()) + is_tuple = false; + ++cnt_found_children; + } + } + ASSERT_USE_FALLBACK_PRINTING(cnt_found_children > 0, data, byte_offset); + + // Printing all the fields with the given discriminant (there can be multiple). + if (is_tuple) + s->PutCString(cnt_found_children > 1 ? "(" : ""); + else + s->PutCString("{ "); + uint32_t field_idx = 0; + cnt_found_children = 0; + for (clang::FieldDecl *field_decl : cxx_record_decl->fields()) { + if (field_decl->getVariantDiscrValue() == discr_value) { + if (cnt_found_children++ > 0) + s->PutCString(is_tuple ? ", " : "; "); + if (!field_decl->getName().empty()) { + s->PutCString(field_decl->getName()); + s->PutCString(" = "); + } + print_field(field_decl, field_idx); + } + ++field_idx; + } + if (is_tuple) + s->PutCString(cnt_found_children > 1 ? ")" : ""); + else + s->PutCString(" }"); + if (!is_artificial) + s->PutChar(')'); + return true; +} + +bool DumpTypeRecord(const clang::QualType &qual_type, Stream *s, + const DataExtractor &data, lldb::offset_t byte_offset, + size_t byte_size, ExecutionContextScope *exe_scope, + TypeSystemClang *type_system_clang, + const clang::RecordDecl *record_decl, + const clang::CXXRecordDecl *cxx_record_decl) { + bool is_tuple = true; + for (clang::FieldDecl *field_decl : cxx_record_decl->fields()) + if (!field_decl->getName().empty()) + is_tuple = false; + + s->PutCString(is_tuple ? "(" : "{ "); + unsigned int idx = 0; + for (clang::FieldDecl *field_decl : cxx_record_decl->fields()) { + if (idx > 0) + s->PutCString(is_tuple ? ", " : "; "); + if (!field_decl->getName().empty()) { + s->PutCString(field_decl->getName()); + s->PutCString(" = "); + } + clang::QualType field_type = field_decl->getType(); + CompilerType field_clang_type = type_system_clang->GetType(field_type); + unsigned int field_bit_size; + if (field_decl->isBitField()) { + field_bit_size = field_decl->getBitWidthValue(type_system_clang->getASTContext()); + } + else { + std::optional size = field_clang_type.GetByteSize(exe_scope); + ASSERT_USE_FALLBACK_PRINTING(size && *size < UINT32_MAX, data, byte_offset); + field_bit_size = 8 * (unsigned int) *size; + } + unsigned int field_byte_size = (field_bit_size + 8 - 1) / 8; + const clang::ASTRecordLayout &record_layout = + type_system_clang->getASTContext().getASTRecordLayout(record_decl); + unsigned int field_bit_offset = record_layout.getFieldOffset(idx); + unsigned int field_byte_offset = field_bit_offset / 8; + field_bit_offset %= 8; + field_clang_type.DumpTypeValue(s, field_clang_type.GetFormat(), data, field_byte_offset, + field_byte_size, field_bit_size, field_bit_offset, + exe_scope); + ++idx; + } + s->PutCString(is_tuple ? ")" : " }"); + return true; +} + +bool DumpTypeOcamlArray(const clang::QualType &qual_type, Stream *s, + const DataExtractor &data, lldb::offset_t byte_offset, + size_t byte_size, ExecutionContextScope *exe_scope, + CompilerType array_element_type) { + std::vector buffer; + ExecutionContext exe_ctx; + exe_scope->CalculateExecutionContext(exe_ctx); + Process *process = exe_ctx.GetProcessPtr(); + ASSERT_USE_FALLBACK_PRINTING(process != nullptr, data, byte_offset); + + lldb::addr_t header_addr = data.getDataOriginalSource() - 8; + Status error; + uint64_t header = + process->ReadUnsignedIntegerFromMemory(header_addr, 8, 0, error); + ASSERT_USE_FALLBACK_PRINTING(!error.Fail(), data, byte_offset); + + uint64_t num_elements = header >> 10; + uint64_t tag = header & 0xff; + + // With the float optimization enabled the DWARF isn't always + // accurate, so we need to watch out for Double_array_tag. + if (tag == 254) { + uint64_t value = data.getDataOriginalSource(); + DataExtractor data_extractor((const void*) &value, 8, data.GetByteOrder(), data.GetAddressByteSize()); + return DumpDataExtractor(data_extractor, s, 0, eFormatOCamlValue, 8, 1, + UINT32_MAX, LLDB_INVALID_ADDRESS, 0, 0, + exe_scope); + } + + + buffer.resize(num_elements * 8); + size_t bytes_read; + lldb::addr_t block_addr = data.getDataOriginalSource(); + bytes_read = + process->ReadMemory(block_addr, + &buffer.front(), buffer.size(), error); + ASSERT_USE_FALLBACK_PRINTING(bytes_read == buffer.size() && !error.Fail(), data, byte_offset); + DataExtractor element_data_extractor(&buffer.front(), buffer.size(), + data.GetByteOrder(), data.GetAddressByteSize()); + + s->PutCString("[| "); + uint64_t field; + for (field = 0; field < num_elements; field++) { + array_element_type.DumpTypeValue(s, eFormatDefault, + element_data_extractor, field * 8, 8, 64, 0, exe_scope); + if (field < num_elements - 1) s->PutCString("; "); + } + s->PutCString(" |]"); + return true; +} + +bool DumpTypeLValueReference(const clang::QualType &qual_type, Stream *s, + const DataExtractor &data, lldb::offset_t byte_offset, + size_t byte_size, ExecutionContextScope *exe_scope, + TypeSystemClang *type_system_clang) { + lldb::offset_t byte_offset_copy = byte_offset; + uint64_t value = data.GetU64(&byte_offset_copy); + ASSERT_USE_FALLBACK_PRINTING(exe_scope != nullptr, data, byte_offset); + ExecutionContext exe_ctx; + exe_scope->CalculateExecutionContext(exe_ctx); + Process *process = exe_ctx.GetProcessPtr(); + ASSERT_USE_FALLBACK_PRINTING(process != nullptr, data, byte_offset); + clang::QualType underlying_type_qual = qual_type.getTypePtr()->getPointeeType(); + CompilerType underlying_type_compiler = type_system_clang->GetType(underlying_type_qual); + + clang::QualType record_qual = underlying_type_qual; + while (record_qual.getTypePtr()->getTypeClass() == clang::Type::Typedef) + record_qual = + llvm::cast(record_qual) + ->getDecl() + ->getUnderlyingType(); + if (record_qual.getTypePtr()->isArrayType()) { + DataExtractor data2(data); + data2.setDataOriginalSource(value); + underlying_type_compiler.DumpTypeValue(s, eFormatDefault, data2, + 0, 8, 64, 0, exe_scope); + return true; + } + ASSERT_USE_FALLBACK_PRINTING(record_qual.getTypePtr()->getTypeClass() == clang::Type::Record, + data, byte_offset); + const clang::RecordType *record_type = + llvm::cast(record_qual.getTypePtr()); + ASSERT_USE_FALLBACK_PRINTING(record_type != nullptr, data, byte_offset); + const clang::RecordDecl *record_decl = record_type->getDecl(); + ASSERT_USE_FALLBACK_PRINTING(record_decl != nullptr, data, byte_offset); + const clang::CXXRecordDecl *cxx_record_decl = + llvm::dyn_cast(record_decl); + ASSERT_USE_FALLBACK_PRINTING(cxx_record_decl != nullptr, data, byte_offset); + value += cxx_record_decl->getOffsetRecordFromPointer(); + + std::optional size = underlying_type_compiler.GetByteSize(exe_scope); + ASSERT_USE_FALLBACK_PRINTING(size.has_value(), data, byte_offset); + + std::vector buffer; + buffer.resize(*size); + size_t bytes_read; + Status error; + bytes_read = + process->ReadMemory(value, + &buffer.front(), buffer.size(), error); + ASSERT_USE_FALLBACK_PRINTING(bytes_read == buffer.size() && !error.Fail(), + data, byte_offset); + + DataExtractor under_pointer(&buffer.front(), *size, + process->GetByteOrder(), 8); + under_pointer.setDataOriginalSource(value); + underlying_type_compiler.DumpTypeValue(s, underlying_type_compiler.GetFormat(), + under_pointer, 0, *size, *size * 8, 0, exe_scope); + return true; +} + bool TypeSystemClang::DumpTypeValue( lldb::opaque_compiler_type_t type, Stream *s, lldb::Format format, const lldb_private::DataExtractor &data, lldb::offset_t byte_offset, @@ -9067,7 +9381,10 @@ bool TypeSystemClang::DumpTypeValue( ExecutionContextScope *exe_scope) { if (!type) return false; - if (IsAggregateType(type)) { + CompilerType array_element_type; + bool is_ocaml_array = isLanguageOCaml() + && IsArrayType(type, &array_element_type, nullptr, nullptr); + if (IsAggregateType(type) && !is_ocaml_array) { return false; } else { clang::QualType qual_type(GetQualType(type)); @@ -9078,6 +9395,11 @@ bool TypeSystemClang::DumpTypeValue( 0, 0, exe_scope); } + if (is_ocaml_array) { + return DumpTypeOcamlArray(qual_type, s, data, byte_offset, byte_size, + exe_scope, array_element_type); + } + const clang::Type::TypeClass type_class = qual_type->getTypeClass(); if (type_class == clang::Type::Elaborated) { @@ -9112,6 +9434,37 @@ bool TypeSystemClang::DumpTypeValue( exe_scope); } break; + case clang::Type::Record: { + ASSERT_USE_FALLBACK_PRINTING(GetCompleteType(type) == true, data, byte_offset) + const clang::RecordType *record_type = + llvm::cast(qual_type.getTypePtr()); + ASSERT_USE_FALLBACK_PRINTING(record_type != nullptr, data, byte_offset); + const clang::RecordDecl *record_decl = record_type->getDecl(); + ASSERT_USE_FALLBACK_PRINTING(record_decl != nullptr, data, byte_offset); + const clang::CXXRecordDecl *cxx_record_decl = + llvm::dyn_cast(record_decl); + ASSERT_USE_FALLBACK_PRINTING(cxx_record_decl != nullptr, data, byte_offset); + + ExecutionContext exe_ctx; + exe_scope->CalculateExecutionContext(exe_ctx); + Process *process = exe_ctx.GetProcessPtr(); + ASSERT_USE_FALLBACK_PRINTING(process != nullptr, data, byte_offset); + + if (cxx_record_decl->isVariant()) { + return DumpTypeVariant(qual_type, s, data, byte_offset, byte_size, exe_scope, + this, record_decl, cxx_record_decl, process); + } + else { + return DumpTypeRecord(qual_type, s, data, byte_offset, byte_size, exe_scope, + this, record_decl, cxx_record_decl); + } + } break; + + case clang::Type::LValueReference: { + return DumpTypeLValueReference(qual_type, s, data, byte_offset, byte_size, + exe_scope, this); + } break; + 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. diff --git a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h index f94a055cb9ada..58e8a2ed6639b 100644 --- a/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h +++ b/lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.h @@ -123,7 +123,8 @@ class TypeSystemClang : public TypeSystem { /// certain characteristics of the ASTContext and its types /// (e.g., whether certain primitive types exist or what their /// signedness is). - explicit TypeSystemClang(llvm::StringRef name, llvm::Triple triple); + explicit TypeSystemClang(llvm::StringRef name, llvm::Triple triple, + lldb::LanguageType language = lldb::eLanguageTypeUnknown); /// Constructs a TypeSystemClang that uses an existing ASTContext internally. /// Useful when having an existing ASTContext created by Clang. @@ -131,7 +132,8 @@ class TypeSystemClang : public TypeSystem { /// \param name The name for the TypeSystemClang (for logging purposes) /// \param existing_ctxt An existing ASTContext. explicit TypeSystemClang(llvm::StringRef name, - clang::ASTContext &existing_ctxt); + clang::ASTContext &existing_ctxt, + lldb::LanguageType language = lldb::eLanguageTypeUnknown); ~TypeSystemClang() override; @@ -158,6 +160,11 @@ class TypeSystemClang : public TypeSystem { /// purpose it serves in LLDB. Used for example in logs. llvm::StringRef getDisplayName() const { return m_display_name; } + // Returns the language for which the type system is currently used. + lldb::LanguageType getLanguage() const { return m_language; } + + bool isLanguageOCaml() const { return m_language == lldb::eLanguageTypeOCaml; } + /// Returns the clang::ASTContext instance managed by this TypeSystemClang. clang::ASTContext &getASTContext(); @@ -855,7 +862,9 @@ class TypeSystemClang : public TypeSystem { llvm::StringRef name, const CompilerType &field_type, lldb::AccessType access, - uint32_t bitfield_bit_size); + uint32_t bitfield_bit_size, + uint64_t variant_discr_value = UINT64_MAX, + bool is_artificial = false); static void BuildIndirectFields(const CompilerType &type); @@ -1109,6 +1118,9 @@ class TypeSystemClang : public TypeSystem { /// Useful for logging and debugging. std::string m_display_name; + /// The language type that this type system was created for. + lldb::LanguageType m_language = lldb::eLanguageTypeUnknown; + typedef llvm::DenseMap DeclMetadataMap; /// Maps Decls to their associated ClangASTMetadata. DeclMetadataMap m_decl_metadata; diff --git a/llvm/include/llvm/ADT/APFloat.h b/llvm/include/llvm/ADT/APFloat.h index c0e2d13c29392..c681e9a10ea74 100644 --- a/llvm/include/llvm/ADT/APFloat.h +++ b/llvm/include/llvm/ADT/APFloat.h @@ -1259,6 +1259,27 @@ class APFloat : public APFloatBase { toString(Str, FormatPrecision, FormatMaxPadding, TruncateZero)); } + void toPossiblyShortString(SmallVectorImpl &Str, + unsigned FormatMaxPadding = 3, + bool TruncateZero = true) { + + unsigned precisions[3] = { 5, 12, 15 }; + for (unsigned i = 0; i < 3; ++i) { + toString(Str, precisions[i], FormatMaxPadding, TruncateZero); + StringRef sr = StringRef(Str.data(), Str.size()); + APFloat maybe_self = APFloat(getSemantics(), sr); + // we have found an identical float + if (maybe_self.bitwiseIsEqual(*this)) { + return; + } else { + Str.clear (); + } + } + + // we default back to full precision + toString(Str, 0, FormatMaxPadding, TruncateZero); + } + void print(raw_ostream &) const; void dump() const; diff --git a/llvm/include/llvm/BinaryFormat/Dwarf.def b/llvm/include/llvm/BinaryFormat/Dwarf.def index 1409568b8664f..73fc473532a1a 100644 --- a/llvm/include/llvm/BinaryFormat/Dwarf.def +++ b/llvm/include/llvm/BinaryFormat/Dwarf.def @@ -577,6 +577,9 @@ HANDLE_DW_AT(0x3a00, PGI_lbase, 0, PGI) HANDLE_DW_AT(0x3a01, PGI_soffset, 0, PGI) HANDLE_DW_AT(0x3a02, PGI_lstride, 0, PGI) +// Ocaml specific. +HANDLE_DW_AT(0x3106, offset_record_from_pointer, 4, DWARF) + // Borland extensions. HANDLE_DW_AT(0x3b11, BORLAND_property_read, 0, BORLAND) HANDLE_DW_AT(0x3b12, BORLAND_property_write, 0, BORLAND)