Index: lit/SymbolFile/PDB/Inputs/SimpleTypesTest.cpp =================================================================== --- /dev/null +++ lit/SymbolFile/PDB/Inputs/SimpleTypesTest.cpp @@ -0,0 +1,40 @@ +// typedef +typedef unsigned long ULongArrayTypedef[10]; +ULongArrayTypedef ULongArrayVar; + +typedef long double*& RefTypedef; +long double* LongDoublePtrVar = 0; +RefTypedef RefVar = LongDoublePtrVar; + +typedef long long (*FuncPtrTypedef)(int&, unsigned char**, short[], const double, volatile bool); +FuncPtrTypedef FuncVar; + +typedef char (*VarArgsFuncTypedef)(void*, long, unsigned short, unsigned int, ...); +VarArgsFuncTypedef VarArgsFuncVar; + +typedef float (*VarArgsFuncTypedefA)(...); +VarArgsFuncTypedefA VarArgsFuncVarA; + +// unscoped enum +enum Enum { RED, GREEN, BLUE }; +Enum EnumVar; + +enum EnumConst { LOW, NORMAL = 10, HIGH }; +EnumConst EnumConstVar; + +enum EnumEmpty {}; +EnumEmpty EnumEmptyVar; + +enum EnumUChar : unsigned char { ON, OFF, AUTO }; +EnumUChar EnumCharVar; + +// scoped enum +enum class EnumClass { YES, NO, DEFAULT }; +EnumClass EnumClassVar; + +enum struct EnumStruct { red, blue, black }; +EnumStruct EnumStructVar; + +int main() { + return 0; +} Index: lit/SymbolFile/PDB/enums-layout.test =================================================================== --- /dev/null +++ lit/SymbolFile/PDB/enums-layout.test @@ -0,0 +1,45 @@ +REQUIRES: windows +RUN: clang-cl -m32 /Z7 /c /GS- %S/Inputs/SimpleTypesTest.cpp /o %T/SimpleTypesTest.cpp.enums.obj +RUN: link %T/SimpleTypesTest.cpp.enums.obj /DEBUG /nodefaultlib /ENTRY:main /OUT:%T/SimpleTypesTest.cpp.enums.exe +RUN: lldb-test symbols %T/SimpleTypesTest.cpp.enums.exe | FileCheck %s + +; FIXME: PDB does not have information about scoped enumeration (Enum class) so the +; compiler type used is the same as the one for unscoped enumeration. + +CHECK: Module [[CU:.*]] +CHECK-DAG: {{^[0-9A-F]+}}: SymbolVendor ([[CU]]) +CHECK: Type{{.*}} , name = "Enum", size = 4, compiler_type = {{.*}} enum Enum { +CHECK-NEXT: RED, +CHECK-NEXT: GREEN, +CHECK-NEXT: BLUE +CHECK-NEXT:} + +CHECK: Type{{.*}} , name = "EnumConst", size = 4, compiler_type = {{.*}} enum EnumConst { +CHECK-NEXT: LOW, +CHECK-NEXT: NORMAL, +CHECK-NEXT: HIGH +CHECK-NEXT:} + +CHECK: Type{{.*}} , name = "EnumEmpty", size = 4, compiler_type = {{.*}} enum EnumEmpty { +CHECK-NEXT:} + +CHECK: Type{{.*}} , name = "EnumUChar", size = 1, compiler_type = {{.*}} enum EnumUChar { +CHECK-NEXT: ON, +CHECK-NEXT: OFF, +CHECK-NEXT: AUTO +CHECK-NEXT:} + +; Note that `enum EnumClass` is tested instead of `enum class EnumClass` +CHECK: Type{{.*}} , name = "EnumClass", size = 4, compiler_type = {{.*}} enum EnumClass { +CHECK-NEXT: YES, +CHECK-NEXT: NO, +CHECK-NEXT: DEFAULT +CHECK-NEXT:} + +CHECK: Type{{.*}} , name = "EnumStruct", size = 4, compiler_type = {{.*}} enum EnumStruct { +CHECK-NEXT: red, +CHECK-NEXT: blue, +CHECK-NEXT: black +CHECK-NEXT:} + +CHECK-DAG: {{^[0-9A-F]+}}: CompileUnit{{[{]0x[0-9a-f]+[}]}}, language = "c++", file = '{{.*}}\SimpleTypesTest.cpp' Index: lit/SymbolFile/PDB/typedefs.test =================================================================== --- /dev/null +++ lit/SymbolFile/PDB/typedefs.test @@ -0,0 +1,55 @@ +REQUIRES: windows +RUN: clang-cl -m32 /Z7 /c /GS- %S/Inputs/SimpleTypesTest.cpp /o %T/SimpleTypesTest.cpp.typedefs.obj +RUN: link %T/SimpleTypesTest.cpp.typedefs.obj /DEBUG /nodefaultlib /ENTRY:main /OUT:%T/SimpleTypesTest.cpp.typedefs.exe +RUN: lldb-test symbols %T/SimpleTypesTest.cpp.typedefs.exe | FileCheck %s + +; Generate 32-bit target + +; FIXME: PDB does not have line information for typedef statements so source +; and line information for them is not tested. + +; Note, types `long double` and `double` have same bit size in MSVC and there +; is no information in the PDB to distinguish them. So the compiler type for +; both of them is the same. + +CHECK: Module [[MOD:.*]] +CHECK: {{^[0-9A-F]+}}: SymbolVendor ([[MOD]]) +CHECK-DAG: Type{{.*}} , name = "unsigned long", size = 4, compiler_type = {{.*}} unsigned long +CHECK-DAG: Type{{.*}} , size = 40, compiler_type = {{.*}} unsigned long [10] +CHECK-DAG: Type{{.*}} , name = "ULongArrayTypedef", compiler_type = {{.*}} typedef ULongArrayTypedef + +; Note: compiler_type of `long double` is represented by the one for `double` +CHECK-DAG: Type{{.*}} , name = "double", size = 8, compiler_type = {{.*}} double +CHECK-DAG: Type{{.*}} , size = 4, compiler_type = {{.*}} double * +CHECK-DAG: Type{{.*}} , size = 4, compiler_type = {{.*}} double *& +CHECK-DAG: Type{{.*}} , name = "RefTypedef", compiler_type = {{.*}} typedef RefTypedef + +CHECK-DAG: Type{{.*}} , name = "int", size = 4, compiler_type = {{.*}} int +CHECK-DAG: Type{{.*}} , size = 4, compiler_type = {{.*}} int & +CHECK-DAG: Type{{.*}} , name = "unsigned char", size = 1, compiler_type = {{.*}} unsigned char +CHECK-DAG: Type{{.*}} , size = 4, compiler_type = {{.*}} unsigned char * +CHECK-DAG: Type{{.*}} , size = 4, compiler_type = {{.*}} unsigned char ** +CHECK-DAG: Type{{.*}} , name = "short", size = 2, compiler_type = {{.*}} short +CHECK-DAG: Type{{.*}} , size = 4, compiler_type = {{.*}} short * +CHECK-DAG: Type{{.*}} , name = "const double", size = 8, compiler_type = {{.*}} const double +CHECK-DAG: Type{{.*}} , name = "volatile bool", size = 1, compiler_type = {{.*}} volatile _Bool +CHECK-DAG: Type{{.*}} , name = "long long", size = 8, compiler_type = {{.*}} long long +CHECK-DAG: Type{{.*}} , compiler_type = {{.*}} long long (int &, unsigned char **, short *, const double, volatile _Bool) +CHECK-DAG: Type{{.*}} , name = "FuncPtrTypedef", compiler_type = {{.*}} typedef FuncPtrTypedef + +CHECK-DAG: Type{{.*}} , name = "void", compiler_type = {{.*}} void +CHECK-DAG: Type{{.*}} , size = 4, compiler_type = {{.*}} void * +CHECK-DAG: Type{{.*}} , name = "long", size = 4, compiler_type = {{.*}} long +CHECK-DAG: Type{{.*}} , name = "unsigned short", size = 2, compiler_type = {{.*}} unsigned short +CHECK-DAG: Type{{.*}} , name = "unsigned int", size = 4, compiler_type = {{.*}} unsigned int +CHECK-DAG: Type{{.*}} , name = "signed char", size = 1, compiler_type = {{.*}} signed char +CHECK-DAG: Type{{.*}} , compiler_type = {{.*}} signed char (void *, long, unsigned short, unsigned int, ...) +CHECK-DAG: Type{{.*}} , size = 4, compiler_type = {{.*}} signed char (*)(void *, long, unsigned short, unsigned int, ...) +CHECK-DAG: Type{{.*}} , name = "VarArgsFuncTypedef", compiler_type = {{.*}} typedef VarArgsFuncTypedef + +CHECK-DAG: Type{{.*}} , name = "float", size = 4, compiler_type = {{.*}} float +CHECK-DAG: Type{{.*}} , compiler_type = {{.*}} float (...) +CHECK-DAG: Type{{.*}} , size = 4, compiler_type = {{.*}} float (*)(...) +CHECK-DAG: Type{{.*}} , name = "VarArgsFuncTypedefA", compiler_type = {{.*}} typedef VarArgsFuncTypedefA + +CHECK-DAG: {{^[0-9A-F]+}}: CompileUnit{{[{]0x[0-9a-f]+[}]}}, language = "c++", file = '{{.*}}\SimpleTypesTest.cpp' Index: source/Plugins/SymbolFile/PDB/PDBASTParser.cpp =================================================================== --- source/Plugins/SymbolFile/PDB/PDBASTParser.cpp +++ source/Plugins/SymbolFile/PDB/PDBASTParser.cpp @@ -26,12 +26,12 @@ #include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h" +#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h" #include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h" using namespace lldb; using namespace lldb_private; -using namespace llvm; using namespace llvm::pdb; namespace { @@ -46,7 +46,7 @@ case PDB_UdtType::Interface: return clang::TTK_Interface; } - return clang::TTK_Class; + return -1; } lldb::Encoding TranslateBuiltinEncoding(PDB_BuiltinType type) { @@ -66,6 +66,106 @@ return lldb::eEncodingInvalid; } } + +lldb::Encoding TranslateEnumEncoding(PDB_VariantType type) { + switch (type) { + case PDB_VariantType::Int8: + case PDB_VariantType::Int16: + case PDB_VariantType::Int32: + case PDB_VariantType::Int64: + return lldb::eEncodingSint; + + case PDB_VariantType::UInt8: + case PDB_VariantType::UInt16: + case PDB_VariantType::UInt32: + case PDB_VariantType::UInt64: + return lldb::eEncodingUint; + + default: + break; + } + + return lldb::eEncodingSint; +} + +CompilerType GetBuiltinTypeForPDBEncodingAndBitSize( + ClangASTContext *clang_ast, const PDBSymbolTypeBuiltin *pdb_type, + Encoding encoding, uint32_t width) { + if (!pdb_type) + return CompilerType(); + if (!clang_ast) + return CompilerType(); + auto *ast = clang_ast->getASTContext(); + if (!ast) + return CompilerType(); + + switch (pdb_type->getBuiltinType()) { + default: break; + case PDB_BuiltinType::None: + return CompilerType(); + case PDB_BuiltinType::Void: + // FIXME: where is non-zero size of `void` from? + if (width == 0) + return clang_ast->GetBasicType(eBasicTypeVoid); + case PDB_BuiltinType::Bool: + return clang_ast->GetBasicType(eBasicTypeBool); + case PDB_BuiltinType::Long: + if (width == ast->getTypeSize(ast->LongTy)) + return CompilerType(ast, ast->LongTy); + if (width == ast->getTypeSize(ast->LongLongTy)) + return CompilerType(ast, ast->LongLongTy); + break; + case PDB_BuiltinType::ULong: + if (width == ast->getTypeSize(ast->UnsignedLongTy)) + return CompilerType(ast, ast->UnsignedLongTy); + if (width == ast->getTypeSize(ast->UnsignedLongLongTy)) + return CompilerType(ast, ast->UnsignedLongLongTy); + break; + case PDB_BuiltinType::WCharT: + if (width == ast->getTypeSize(ast->WCharTy)) + return CompilerType(ast, ast->WCharTy); + break; + case PDB_BuiltinType::Float: + // Note: types `long double` and `double` have same bit size in MSVC and there + // is no information in the PDB to distinguish them. So when falling back + // to default search, the compiler type of `long double` will be represented by + // the one generated for `double`. + break; + } + // If there is no match on PDB_BuiltinType, fall back to default search + // by encoding and width only + return clang_ast->GetBuiltinTypeForEncodingAndBitSize(encoding, width); +} + +ConstString GetPDBBuiltinTypeName(const PDBSymbolTypeBuiltin *pdb_type, + CompilerType &compiler_type) { + if (!pdb_type) + return compiler_type.GetTypeName(); + + PDB_BuiltinType kind = pdb_type->getBuiltinType(); + switch (kind) { + default: break; + case PDB_BuiltinType::Currency: + return ConstString("CURRENCY"); + case PDB_BuiltinType::Date: + return ConstString("DATE"); + case PDB_BuiltinType::Variant: + return ConstString("VARIANT"); + case PDB_BuiltinType::Complex: + return ConstString("complex"); + case PDB_BuiltinType::Bitfield: + return ConstString("bitfield"); + case PDB_BuiltinType::BSTR: + return ConstString("BSTR"); + case PDB_BuiltinType::HResult: + return ConstString("HRESULT"); + case PDB_BuiltinType::BCD: + return ConstString("HRESULT"); + case PDB_BuiltinType::None: + return ConstString("..."); + } + return compiler_type.GetTypeName(); +} } PDBASTParser::PDBASTParser(lldb_private::ClangASTContext &ast) : m_ast(ast) {} @@ -85,12 +185,15 @@ if (auto udt = llvm::dyn_cast(&type)) { AccessType access = lldb::eAccessPublic; PDB_UdtType udt_kind = udt->getUdtKind(); + auto tag_type_kind = TranslateUdtKind(udt_kind); + if (tag_type_kind == -1) + return nullptr; if (udt_kind == PDB_UdtType::Class) access = lldb::eAccessPrivate; CompilerType clang_type = m_ast.CreateRecordType( - tu_decl_ctx, access, udt->getName().c_str(), TranslateUdtKind(udt_kind), + tu_decl_ctx, access, udt->getName().c_str(), tag_type_kind, lldb::eLanguageTypeC_plus_plus, nullptr); m_ast.SetHasExternalStorage(clang_type.GetOpaqueQualType(), true); @@ -101,21 +204,41 @@ LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, clang_type, lldb_private::Type::eResolveStateForward); } else if (auto enum_type = llvm::dyn_cast(&type)) { - std::string name = enum_type->getName(); + auto underlying_type_up = enum_type->getUnderlyingType(); + if (!underlying_type_up) + return nullptr; lldb::Encoding encoding = - TranslateBuiltinEncoding(enum_type->getBuiltinType()); + TranslateBuiltinEncoding(underlying_type_up->getBuiltinType()); + // FIXME: Type of underlying builtin is always `Int`. We correct it with + // the very first enumerator's encoding if any. + auto first_child = enum_type->findOneChild(); + if (first_child) { + encoding = TranslateEnumEncoding(first_child->getValue().Type); + } + std::string name = enum_type->getName(); uint64_t bytes = enum_type->getLength(); - CompilerType builtin_type = - m_ast.GetBuiltinTypeForEncodingAndBitSize(encoding, bytes * 8); + CompilerType builtin_type; + if (bytes > 0) + builtin_type = GetBuiltinTypeForPDBEncodingAndBitSize( + &m_ast, underlying_type_up.get(), encoding, bytes * 8); + else + builtin_type = m_ast.GetBasicType(eBasicTypeInt); + // FIXME: PDB does not have information about scoped enumeration (Enum Class). + // Set it false for now. + bool isScoped = false; CompilerType ast_enum = m_ast.CreateEnumerationType( - name.c_str(), tu_decl_ctx, decl, builtin_type, false); + name.c_str(), tu_decl_ctx, decl, builtin_type, isScoped); auto enum_values = enum_type->findAllChildren(); - while (auto enum_value = enum_values->getNext()) { - if (enum_value->getDataKind() != PDB_DataKind::Constant) - continue; - AddEnumValue(ast_enum, *enum_value); + if (enum_values) { + while (auto enum_value = enum_values->getNext()) { + if (enum_value->getDataKind() != PDB_DataKind::Constant) + continue; + AddEnumValue(ast_enum, *enum_value); + } } + if (ClangASTContext::StartTagDeclarationDefinition(ast_enum)) + ClangASTContext::CompleteTagDeclarationDefinition(ast_enum); return std::make_shared( type.getSymIndexId(), m_ast.GetSymbolFile(), ConstString(name), bytes, @@ -141,8 +264,16 @@ } else if (auto func_sig = llvm::dyn_cast(&type)) { auto arg_enum = func_sig->getArguments(); uint32_t num_args = arg_enum->getChildCount(); - std::vector arg_list(num_args); - while (auto arg = arg_enum->getNext()) { + std::vector arg_list; + + bool is_variadic = func_sig->isCVarArgs(); + // Drop last variadic argument. + if (is_variadic) + --num_args; + for (int arg_idx = 0; arg_idx < num_args; arg_idx++) { + auto arg = arg_enum->getChildAtIndex(arg_idx); + if (!arg) + break; lldb_private::Type *arg_type = m_ast.GetSymbolFile()->ResolveTypeUID(arg->getSymIndexId()); // If there's some error looking up one of the dependent types of this @@ -152,6 +283,8 @@ CompilerType arg_ast_type = arg_type->GetFullCompilerType(); arg_list.push_back(arg_ast_type); } + lldbassert(arg_list.size() <= num_args); + auto pdb_return_type = func_sig->getReturnType(); lldb_private::Type *return_type = m_ast.GetSymbolFile()->ResolveTypeUID(pdb_return_type->getSymIndexId()); @@ -166,7 +299,8 @@ if (func_sig->isVolatileType()) type_quals |= clang::Qualifiers::Volatile; CompilerType func_sig_ast_type = m_ast.CreateFunctionType( - return_ast_type, &arg_list[0], num_args, false, type_quals); + return_ast_type, arg_list.data(), arg_list.size(), is_variadic, + type_quals); return std::make_shared( func_sig->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(), 0, @@ -188,6 +322,51 @@ array_type->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(), bytes, nullptr, LLDB_INVALID_UID, lldb_private::Type::eEncodingIsUID, decl, array_ast_type, lldb_private::Type::eResolveStateFull); + } else if (auto *builtin_type = llvm::dyn_cast(&type)) { + PDB_BuiltinType builtin_kind = builtin_type->getBuiltinType(); + if (builtin_kind == PDB_BuiltinType::None) + return nullptr; + + uint64_t bytes = builtin_type->getLength(); + Encoding encoding = TranslateBuiltinEncoding(builtin_kind); + CompilerType builtin_ast_type = GetBuiltinTypeForPDBEncodingAndBitSize( + &m_ast, builtin_type, encoding, bytes * 8); + + Type::EncodingDataType encoding_data_type = Type::eEncodingIsUID; + if (builtin_type->isConstType()) { + encoding_data_type = Type::eEncodingIsConstUID; + builtin_ast_type = builtin_ast_type.AddConstModifier(); + } + if (builtin_type->isVolatileType()) { + encoding_data_type = Type::eEncodingIsVolatileUID; + builtin_ast_type = builtin_ast_type.AddVolatileModifier(); + } + auto type_name = GetPDBBuiltinTypeName(builtin_type, builtin_ast_type); + + return std::make_shared( + builtin_type->getSymIndexId(), m_ast.GetSymbolFile(), type_name, + bytes, nullptr, LLDB_INVALID_UID, encoding_data_type, + decl, builtin_ast_type, lldb_private::Type::eResolveStateFull); + } else if (auto *pointer_type = llvm::dyn_cast(&type)) { + Type *pointee_type = m_ast.GetSymbolFile()->ResolveTypeUID( + pointer_type->getPointeeType()->getSymIndexId()); + if (!pointee_type) + return nullptr; + + CompilerType pointer_ast_type; + Type::EncodingDataType encoding_data_type = Type::eEncodingIsPointerUID; + if (pointer_type->isReference()) { + encoding_data_type = Type::eEncodingIsLValueReferenceUID; + pointer_ast_type = + pointee_type->GetFullCompilerType().GetLValueReferenceType(); + } else + pointer_ast_type = pointee_type->GetFullCompilerType().GetPointerType(); + + return std::make_shared( + pointer_type->getSymIndexId(), m_ast.GetSymbolFile(), ConstString(), + pointer_type->getLength(), nullptr, LLDB_INVALID_UID, + encoding_data_type, decl, pointer_ast_type, + lldb_private::Type::eResolveStateFull); } return nullptr; } Index: source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp =================================================================== --- source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp +++ source/Plugins/SymbolFile/PDB/SymbolFilePDB.cpp @@ -20,6 +20,7 @@ #include "lldb/Symbol/SymbolContext.h" #include "lldb/Symbol/SymbolVendor.h" #include "lldb/Symbol/TypeMap.h" +#include "lldb/Symbol/TypeList.h" #include "lldb/Utility/RegularExpression.h" #include "llvm/DebugInfo/PDB/GenericError.h" @@ -318,8 +319,33 @@ } size_t SymbolFilePDB::ParseTypes(const lldb_private::SymbolContext &sc) { - // TODO: Implement this - return size_t(); + lldbassert(sc.module_sp.get()); + size_t num_added = 0; + auto results_up = m_session_up->getGlobalScope()->findAllChildren(); + if (!results_up) + return 0; + while (auto symbol_up = results_up->getNext()) { + switch (symbol_up->getSymTag()) { + case PDB_SymType::Enum: + case PDB_SymType::UDT: + case PDB_SymType::Typedef: + break; + default: + continue; + } + + auto type_uid = symbol_up->getSymIndexId(); + if (m_types.find(type_uid) != m_types.end()) + continue; + + // This should cause the type to get cached and stored in the `m_types` + // lookup. + if (!ResolveTypeUID(symbol_up->getSymIndexId())) + continue; + + ++num_added; + } + return num_added; } size_t @@ -349,8 +375,11 @@ return nullptr; lldb::TypeSP result = pdb->CreateLLDBTypeFromPDBType(*pdb_type); - if (result.get()) + if (result.get()) { m_types.insert(std::make_pair(type_uid, result)); + auto type_list = GetTypeList(); + type_list->Insert(result); + } return result.get(); } @@ -649,7 +678,9 @@ return 0; } -lldb_private::TypeList *SymbolFilePDB::GetTypeList() { return nullptr; } +lldb_private::TypeList *SymbolFilePDB::GetTypeList() { + return m_obj_file->GetModule()->GetTypeList(); +} size_t SymbolFilePDB::GetTypes(lldb_private::SymbolContextScope *sc_scope, uint32_t type_mask,