diff --git a/lldb/include/lldb/Core/ClangForward.h b/lldb/include/lldb/Core/ClangForward.h index d4b854925c84..a099cd21a883 100644 --- a/lldb/include/lldb/Core/ClangForward.h +++ b/lldb/include/lldb/Core/ClangForward.h @@ -31,6 +31,8 @@ namespace clang class AddrLabelExpr; class AnalyzerOptions; class BinaryOperator; + class ClassTemplateDecl; + class ClassTemplateSpecializationDecl; class CodeGenOptions; class CodeGenerator; class CompilerInstance; diff --git a/lldb/include/lldb/Symbol/ClangASTContext.h b/lldb/include/lldb/Symbol/ClangASTContext.h index c18cb4e9aec6..5a2bd2169b6c 100644 --- a/lldb/include/lldb/Symbol/ClangASTContext.h +++ b/lldb/include/lldb/Symbol/ClangASTContext.h @@ -19,6 +19,8 @@ // Other libraries and framework includes #include "llvm/ADT/OwningPtr.h" +#include "llvm/ADT/SmallVector.h" +#include "clang/AST/TemplateBase.h" // Project includes #include "lldb/lldb-enumerations.h" @@ -55,7 +57,7 @@ public: typedef void (*CompleteTagDeclCallback)(void *baton, clang::TagDecl *); typedef void (*CompleteObjCInterfaceDeclCallback)(void *baton, clang::ObjCInterfaceDecl *); - + //------------------------------------------------------------------ // Constructors and Destructors //------------------------------------------------------------------ @@ -300,6 +302,44 @@ public: is_explicit); } + class TemplateParameterInfos + { + public: + bool + IsValid() const + { + if (args.empty()) + return false; + return args.size() == names.size(); + } + + size_t + GetSize () const + { + if (IsValid()) + return args.size(); + return 0; + } + + llvm::SmallVector names; + llvm::SmallVector args; + }; + + clang::ClassTemplateDecl * + CreateClassTemplateDecl (clang::DeclContext *decl_ctx, + const char *class_name, + int kind, + const TemplateParameterInfos &infos); + + clang::ClassTemplateSpecializationDecl * + CreateClassTemplateSpecializationDecl (clang::DeclContext *decl_ctx, + clang::ClassTemplateDecl *class_template_decl, + int kind, + const TemplateParameterInfos &infos); + + lldb::clang_type_t + CreateClassTemplateSpecializationType (clang::ClassTemplateSpecializationDecl *class_template_specialization_decl); + static clang::DeclContext * GetAsDeclContext (clang::CXXMethodDecl *cxx_method_decl); diff --git a/lldb/source/Expression/IRForTarget.cpp b/lldb/source/Expression/IRForTarget.cpp index 88cdca01eb80..50cd0cc28969 100644 --- a/lldb/source/Expression/IRForTarget.cpp +++ b/lldb/source/Expression/IRForTarget.cpp @@ -224,16 +224,41 @@ IRForTarget::GetFunctionAddress (llvm::Function *fun, { if (!m_decl_map->GetFunctionInfo (fun_decl, fun_value_ptr, fun_addr)) { - fun_value_ptr = NULL; - - if (!m_decl_map->GetFunctionAddress (name, fun_addr)) + lldb_private::ConstString alternate_mangling_const_str; + bool found_it = m_decl_map->GetFunctionAddress (name, fun_addr); + if (!found_it) { + // Check for an alternate mangling for "std::basic_string" + // that is part of the itanium C++ name mangling scheme + const char *name_cstr = name.GetCString(); + if (strncmp(name_cstr, "_ZNKSbIcE", strlen("_ZNKSbIcE")) == 0) + { + std::string alternate_mangling("_ZNKSs"); + alternate_mangling.append (name_cstr + strlen("_ZNKSbIcE")); + alternate_mangling_const_str.SetCString(alternate_mangling.c_str()); + found_it = m_decl_map->GetFunctionAddress (alternate_mangling_const_str, fun_addr); + } + } + + if (!found_it) + { + fun_value_ptr = NULL; + if (log) - log->Printf("Function \"%s\" had no address", name.GetCString()); + { + if (alternate_mangling_const_str) + log->Printf("Function \"%s\" (alternate name \"%s\") has no address", name.GetCString(), alternate_mangling_const_str.GetCString()); + else + log->Printf("Function \"%s\" had no address", name.GetCString()); + } if (m_error_stream) - m_error_stream->Printf("Error [IRForTarget]: Call to a function '%s' that is not present in the target\n", name.GetCString()); - + { + if (alternate_mangling_const_str) + m_error_stream->Printf("error: call to a function '%s' (alternate name '%s') that is not present in the target\n", name.GetCString(), alternate_mangling_const_str.GetCString()); + else + m_error_stream->Printf("error: call to a function '%s' that is not present in the target\n", name.GetCString()); + } return false; } } diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp index 89af5bcb580a..0c467ea10101 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.cpp @@ -1133,6 +1133,128 @@ SymbolFileDWARF::ParseFunctionBlocks return blocks_added; } +bool +SymbolFileDWARF::ParseTemplateParameterInfos (DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *parent_die, + ClangASTContext::TemplateParameterInfos &template_param_infos) +{ + + if (parent_die == NULL) + return NULL; + + const uint8_t *fixed_form_sizes = DWARFFormValue::GetFixedFormSizesForAddressSize (dwarf_cu->GetAddressByteSize()); + + Args template_parameter_names; + for (const DWARFDebugInfoEntry *die = parent_die->GetFirstChild(); + die != NULL; + die = die->GetSibling()) + { + const dw_tag_t tag = die->Tag(); + + switch (tag) + { + case DW_TAG_template_type_parameter: + case DW_TAG_template_value_parameter: + { + DWARFDebugInfoEntry::Attributes attributes; + const size_t num_attributes = die->GetAttributes (this, + dwarf_cu, + fixed_form_sizes, + attributes); + const char *name = NULL; + Type *lldb_type = NULL; + clang_type_t clang_type = NULL; + uint64_t uval64 = 0; + bool uval64_valid = false; + if (num_attributes > 0) + { + DWARFFormValue form_value; + for (size_t i=0; iGetClangForwardType(); + } + break; + + case DW_AT_const_value: + if (attributes.ExtractFormValueAtIndex(this, i, form_value)) + { + uval64_valid = true; + uval64 = form_value.Unsigned(); + } + break; + default: + break; + } + } + + if (name && lldb_type && clang_type) + { + bool is_signed = false; + template_param_infos.names.push_back(name); + clang::QualType clang_qual_type (clang::QualType::getFromOpaquePtr (clang_type)); + if (tag == DW_TAG_template_value_parameter && ClangASTContext::IsIntegerType (clang_type, is_signed) && uval64_valid) + { + llvm::APInt apint (lldb_type->GetByteSize() * 8, uval64, is_signed); + template_param_infos.args.push_back (clang::TemplateArgument (llvm::APSInt(apint), clang_qual_type)); + } + else + { + template_param_infos.args.push_back (clang::TemplateArgument (clang_qual_type)); + } + } + else + { + return false; + } + + } + } + break; + + default: + break; + } + } + if (template_param_infos.args.empty()) + return false; + return template_param_infos.args.size() == template_param_infos.names.size(); +} + +clang::ClassTemplateDecl * +SymbolFileDWARF::ParseClassTemplateDecl (clang::DeclContext *decl_ctx, + const char *parent_name, + int tag_decl_kind, + const ClangASTContext::TemplateParameterInfos &template_param_infos) +{ + if (template_param_infos.IsValid()) + { + std::string template_basename(parent_name); + template_basename.erase (template_basename.find('<')); + ClangASTContext &ast = GetClangASTContext(); + + return ast.CreateClassTemplateDecl (decl_ctx, + template_basename.c_str(), + tag_decl_kind, + template_param_infos); + } + return NULL; +} + size_t SymbolFileDWARF::ParseChildMembers ( @@ -2342,16 +2464,16 @@ SymbolFileDWARF::FunctionDieMatchesPartialName (const DWARFDebugInfoEntry* die, if (name_type_mask == eFunctionNameTypeMethod || name_type_mask == eFunctionNameTypeBase) { - clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIEOffset(die->GetOffset()); - if (!containing_decl_ctx) - return false; - - bool is_cxx_method = (containing_decl_ctx->getDeclKind() == clang::Decl::CXXRecord); - - if (!is_cxx_method && name_type_mask == eFunctionNameTypeMethod) - return false; - if (is_cxx_method && name_type_mask == eFunctionNameTypeBase) - return false; + clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIEOffset(die->GetOffset()); + if (!containing_decl_ctx) + return false; + + bool is_cxx_method = DeclKindIsCXXClass(containing_decl_ctx->getDeclKind()); + + if (!is_cxx_method && name_type_mask == eFunctionNameTypeMethod) + return false; + if (is_cxx_method && name_type_mask == eFunctionNameTypeBase) + return false; } // Now we need to check whether the name we got back for this type matches the extra specifications @@ -2989,7 +3111,7 @@ SymbolFileDWARF::ParseChildParameters (const SymbolContext& sc, // Ugly, but that if (arg_idx == 0) { - if (containing_decl_ctx->getDeclKind() == clang::Decl::CXXRecord) + if (DeclKindIsCXXClass(containing_decl_ctx->getDeclKind())) { // Often times compilers omit the "this" name for the // specification DIEs, so we can't rely upon the name @@ -3900,11 +4022,34 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, clang_type = m_forward_decl_die_to_clang_type.lookup (die); if (clang_type == NULL) { - clang_type_was_created = true; - clang_type = ast.CreateRecordType (type_name_cstr, - tag_decl_kind, - GetClangDeclContextContainingDIE (dwarf_cu, die, NULL), - class_language); + clang::DeclContext *decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, NULL); + if (type_name_cstr && strchr (type_name_cstr, '<')) + { + ClangASTContext::TemplateParameterInfos template_param_infos; + if (ParseTemplateParameterInfos (dwarf_cu, die, template_param_infos)) + { + clang::ClassTemplateDecl *class_template_decl = ParseClassTemplateDecl (decl_ctx, + type_name_cstr, + tag_decl_kind, + template_param_infos); + + clang::ClassTemplateSpecializationDecl *class_specialization_decl = ast.CreateClassTemplateSpecializationDecl (decl_ctx, + class_template_decl, + tag_decl_kind, + template_param_infos); + clang_type = ast.CreateClassTemplateSpecializationType (class_specialization_decl); + clang_type_was_created = true; + } + } + + if (!clang_type_was_created) + { + clang_type_was_created = true; + clang_type = ast.CreateRecordType (type_name_cstr, + tag_decl_kind, + decl_ctx, + class_language); + } } // Store a forward declaration to this class type in case any @@ -4167,7 +4312,7 @@ SymbolFileDWARF::ParseType (const SymbolContext& sc, DWARFCompileUnit* dwarf_cu, clang::DeclContext *containing_decl_ctx = GetClangDeclContextContainingDIE (dwarf_cu, die, &decl_ctx_die); const clang::Decl::Kind containing_decl_kind = containing_decl_ctx->getDeclKind(); - const bool is_cxx_method = containing_decl_kind == clang::Decl::CXXRecord; + const bool is_cxx_method = DeclKindIsCXXClass (containing_decl_kind); // Start off static. This will be set to false in ParseChildParameters(...) // if we find a "this" paramters as the first parameter if (is_cxx_method) diff --git a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h index c3fb5d1145b3..3367b6100ece 100644 --- a/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h +++ b/lldb/source/Plugins/SymbolFile/DWARF/SymbolFileDWARF.h @@ -28,6 +28,7 @@ #include "lldb/Core/DataExtractor.h" #include "lldb/Core/Flags.h" #include "lldb/Core/UniqueCStringMap.h" +#include "lldb/Symbol/ClangASTContext.h" #include "lldb/Symbol/SymbolFile.h" #include "lldb/Symbol/SymbolContext.h" @@ -58,7 +59,7 @@ class SymbolFileDWARFDebugMap; class SymbolFileDWARF : public lldb_private::SymbolFile, public lldb_private::UserID { public: - friend class SymbolFileDWARFDebugMap; + friend class SymbolFileDWARFDebugMap; //------------------------------------------------------------------ // Static Functions @@ -426,6 +427,32 @@ protected: return GetID() | die_offset; } + static bool + DeclKindIsCXXClass (clang::Decl::Kind decl_kind) + { + switch (decl_kind) + { + case clang::Decl::CXXRecord: + case clang::Decl::ClassTemplateSpecialization: + return true; + default: + break; + } + return false; + } + + bool + ParseTemplateParameterInfos (DWARFCompileUnit* dwarf_cu, + const DWARFDebugInfoEntry *parent_die, + lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos); + + clang::ClassTemplateDecl * + ParseClassTemplateDecl (clang::DeclContext *decl_ctx, + const char *parent_name, + int tag_decl_kind, + const lldb_private::ClangASTContext::TemplateParameterInfos &template_param_infos); + + void ReportError (const char *format, ...) __attribute__ ((format (printf, 2, 3))); void diff --git a/lldb/source/Symbol/ClangASTContext.cpp b/lldb/source/Symbol/ClangASTContext.cpp index c4712cd9ca30..320f1eb4b721 100644 --- a/lldb/source/Symbol/ClangASTContext.cpp +++ b/lldb/source/Symbol/ClangASTContext.cpp @@ -36,6 +36,7 @@ #include "clang/AST/ASTImporter.h" #include "clang/AST/CXXInheritance.h" #include "clang/AST/DeclObjC.h" +#include "clang/AST/DeclTemplate.h" #include "clang/AST/RecordLayout.h" #include "clang/AST/Type.h" #include "clang/Basic/Builtins.h" @@ -58,6 +59,8 @@ #include "lldb/Core/dwarf.h" #include "lldb/Core/Flags.h" #include "lldb/Core/Log.h" +#include "lldb/Core/RegularExpression.h" +#include "lldb/Expression/ASTDumper.h" #include "lldb/Target/ExecutionContext.h" #include "lldb/Target/Process.h" #include "lldb/Target/ObjCLanguageRuntime.h" @@ -1085,16 +1088,138 @@ ClangASTContext::CreateRecordType (const char *name, int kind, DeclContext *decl // the CXXRecordDecl class since we often don't know from debug information // if something is struct or a class, so we default to always use the more // complete definition just in case. - CXXRecordDecl *decl = CXXRecordDecl::Create(*ast, - (TagDecl::TagKind)kind, - decl_ctx, - SourceLocation(), - SourceLocation(), - name && name[0] ? &ast->Idents.get(name) : NULL); + CXXRecordDecl *decl = CXXRecordDecl::Create (*ast, + (TagDecl::TagKind)kind, + decl_ctx, + SourceLocation(), + SourceLocation(), + name && name[0] ? &ast->Idents.get(name) : NULL); return ast->getTagDeclType(decl).getAsOpaquePtr(); } +ClassTemplateDecl * +ClangASTContext::CreateClassTemplateDecl (DeclContext *decl_ctx, + const char *class_name, + int kind, + const TemplateParameterInfos &template_param_infos) +{ + ASTContext *ast = getASTContext(); + + ClassTemplateDecl *class_template_decl = NULL; + if (decl_ctx == NULL) + decl_ctx = ast->getTranslationUnitDecl(); + + IdentifierInfo &identifier_info = ast->Idents.get(class_name); + DeclarationName decl_name (&identifier_info); + + clang::DeclContext::lookup_result result = decl_ctx->lookup(decl_name); + for (clang::DeclContext::lookup_iterator pos = result.first, end = result.second; pos != end; ++pos) + { + class_template_decl = dyn_cast(*pos); + if (class_template_decl) + return class_template_decl; + } + + llvm::SmallVector template_param_decls; + const bool parameter_pack = false; + const bool is_typename = false; + const unsigned depth = 0; + const size_t num_template_params = template_param_infos.GetSize(); + for (size_t i=0; igetTranslationUnitDecl(), // Is this the right decl context?, SourceLocation StartLoc, + SourceLocation(), + SourceLocation(), + depth, + i, + &ast->Idents.get(name), + template_param_infos.args[i].getAsType(), + parameter_pack, + NULL)); + + } + else + { + template_param_decls.push_back (TemplateTypeParmDecl::Create (*ast, + ast->getTranslationUnitDecl(), // Is this the right decl context? + SourceLocation(), + SourceLocation(), + depth, + i, + &ast->Idents.get(name), + is_typename, + parameter_pack)); + } + } + + TemplateParameterList *template_param_list = TemplateParameterList::Create (*ast, + SourceLocation(), + SourceLocation(), + &template_param_decls.front(), + template_param_decls.size(), + SourceLocation()); + + + CXXRecordDecl *template_cxx_decl = CXXRecordDecl::Create (*ast, + (TagDecl::TagKind)kind, + decl_ctx, // What decl context do we use here? TU? The actual decl context? + SourceLocation(), + SourceLocation(), + &identifier_info); + + + class_template_decl = ClassTemplateDecl::Create (*ast, + decl_ctx, // What decl context do we use here? TU? The actual decl context? + SourceLocation(), + decl_name, + template_param_list, + template_cxx_decl, + NULL); + + if (class_template_decl) + decl_ctx->addDecl (class_template_decl); + + return class_template_decl; +} + + +ClassTemplateSpecializationDecl * +ClangASTContext::CreateClassTemplateSpecializationDecl (DeclContext *decl_ctx, + ClassTemplateDecl *class_template_decl, + int kind, + const TemplateParameterInfos &template_param_infos) +{ + ASTContext *ast = getASTContext(); + ClassTemplateSpecializationDecl *class_template_specialization_decl = ClassTemplateSpecializationDecl::Create (*ast, + (TagDecl::TagKind)kind, + decl_ctx, + SourceLocation(), + SourceLocation(), + class_template_decl, + &template_param_infos.args.front(), + template_param_infos.args.size(), + NULL); + + return class_template_specialization_decl; +} + +lldb::clang_type_t +ClangASTContext::CreateClassTemplateSpecializationType (ClassTemplateSpecializationDecl *class_template_specialization_decl) +{ + if (class_template_specialization_decl) + { + ASTContext *ast = getASTContext(); + if (ast) + return ast->getTagDeclType(class_template_specialization_decl).getAsOpaquePtr(); + } + return NULL; +} + bool ClangASTContext::SetHasExternalStorage (clang_type_t clang_type, bool has_extern) { @@ -2842,6 +2967,8 @@ ClangASTContext::GetNumPointeeChildren (clang_type_t clang_type) case clang::BuiltinType::ObjCClass: case clang::BuiltinType::ObjCSel: case clang::BuiltinType::BoundMember: + case clang::BuiltinType::Half: + case clang::BuiltinType::ARCUnbridgedCast: return 1; } break; @@ -4615,6 +4742,8 @@ ClangASTContext::IsPossibleDynamicType (clang::ASTContext *ast, clang_type_t cla case clang::BuiltinType::ObjCClass: case clang::BuiltinType::ObjCSel: case clang::BuiltinType::BoundMember: + case clang::BuiltinType::Half: + case clang::BuiltinType::ARCUnbridgedCast: break; } break; @@ -4748,6 +4877,8 @@ ClangASTContext::IsPossibleCPlusPlusDynamicType (clang::ASTContext *ast, clang_t case clang::BuiltinType::ObjCClass: case clang::BuiltinType::ObjCSel: case clang::BuiltinType::BoundMember: + case clang::BuiltinType::Half: + case clang::BuiltinType::ARCUnbridgedCast: break; } break; diff --git a/lldb/source/Symbol/ClangASTType.cpp b/lldb/source/Symbol/ClangASTType.cpp index 40d049652a67..8867ba65ea90 100644 --- a/lldb/source/Symbol/ClangASTType.cpp +++ b/lldb/source/Symbol/ClangASTType.cpp @@ -569,7 +569,10 @@ ClangASTType::GetFormat (clang_type_t clang_type) case clang::BuiltinType::Dependent: case clang::BuiltinType::ObjCId: case clang::BuiltinType::ObjCClass: - case clang::BuiltinType::ObjCSel: return lldb::eFormatHex; + case clang::BuiltinType::ObjCSel: + case clang::BuiltinType::Half: + case clang::BuiltinType::ARCUnbridgedCast: + return lldb::eFormatHex; } break; case clang::Type::ObjCObjectPointer: return lldb::eFormatHex;