This revision was automatically updated to reflect the committed changes. Closed by commit rL345848: [NativePDB] Get LLDB types from PDB function types. (authored by zturner, committed by ). Herald added a subscriber: llvm-commits.
Changed prior to commit: https://reviews.llvm.org/D53951?vs=172023&id=172151#toc Repository: rL LLVM https://reviews.llvm.org/D53951 Files: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-builtins.lldbinit lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-calling-conv.lldbinit lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit lldb/trunk/lit/SymbolFile/NativePDB/function-types-builtins.cpp lldb/trunk/lit/SymbolFile/NativePDB/function-types-calling-conv.cpp lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h
Index: lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp +++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.cpp @@ -49,6 +49,8 @@ #include "llvm/Support/ErrorOr.h" #include "llvm/Support/MemoryBuffer.h" +#include "Plugins/Language/CPlusPlus/CPlusPlusNameParser.h" + #include "PdbSymUid.h" #include "PdbUtil.h" #include "UdtRecordCompleter.h" @@ -394,6 +396,12 @@ return GetPdbSymType(tpi, LookThroughModifierRecord(cvt)); } +static bool IsCVarArgsFunction(llvm::ArrayRef<TypeIndex> args) { + if (args.empty()) + return false; + return args.back() == TypeIndex::None(); +} + static clang::TagTypeKind TranslateUdtKind(const TagRecord &cr) { switch (cr.Kind) { case TypeRecordKind::Class: @@ -412,6 +420,32 @@ } } +static llvm::Optional<clang::CallingConv> +TranslateCallingConvention(llvm::codeview::CallingConvention conv) { + using CC = llvm::codeview::CallingConvention; + switch (conv) { + + case CC::NearC: + case CC::FarC: + return clang::CallingConv::CC_C; + case CC::NearPascal: + case CC::FarPascal: + return clang::CallingConv::CC_X86Pascal; + case CC::NearFast: + case CC::FarFast: + return clang::CallingConv::CC_X86FastCall; + case CC::NearStdCall: + case CC::FarStdCall: + return clang::CallingConv::CC_X86StdCall; + case CC::ThisCall: + return clang::CallingConv::CC_X86ThisCall; + case CC::NearVector: + return clang::CallingConv::CC_X86VectorCall; + default: + return llvm::None; + } +} + void SymbolFileNativePDB::Initialize() { PluginManager::RegisterPlugin(GetPluginNameStatic(), GetPluginDescriptionStatic(), CreateInstance, @@ -540,7 +574,6 @@ PdbSymUid sig_uid = PdbSymUid::makeTypeSymId(PDB_SymType::FunctionSig, TypeIndex{0}, false); Mangled mangled(getSymbolName(sym_record)); - FunctionSP func_sp = std::make_shared<Function>( sc.comp_unit, func_uid.toOpaqueId(), sig_uid.toOpaqueId(), mangled, func_type, func_range); @@ -598,6 +631,8 @@ lldb::TypeSP SymbolFileNativePDB::CreatePointerType( PdbSymUid type_uid, const llvm::codeview::PointerRecord &pr) { TypeSP pointee = GetOrCreateType(pr.ReferentType); + if (!pointee) + return nullptr; CompilerType pointee_ct = pointee->GetForwardCompilerType(); lldbassert(pointee_ct); Declaration decl; @@ -639,6 +674,17 @@ } lldb::TypeSP SymbolFileNativePDB::CreateSimpleType(TypeIndex ti) { + if (ti == TypeIndex::NullptrT()) { + PdbSymUid uid = + PdbSymUid::makeTypeSymId(PDB_SymType::BuiltinType, ti, false); + CompilerType ct = m_clang->GetBasicType(eBasicTypeNullPtr); + Declaration decl; + return std::make_shared<Type>(uid.toOpaqueId(), this, + ConstString("std::nullptr_t"), 0, nullptr, + LLDB_INVALID_UID, Type::eEncodingIsUID, decl, + ct, Type::eResolveStateFull); + } + if (ti.getSimpleMode() != SimpleTypeMode::Direct) { PdbSymUid uid = PdbSymUid::makeTypeSymId(PDB_SymType::PointerType, ti, false); @@ -670,7 +716,8 @@ return nullptr; lldb::BasicType bt = GetCompilerTypeForSimpleKind(ti.getSimpleKind()); - lldbassert(bt != lldb::eBasicTypeInvalid); + if (bt == lldb::eBasicTypeInvalid) + return nullptr; CompilerType ct = m_clang->GetBasicType(bt); size_t size = GetTypeSizeForSimpleKind(ti.getSimpleKind()); @@ -687,10 +734,6 @@ PdbSymUid type_uid, llvm::StringRef name, size_t size, clang::TagTypeKind ttk, clang::MSInheritanceAttr::Spelling inheritance) { - // Some UDT with trival ctor has zero length. Just ignore. - if (size == 0) - return nullptr; - // Ignore unnamed-tag UDTs. name = DropNameScope(name); if (name.empty()) @@ -792,6 +835,49 @@ return array_sp; } +TypeSP SymbolFileNativePDB::CreateProcedureType(PdbSymUid type_uid, + const ProcedureRecord &pr) { + TpiStream &stream = m_index->tpi(); + CVType args_cvt = stream.getType(pr.ArgumentList); + ArgListRecord args; + llvm::cantFail( + TypeDeserializer::deserializeAs<ArgListRecord>(args_cvt, args)); + + llvm::ArrayRef<TypeIndex> arg_indices = llvm::makeArrayRef(args.ArgIndices); + bool is_variadic = IsCVarArgsFunction(arg_indices); + if (is_variadic) + arg_indices = arg_indices.drop_back(); + + std::vector<CompilerType> arg_list; + arg_list.reserve(arg_list.size()); + + for (TypeIndex arg_index : arg_indices) { + TypeSP arg_sp = GetOrCreateType(arg_index); + if (!arg_sp) + return nullptr; + arg_list.push_back(arg_sp->GetFullCompilerType()); + } + + TypeSP return_type_sp = GetOrCreateType(pr.ReturnType); + if (!return_type_sp) + return nullptr; + + llvm::Optional<clang::CallingConv> cc = + TranslateCallingConvention(pr.CallConv); + if (!cc) + return nullptr; + + CompilerType return_ct = return_type_sp->GetFullCompilerType(); + CompilerType func_sig_ast_type = m_clang->CreateFunctionType( + return_ct, arg_list.data(), arg_list.size(), is_variadic, 0, *cc); + + Declaration decl; + return std::make_shared<lldb_private::Type>( + type_uid.toOpaqueId(), this, ConstString(), 0, nullptr, LLDB_INVALID_UID, + lldb_private::Type::eEncodingIsUID, decl, func_sig_ast_type, + lldb_private::Type::eResolveStateFull); +} + TypeSP SymbolFileNativePDB::CreateType(PdbSymUid type_uid) { const PdbTypeSymId &tsid = type_uid.asTypeSym(); TypeIndex index(tsid.index); @@ -840,6 +926,12 @@ return CreateArrayType(type_uid, ar); } + if (cvt.kind() == LF_PROCEDURE) { + ProcedureRecord pr; + llvm::cantFail(TypeDeserializer::deserializeAs<ProcedureRecord>(cvt, pr)); + return CreateProcedureType(type_uid, pr); + } + return nullptr; } @@ -858,7 +950,7 @@ auto expected_full_ti = m_index->tpi().findFullDeclForForwardRef(ti); if (!expected_full_ti) llvm::consumeError(expected_full_ti.takeError()); - else { + else if (*expected_full_ti != ti) { full_decl_uid = PdbSymUid::makeTypeSymId( type_uid.tag(), *expected_full_ti, type_id.is_ipi); @@ -880,6 +972,8 @@ PdbSymUid best_uid = full_decl_uid ? *full_decl_uid : type_uid; TypeSP result = CreateType(best_uid); + if (!result) + return nullptr; m_types[best_uid.toOpaqueId()] = result; // If we had both a forward decl and a full decl, make both point to the new // type. Index: lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h +++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/SymbolFileNativePDB.h @@ -172,6 +172,8 @@ const llvm::codeview::UnionRecord &ur); lldb::TypeSP CreateArrayType(PdbSymUid type_uid, const llvm::codeview::ArrayRecord &ar); + lldb::TypeSP CreateProcedureType(PdbSymUid type_uid, + const llvm::codeview::ProcedureRecord &pr); lldb::TypeSP CreateClassStructUnion(PdbSymUid type_uid, llvm::StringRef name, size_t size, clang::TagTypeKind ttk, Index: lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp =================================================================== --- lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp +++ lldb/trunk/source/Plugins/SymbolFile/NativePDB/PdbUtil.cpp @@ -92,6 +92,8 @@ return PDB_SymType::PointerType; case LF_ENUM: return PDB_SymType::Enum; + case LF_PROCEDURE: + return PDB_SymType::FunctionSig; default: lldbassert(false && "Invalid type record kind!"); } @@ -361,4 +363,4 @@ assert(offset + 2 <= name.size()); return name.substr(offset + 2); -} \ No newline at end of file +} Index: lldb/trunk/lit/SymbolFile/NativePDB/function-types-builtins.cpp =================================================================== --- lldb/trunk/lit/SymbolFile/NativePDB/function-types-builtins.cpp +++ lldb/trunk/lit/SymbolFile/NativePDB/function-types-builtins.cpp @@ -0,0 +1,215 @@ +// clang-format off +// REQUIRES: lld + +// RUN: clang-cl /Z7 /GS- /GR- /c -Xclang -fkeep-static-consts /Fo%t.obj -- %s +// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \ +// RUN: %p/Inputs/function-types-builtins.lldbinit | FileCheck %s + +// Test that we can display function signatures with simple builtin +// and pointer types. We do this by using `target variable` in lldb +// with global variables of type ptr-to-function or reference-to-function. +// This technique in general allows us to exercise most of LLDB's type +// system without a running process. + +template<typename T> +struct MakeResult { + static T result() { + return T{}; + } +}; + +template<typename T> +struct MakeResult<T&> { + static T& result() { + static T t; + return t; + } +}; + +template<typename T> +struct MakeResult<T&&> { + static T&& result() { + static T t; + return static_cast<T&&>(t); + } +}; + + +void nullary() {} + +template<typename Arg> +void unary(Arg) { } + +template<typename Ret, int N> +Ret unaryret() { return MakeResult<Ret>::result(); } + +template<typename A1, typename A2> +void binary(A1, A2) { } + +int varargs(int, int, ...) { return 0; } + +// Make sure to test every builtin type at least once for completeness. We +// test these in the globals-fundamentals.cpp when they are the types of +// variables but it's possible to imagine a situation where things behave +// differently as function arguments or return values than they do with +// global variables. + +// some interesting cases with argument types. +auto aa = &unary<bool>; +// CHECK: (void (*)(bool)) aa = {{.*}} +auto ab = &unary<char>; +// CHECK: (void (*)(char)) ab = {{.*}} +auto ac = &unary<signed char>; +// CHECK: (void (*)(signed char)) ac = {{.*}} +auto ad = &unary<unsigned char>; +// CHECK: (void (*)(unsigned char)) ad = {{.*}} +auto ae = &unary<char16_t>; +// CHECK: (void (*)(char16_t)) ae = {{.*}} +auto af = &unary<char32_t>; +// CHECK: (void (*)(char32_t)) af = {{.*}} +auto ag = &unary<wchar_t>; +// CHECK: (void (*)(wchar_t)) ag = {{.*}} +auto ah = &unary<short>; +// CHECK: (void (*)(short)) ah = {{.*}} +auto ai = &unary<unsigned short>; +// CHECK: (void (*)(unsigned short)) ai = {{.*}} +auto aj = &unary<int>; +// CHECK: (void (*)(int)) aj = {{.*}} +auto ak = &unary<unsigned int>; +// CHECK: (void (*)(unsigned int)) ak = {{.*}} +auto al = &unary<long>; +// CHECK: (void (*)(long)) al = {{.*}} +auto am = &unary<unsigned long>; +// CHECK: (void (*)(unsigned long)) am = {{.*}} +auto an = &unary<long long>; +// CHECK: (void (*)(long long)) an = {{.*}} +auto ao = &unary<unsigned long long>; +// CHECK: (void (*)(unsigned long long)) ao = {{.*}} +auto aq = &unary<float>; +// CHECK: (void (*)(float)) aq = {{.*}} +auto ar = &unary<double>; +// CHECK: (void (*)(double)) ar = {{.*}} + +auto as = &unary<int*>; +// CHECK: (void (*)(int *)) as = {{.*}} +auto at = &unary<int**>; +// CHECK: (void (*)(int **)) at = {{.*}} +auto au = &unary<int&>; +// CHECK: (void (*)(int &)) au = {{.*}} +auto av = &unary<int&&>; +// CHECK: (void (*)(int &&)) av = {{.*}} +auto aw = &unary<const int*>; +// CHECK: (void (*)(const int *)) aw = {{.*}} +auto ax = &unary<volatile int*>; +// CHECK: (void (*)(volatile int *)) ax = {{.*}} +auto ay = &unary<const volatile int*>; +// CHECK: (void (*)(const volatile int *)) ay = {{.*}} +auto az = &unary<void*&>; +// CHECK: (void (*)(void *&)) az = {{.*}} +auto aaa = &unary<int(&)[5]>; +// CHECK: (void (*)(int (&)[5])) aaa = {{.*}} +auto aab = &unary<int(*)[5]>; +// CHECK: (void (*)(int (*)[5])) aab = {{.*}} +auto aac = &unary<int(&&)[5]>; +// CHECK: (void (*)(int (&&)[5])) aac = {{.*}} +auto aad = &unary<int(*const)[5]>; +// CHECK: (void (*)(int (*)[5])) aad = {{.*}} + + +// same test cases with return values, note we can't overload on return type +// so we need to use a different instantiation each time. +auto ra = &unaryret<bool, 0>; +// CHECK: (bool (*)()) ra = {{.*}} +auto rb = &unaryret<char, 1>; +// CHECK: (char (*)()) rb = {{.*}} +auto rc = &unaryret<signed char, 2>; +// CHECK: (signed char (*)()) rc = {{.*}} +auto rd = &unaryret<unsigned char, 3>; +// CHECK: (unsigned char (*)()) rd = {{.*}} +auto re = &unaryret<char16_t, 4>; +// CHECK: (char16_t (*)()) re = {{.*}} +auto rf = &unaryret<char32_t, 5>; +// CHECK: (char32_t (*)()) rf = {{.*}} +auto rg = &unaryret<wchar_t, 6>; +// CHECK: (wchar_t (*)()) rg = {{.*}} +auto rh = &unaryret<short, 7>; +// CHECK: (short (*)()) rh = {{.*}} +auto ri = &unaryret<unsigned short, 8>; +// CHECK: (unsigned short (*)()) ri = {{.*}} +auto rj = &unaryret<int, 9>; +// CHECK: (int (*)()) rj = {{.*}} +auto rk = &unaryret<unsigned int, 10>; +// CHECK: (unsigned int (*)()) rk = {{.*}} +auto rl = &unaryret<long, 11>; +// CHECK: (long (*)()) rl = {{.*}} +auto rm = &unaryret<unsigned long, 12>; +// CHECK: (unsigned long (*)()) rm = {{.*}} +auto rn = &unaryret<long long, 13>; +// CHECK: (long long (*)()) rn = {{.*}} +auto ro = &unaryret<unsigned long long, 14>; +// CHECK: (unsigned long long (*)()) ro = {{.*}} +auto rq = &unaryret<float, 15>; +// CHECK: (float (*)()) rq = {{.*}} +auto rr = &unaryret<double, 16>; +// CHECK: (double (*)()) rr = {{.*}} + +auto rs = &unaryret<int*, 17>; +// CHECK: (int *(*)()) rs = {{.*}} +auto rt = &unaryret<int**, 18>; +// CHECK: (int **(*)()) rt = {{.*}} +auto ru = &unaryret<int&, 19>; +// CHECK: (int &(*)()) ru = {{.*}} +auto rv = &unaryret<int&&, 20>; +// CHECK: (int &&(*)()) rv = {{.*}} +auto rw = &unaryret<const int*, 21>; +// CHECK: (const int *(*)()) rw = {{.*}} +auto rx = &unaryret<volatile int*, 22>; +// CHECK: (volatile int *(*)()) rx = {{.*}} +auto ry = &unaryret<const volatile int*, 23>; +// CHECK: (const volatile int *(*)()) ry = {{.*}} +auto rz = &unaryret<void*&, 24>; +// CHECK: (void *&(*)()) rz = {{.*}} + +// FIXME: This output doesn't really look correct. It should probably be +// formatting this as `int(&)[5] (*)()`. +auto raa = &unaryret<int(&)[5], 25>; +// CHECK: (int (&(*)())[5]) raa = {{.*}} +auto rab = &unaryret<int(*)[5], 26>; +// CHECK: (int (*(*)())[5]) rab = {{.*}} +auto rac = &unaryret<int(&&)[5], 27>; +// CHECK: (int (&&(*)())[5]) rac = {{.*}} +auto rad = &unaryret<int(*const)[5], 28>; +// CHECK: (int (*const (*)())[5]) rad = {{.*}} + + + +// Function references, we only need a couple of these since most of the +// interesting cases are already tested. +auto &ref = unary<bool>; +// CHECK: (void (&)(bool)) ref = {{.*}} (&::ref = <Unable to determine byte size.>) +auto &ref2 = unary<volatile int*>; +// CHECK: (void (&)(volatile int *)) ref2 = {{.*}} (&::ref2 = <Unable to determine byte size.>) +auto &ref3 = varargs; +// CHECK: (int (&)(int, int, ...)) ref3 = {{.*}} (&::ref3 = <Unable to determine byte size.>) + +// Multiple arguments, as before, just something to make sure it works. +auto binp = &binary<int*, const int*>; +// CHECK: (void (*)(int *, const int *)) binp = {{.*}} +auto &binr = binary<int*, const int*>; +// CHECK: (void (&)(int *, const int *)) binr = {{.*}} (&::binr = <Unable to determine byte size.>) + +// And finally, a function with no arguments. +auto null = &nullary; +// CHECK: (void (*)()) null = {{.*}} + +// FIXME: These currently don't work because clang-cl emits incorrect debug info +// for std::nullptr_t. We should fix these in clang-cl. +auto rae = &unaryret<decltype(nullptr), 29>; +// CHECK: (nullptr_t (*)()) rae = {{.*}} +auto aae = &unary<decltype(nullptr)>; +// CHECK: (void (*)(nullptr_t)) aae = {{.*}} + +int main(int argc, char **argv) { + return 0; +} Index: lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp =================================================================== --- lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp +++ lldb/trunk/lit/SymbolFile/NativePDB/function-types-classes.cpp @@ -0,0 +1,118 @@ +// clang-format off +// REQUIRES: lld + +// Test that we can display function signatures with class types. +// RUN: clang-cl /Z7 /GS- /GR- /c -Xclang -fkeep-static-consts /Fo%t.obj -- %s +// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \ +// RUN: %p/Inputs/function-types-classes.lldbinit | FileCheck %s + +// This is just some unimportant helpers needed so that we can get reference and +// rvalue-reference types into return values. +template<typename T> +struct MakeResult { + static T result() { + return T{}; + } +}; + +template<typename T> +struct MakeResult<T&> { + static T& result() { + static T t; + return t; + } +}; + +template<typename T> +struct MakeResult<T&&> { + static T&& result() { + static T t; + return static_cast<T&&>(t); + } +}; + + +template<typename R> +R nullary() { return MakeResult<R>::result(); } + +template<typename R, typename A, typename B> +R three(A a, B b) { return MakeResult<R>::result(); } + +template<typename R, typename A, typename B, typename C> +R four(A a, B b, C c) { return MakeResult<R>::result(); } + +struct S {}; +class C {}; +union U {}; +enum E {}; + +namespace A { + namespace B { + // NS::NS + struct S { }; + } + + struct C { + // NS::Struct + struct S {}; + }; +} + +struct B { + struct A { + // Struct::Struct + struct S {}; + }; +}; + +template<typename T> +struct TC {}; + +// const and volatile modifiers +auto a = &four<S, C*, U&, E&&>; +// CHECK: (S (*)(C *, U &, E &&)) a = {{.*}} +auto b = &four<E, const S*, const C&, const U&&>; +// CHECK: (E (*)(const S *, const C &, const U &&)) b = {{.*}} +auto c = &four<U, volatile E*, volatile S&, volatile C&&>; +// CHECK: (U (*)(volatile E *, volatile S &, volatile C &&)) c = {{.*}} +auto d = &four<C, const volatile U*, const volatile E&, const volatile S&&>; +// CHECK: (C (*)(const volatile U *, const volatile E &, const volatile S &&)) d = {{.*}} + +// classes nested in namespaces and inner classes + +// FIXME: LLDB with native pdb plugin doesn't currently resolve nested names +// correctly, because it requires creating clang::NamespaceDecl or +// clang::RecordDecl for the outer namespace or classes. PDB doesn't contain +// sufficient information to distinguish namespace scopes from nested class +// scopes, so the best we can hope for is a heuristic reconstruction of the +// clang AST based on demangling the type's unique name. However, this is +// as-yet unimplemented in the native PDB plugin, so for now all of these will +// all just look like `S` when LLDB prints them. +auto e = &three<A::B::S*, B::A::S*, A::C::S&>; +// CHECK: (S *(*)(S *, S &)) e = {{.*}} +auto f = &three<A::C::S&, A::B::S*, B::A::S*>; +// CHECK: (S &(*)(S *, S *)) f = {{.*}} +auto g = &three<B::A::S*, A::C::S&, A::B::S*>; +// CHECK: (S *(*)(S &, S *)) g = {{.*}} + +// parameter types that are themselves template instantiations. +auto h = &four<TC<void>, TC<int>, TC<TC<int>>, TC<A::B::S>>; +// Note the awkward space in TC<TC<int> >. This is because this is how template +// instantiations are emitted by the compiler, as the fully instantiated name. +// Only via reconstruction of the AST through the mangled type name (see above +// comment) can we hope to do better than this). +// CHECK: (TC<void> (*)(TC<int>, TC<TC<int> >, S>)) h = {{.*}} + +auto i = &nullary<A::B::S>; +// CHECK: (S (*)()) i = {{.*}} + + +// Make sure we can handle types that don't have complete debug info. +struct Incomplete; +auto incomplete = &three<Incomplete*, Incomplete**, const Incomplete*>; +// CHECK: (Incomplete *(*)(Incomplete **, const Incomplete *)) incomplete = {{.*}} + +int main(int argc, char **argv) { + return 0; +} Index: lldb/trunk/lit/SymbolFile/NativePDB/function-types-calling-conv.cpp =================================================================== --- lldb/trunk/lit/SymbolFile/NativePDB/function-types-calling-conv.cpp +++ lldb/trunk/lit/SymbolFile/NativePDB/function-types-calling-conv.cpp @@ -0,0 +1,33 @@ +// clang-format off +// REQUIRES: lld + +// RUN: clang-cl -m32 /Z7 /GS- /GR- /c -Xclang -fkeep-static-consts /Fo%t.obj -- %s +// RUN: lld-link /DEBUG /nodefaultlib /entry:main /OUT:%t.exe /PDB:%t.pdb -- %t.obj +// RUN: env LLDB_USE_NATIVE_PDB_READER=1 lldb -f %t.exe -s \ +// RUN: %p/Inputs/function-types-calling-conv.lldbinit | FileCheck %s + + +void __stdcall StdcallFn() {} +void __fastcall FastcallFn() {} +void __thiscall ThiscallFn() {} +void __cdecl CdeclFn() {} +void __vectorcall VectorcallFn() {} + +auto sfn = &StdcallFn; +// CHECK: (void (*)() __attribute__((stdcall))) sfn = {{.*}} + +auto ffn = &FastcallFn; +// CHECK: (void (*)() __attribute__((fastcall))) ffn = {{.*}} + +auto tfn = &ThiscallFn; +// CHECK: (void (*)() __attribute__((thiscall))) tfn = {{.*}} + +auto cfn = &CdeclFn; +// CHECK: (void (*)()) cfn = {{.*}} + +auto vfn = &VectorcallFn; +// CHECK: (void (*)() __attribute__((vectorcall))) vfn = {{.*}} + +int main(int argc, char **argv) { + return 0; +} \ No newline at end of file Index: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-calling-conv.lldbinit =================================================================== --- lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-calling-conv.lldbinit +++ lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-calling-conv.lldbinit @@ -0,0 +1,7 @@ +target variable sfn +target variable ffn +target variable tfn +target variable cfn +target variable vfn + +quit Index: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-builtins.lldbinit =================================================================== --- lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-builtins.lldbinit +++ lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-builtins.lldbinit @@ -0,0 +1,70 @@ +command alias dv target variable + +dv aa +dv ab +dv ac +dv ad +dv ae +dv af +dv ag +dv ah +dv ai +dv aj +dv ak +dv al +dv am +dv an +dv ao +dv aq +dv ar +dv as +dv at +dv au +dv av +dv aw +dv ax +dv ay +dv az +dv aaa +dv aab +dv aac +dv aad +dv ra +dv rb +dv rc +dv rd +dv re +dv rf +dv rg +dv rh +dv ri +dv rj +dv rk +dv rl +dv rm +dv rn +dv ro +dv rq +dv rr +dv rs +dv rt +dv ru +dv rv +dv rw +dv rx +dv ry +dv rz +dv raa +dv rab +dv rac +dv rad +dv ref +dv ref2 +dv ref3 +dv binp +dv binr +dv null +dv rae +dv aae + +quit Index: lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit =================================================================== --- lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit +++ lldb/trunk/lit/SymbolFile/NativePDB/Inputs/function-types-classes.lldbinit @@ -0,0 +1,12 @@ +target variable a +target variable b +target variable c +target variable d +target variable e +target variable f +target variable g +target variable h +target variable i +target variable incomplete + +quit Index: llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h =================================================================== --- llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h +++ llvm/trunk/include/llvm/DebugInfo/CodeView/SymbolDeserializer.h @@ -47,7 +47,7 @@ return Error::success(); } template <typename T> static Expected<T> deserializeAs(CVSymbol Symbol) { - T Record(Symbol.kind()); + T Record(static_cast<SymbolRecordKind>(Symbol.kind())); if (auto EC = deserializeAs<T>(Symbol, Record)) return std::move(EC); return Record;
_______________________________________________ lldb-commits mailing list lldb-commits@lists.llvm.org http://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits