Skip to content

Commit 3f342ba

Browse files
weliveindetailadrian-prantl
authored andcommitted
[lldb] Infer MSInheritanceAttr for CXXRecordDecl with DWARF on Windows (llvm#115177)
Following up from llvm#112928, we can reuse the approach from Clang Sema to infer the MSInheritanceModel and add the necessary attribute manually. This allows the inspection of member function pointers with DWARF on Windows. (cherry picked from commit e9dd419)
1 parent 214f002 commit 3f342ba

File tree

3 files changed

+74
-14
lines changed

3 files changed

+74
-14
lines changed

lldb/source/Plugins/SymbolFile/DWARF/DWARFASTParserClang.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,7 @@
4848
#include "clang/AST/DeclObjC.h"
4949
#include "clang/AST/DeclTemplate.h"
5050
#include "clang/AST/Type.h"
51+
#include "clang/Basic/Specifiers.h"
5152
#include "llvm/ADT/StringExtras.h"
5253
#include "llvm/Demangle/Demangle.h"
5354
#include "llvm/Support/Casting.h"
@@ -2369,6 +2370,16 @@ bool DWARFASTParserClang::CompleteRecordType(const DWARFDIE &die,
23692370
if (record_decl)
23702371
GetClangASTImporter().SetRecordLayout(record_decl, layout_info);
23712372

2373+
// DWARF doesn't have the attribute, but we can infer the value the same way
2374+
// as Clang Sema does. It's required to calculate the size of pointers to
2375+
// member functions of this type.
2376+
if (m_ast.getASTContext().getTargetInfo().getCXXABI().isMicrosoft()) {
2377+
auto IM = record_decl->calculateInheritanceModel();
2378+
record_decl->addAttr(clang::MSInheritanceAttr::CreateImplicit(
2379+
m_ast.getASTContext(), true, {},
2380+
clang::MSInheritanceAttr::Spelling(IM)));
2381+
}
2382+
23722383
// Now parse all contained types inside of the class. We make forward
23732384
// declarations to all classes, but we need the CXXRecordDecl to have decls
23742385
// for all contained types because we don't get asked for them via the

lldb/source/Plugins/TypeSystem/Clang/TypeSystemClang.cpp

Lines changed: 11 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2881,7 +2881,17 @@ static bool GetCompleteQualType(clang::ASTContext *ast,
28812881
allow_completion);
28822882

28832883
case clang::Type::MemberPointer:
2884-
return !qual_type.getTypePtr()->isIncompleteType();
2884+
// MS C++ ABI requires type of the class to be complete of which the pointee
2885+
// is a member.
2886+
if (ast->getTargetInfo().getCXXABI().isMicrosoft()) {
2887+
auto *MPT = qual_type.getTypePtr()->castAs<clang::MemberPointerType>();
2888+
if (MPT->getClass()->isRecordType())
2889+
GetCompleteRecordType(ast, clang::QualType(MPT->getClass(), 0),
2890+
allow_completion);
2891+
2892+
return !qual_type.getTypePtr()->isIncompleteType();
2893+
}
2894+
break;
28852895

28862896
default:
28872897
break;

lldb/test/Shell/SymbolFile/DWARF/x86/member-pointers.cpp

Lines changed: 52 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,23 +2,62 @@
22

33
// Itanium ABI:
44
// RUN: %clang --target=x86_64-pc-linux -gdwarf -c -o %t_linux.o %s
5-
// RUN: %lldb -f %t_linux.o -b -o "target variable mp" | FileCheck %s
5+
// RUN: %lldb -f %t_linux.o -b -o "target variable s1 s2 m1 m2 v1 v2 v3 v4" | FileCheck --check-prefix=CHECK-GNU %s
66
//
7-
// CHECK: (char SI::*) mp = 0x0000000000000000
7+
// CHECK-GNU: (void (Single1::*)()) s1 = 0x00000000000000000000000000000000
8+
// CHECK-GNU: (void (Single2::*)()) s2 = 0x00000000000000000000000000000000
9+
// CHECK-GNU: (void (Multiple1::*)()) m1 = 0x00000000000000000000000000000000
10+
// CHECK-GNU: (void (Multiple2::*)()) m2 = 0x00000000000000000000000000000000
11+
// CHECK-GNU: (void (Virtual1::*)()) v1 = 0x00000000000000000000000000000000
12+
// CHECK-GNU: (void (Virtual2::*)()) v2 = 0x00000000000000000000000000000000
13+
// CHECK-GNU: (void (Virtual3::*)()) v3 = 0x00000000000000000000000000000000
14+
// CHECK-GNU: (void (Virtual4::*)()) v4 = 0x00000000000000000000000000000000
815

916
// Microsoft ABI:
10-
// RUN: %clang_cl --target=x86_64-windows-msvc -c -gdwarf -o %t_win.obj -- %s
11-
// RUN: lld-link /out:%t_win.exe %t_win.obj /nodefaultlib /entry:main /debug
12-
// RUN: %lldb -f %t_win.exe -b -o "target variable mp" | FileCheck --check-prefix=CHECK-MSVC %s
17+
// RUN: %clang_cl --target=x86_64-windows-msvc -c -gdwarf -o %t_win.obj /GS- -- %s
18+
// RUN: lld-link /out:%t_win.exe %t_win.obj /entry:main /debug /nodefaultlib
19+
// RUN: %lldb -f %t_win.exe -b -o "target variable s1 s2 m1 m2 v1 v2 v3 v4" | FileCheck --check-prefix=CHECK-MSVC %s
1320
//
14-
// DWARF has no representation of MSInheritanceAttr, so we cannot determine the size
15-
// of member-pointers yet. For the moment, make sure we don't crash on such variables.
16-
// CHECK-MSVC: error: Unable to determine byte size.
21+
// CHECK-MSVC: (void (Single1::*)()) s1 = 0x0000000000000000
22+
// CHECK-MSVC: (void (Single2::*)()) s2 = 0x0000000000000000
23+
// CHECK-MSVC: (void (Multiple1::*)()) m1 = 0x00000000000000000000000000000000
24+
// CHECK-MSVC: (void (Multiple2::*)()) m2 = 0x00000000000000000000000000000000
25+
// CHECK-MSVC: (void (Virtual1::*)()) v1 = 0xffffffff000000000000000000000000
26+
// CHECK-MSVC: (void (Virtual2::*)()) v2 = 0xffffffff000000000000000000000000
27+
// CHECK-MSVC: (void (Virtual3::*)()) v3 = 0xffffffff000000000000000000000000
28+
// CHECK-MSVC: (void (Virtual4::*)()) v4 = 0xffffffff000000000000000000000000
1729

18-
struct SI {
19-
char si;
20-
};
30+
// clang-format off
31+
struct Single1 { void s1() {} };
32+
struct Single2 : Single1 { void s2() {} };
2133

22-
char SI::*mp = &SI::si;
34+
struct Helper {};
35+
struct Multiple1 : Single1, Helper { void m1() {} };
36+
struct Multiple2 : Multiple1 { void m2() {} };
2337

24-
int main() { return 0; }
38+
struct Virtual1 : virtual Single1 { void v1() {} };
39+
struct Virtual2 : Virtual1 { void v2() {} };
40+
struct Virtual3 : virtual Multiple1 { void v3() {} };
41+
struct Virtual4 : Virtual1, Helper { void v4() {} };
42+
43+
void (Single1::*s1)() = nullptr;
44+
void (Single2::*s2)() = nullptr;
45+
void (Multiple1::*m1)() = nullptr;
46+
void (Multiple2::*m2)() = nullptr;
47+
void (Virtual1::*v1)() = nullptr;
48+
void (Virtual2::*v2)() = nullptr;
49+
void (Virtual3::*v3)() = nullptr;
50+
void (Virtual4::*v4)() = nullptr;
51+
52+
int main(int argc, char *argv[]) {
53+
// We need to force emission of type info to DWARF. That's reasonable, because
54+
// Clang doesn't know that we need it to infer member-pointer sizes. We could
55+
// probably teach Clang to do so, but in most real-world scenarios this might
56+
// be a non-issue.
57+
Virtual1 vi1;
58+
Virtual2 vi2;
59+
Virtual3 vi3;
60+
Virtual4 vi4;
61+
int sum = sizeof(Single2) + sizeof(Multiple2);
62+
return argc < sum ? 0 : 1;
63+
}

0 commit comments

Comments
 (0)