-
Notifications
You must be signed in to change notification settings - Fork 15.2k
[clang][DebugInfo] Add symbol for debugger with VTable information. #130255
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
4bd0c48
e811ab7
dc84180
8356bb7
75357fa
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||
|---|---|---|---|---|---|---|
|
|
@@ -2518,6 +2518,59 @@ StringRef CGDebugInfo::getVTableName(const CXXRecordDecl *RD) { | |||||
| return internString("_vptr$", RD->getNameAsString()); | ||||||
| } | ||||||
|
|
||||||
| // Emit symbol for the debugger that points to the vtable address for | ||||||
| // the given class. The symbol is named as '_vtable$'. | ||||||
| // The debugger does not need to know any details about the contents of the | ||||||
| // vtable as it can work this out using its knowledge of the ABI and the | ||||||
| // existing information in the DWARF. The type is assumed to be 'void *'. | ||||||
| void CGDebugInfo::emitVTableSymbol(llvm::GlobalVariable *VTable, | ||||||
| const CXXRecordDecl *RD) { | ||||||
| ASTContext &Context = CGM.getContext(); | ||||||
| SmallString<64> Buffer; | ||||||
| Twine SymbolName = internString("_vtable$"); | ||||||
| StringRef SymbolNameRef = SymbolName.toStringRef(Buffer); | ||||||
|
||||||
| DeclContext *DC = static_cast<DeclContext *>(const_cast<CXXRecordDecl *>(RD)); | ||||||
|
||||||
| SourceLocation Loc; | ||||||
| QualType VoidPtr = Context.getPointerType(Context.VoidTy); | ||||||
|
|
||||||
| // We deal with two different contexts: | ||||||
| // - The type for the variable, which is part of the class that has the | ||||||
| // vtable, is placed in the context of the DICompositeType metadata. | ||||||
| // - The DIGlobalVariable for the vtable is put in the DICompileUnitScope. | ||||||
|
|
||||||
| // The created non-member should be mark as 'artificial'. It will be | ||||||
| // placed it inside the scope of the C++ class/structure. | ||||||
|
||||||
| // placed it inside the scope of the C++ class/structure. | |
| // placed inside the scope of the C++ class/structure. |
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Instead of calling createArtificialType could we just add llvm::DINode::FlagArtificial to the Flags parameter we pass to createStaticMemberType?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Very good point.
Outdated
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks like this is how ItaniumCXXABI::getAddrOfVTable does it? Might be worth splitting this out into a common helper that can be shared between the two? (there's a couple more copies of this around Clang).
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Probably also need to guard this behind CGM.getTarget().getCXXABI().isItaniumFamily() or something (or even just short-circuit this entire function if we're not generating for Itanium?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Created a helper function just to calculate the alignment.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The whole function emitVTableSymbol now is guarded.
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| #include "vtable-debug-info-inheritance-simple-base.h" | ||
|
|
||
| void NSP::CBase::zero() {} | ||
| int NSP::CBase::one() { return 1; } | ||
| int NSP::CBase::two() { return 2; }; | ||
| int NSP::CBase::three() { return 3; } | ||
|
|
||
| #ifdef SYMBOL_AT_FILE_SCOPE | ||
| static NSP::CBase Base; | ||
| #else | ||
| void fooBase() { | ||
| NSP::CBase Base; | ||
| } | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,15 @@ | ||
| #ifndef BASE_H | ||
| #define BASE_H | ||
|
|
||
| namespace NSP { | ||
| struct CBase { | ||
| unsigned B = 1; | ||
| virtual void zero(); | ||
| virtual int one(); | ||
| virtual int two(); | ||
| virtual int three(); | ||
| }; | ||
| } | ||
|
|
||
| extern void fooBase(); | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,13 @@ | ||
| #include "vtable-debug-info-inheritance-simple-derived.h" | ||
|
|
||
| void CDerived::zero() {} | ||
| int CDerived::two() { return 22; }; | ||
| int CDerived::three() { return 33; } | ||
|
|
||
| #ifdef SYMBOL_AT_FILE_SCOPE | ||
| static CDerived Derived; | ||
| #else | ||
| void fooDerived() { | ||
| CDerived Derived; | ||
| } | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,14 @@ | ||
| #include "vtable-debug-info-inheritance-simple-base.h" | ||
|
|
||
| #ifndef DERIVED_H | ||
| #define DERIVED_H | ||
|
|
||
| struct CDerived : NSP::CBase { | ||
| unsigned D = 2; | ||
| void zero() override; | ||
| int two() override; | ||
| int three() override; | ||
| }; | ||
|
|
||
| extern void fooDerived(); | ||
| #endif |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,87 @@ | ||
| // REQUIRES: target={{x86_64.*-linux.*}} | ||
|
|
||
| // Diamond inheritance case: | ||
| // For CBase, CLeft, CRight and CDerived we check: | ||
| // - Generation of their vtables (including attributes). | ||
| // - Generation of their '_vtable$' data members: | ||
| // * Correct scope and attributes | ||
|
|
||
| namespace NSP { | ||
| struct CBase { | ||
| int B = 0; | ||
| virtual char fooBase() { return 'B'; } | ||
| }; | ||
| } | ||
|
|
||
| namespace NSP_1 { | ||
| struct CLeft : NSP::CBase { | ||
| int M1 = 1; | ||
| char fooBase() override { return 'O'; }; | ||
| virtual int fooLeft() { return 1; } | ||
| }; | ||
| } | ||
|
|
||
| namespace NSP_2 { | ||
| struct CRight : NSP::CBase { | ||
| int M2 = 2; | ||
| char fooBase() override { return 'T'; }; | ||
| virtual int fooRight() { return 2; } | ||
| }; | ||
| } | ||
|
|
||
| struct CDerived : NSP_1::CLeft, NSP_2::CRight { | ||
| int D = 3; | ||
| char fooBase() override { return 'D'; }; | ||
| int fooDerived() { return 3; }; | ||
| }; | ||
|
|
||
| int main() { | ||
| NSP::CBase Base; | ||
| NSP_1::CLeft Left; | ||
| NSP_2::CRight Right; | ||
| CDerived Derived; | ||
|
|
||
| return 0; | ||
| } | ||
|
|
||
| // RUN: %clang --target=x86_64-linux -Xclang -disable-O0-optnone -Xclang -disable-llvm-passes -emit-llvm -S -g %s -o - | FileCheck %s | ||
|
|
||
| // CHECK: $_ZTVN3NSP5CBaseE = comdat any | ||
| // CHECK: $_ZTVN5NSP_15CLeftE = comdat any | ||
| // CHECK: $_ZTVN5NSP_26CRightE = comdat any | ||
| // CHECK: $_ZTV8CDerived = comdat any | ||
|
|
||
| // CHECK: @_ZTVN3NSP5CBaseE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[BASE_VTABLE_VAR:![0-9]*]] | ||
| // CHECK: @_ZTVN5NSP_15CLeftE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[LEFT_VTABLE_VAR:![0-9]*]] | ||
| // CHECK: @_ZTVN5NSP_26CRightE = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[RIGHT_VTABLE_VAR:![0-9]*]] | ||
| // CHECK: @_ZTV8CDerived = linkonce_odr {{dso_local|hidden}} unnamed_addr constant {{.*}}, comdat, align 8, !dbg [[DERIVED_VTABLE_VAR:![0-9]*]] | ||
|
|
||
| // CHECK: [[BASE_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[BASE_VTABLE:![0-9]*]], expr: !DIExpression()) | ||
| // CHECK-NEXT: [[BASE_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN3NSP5CBaseE" | ||
|
|
||
| // CHECK: [[LEFT_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[LEFT_VTABLE:![0-9]*]], expr: !DIExpression()) | ||
| // CHECK-NEXT: [[LEFT_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN5NSP_15CLeftE" | ||
|
|
||
| // CHECK: [[TYPE:![0-9]*]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: null, size: 64) | ||
|
|
||
| // CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[LEFT:![0-9]*]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember) | ||
|
|
||
| // CHECK: [[LEFT]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CLeft" | ||
|
|
||
| // CHECK: [[BASE:![0-9]*]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CBase" | ||
|
|
||
| // CHECK: [[RIGHT_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[RIGHT_VTABLE:![0-9]*]], expr: !DIExpression()) | ||
| // CHECK-NEXT: [[RIGHT_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTVN5NSP_26CRightE" | ||
|
|
||
| // CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[RIGHT:![0-9]*]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember) | ||
|
|
||
| // CHECK: [[RIGHT]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CRight" | ||
|
|
||
| // CHECK: [[DERIVED_VTABLE_VAR]] = !DIGlobalVariableExpression(var: [[DERIVED_VTABLE:![0-9]*]], expr: !DIExpression()) | ||
| // CHECK-NEXT: [[DERIVED_VTABLE]] = distinct !DIGlobalVariable(name: "_vtable$", linkageName: "_ZTV8CDerived" | ||
|
|
||
| // CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[DERIVED:![0-9]*]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember) | ||
|
|
||
| // CHECK: [[DERIVED]] = distinct !DICompositeType(tag: DW_TAG_structure_type, name: "CDerived" | ||
|
|
||
| // CHECK: !DIDerivedType(tag: DW_TAG_variable, name: "_vtable$", scope: [[BASE]], file: {{.*}}, baseType: [[TYPE]], flags: DIFlagPrivate | DIFlagArtificial | DIFlagStaticMember) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
unused?