Skip to content

Commit d77ae15

Browse files
committed
[DebugInfo] Support to emit debugInfo for extern variables
Extern variable usage in BPF is different from traditional pure user space application. Recent discussion in linux bpf mailing list has two use cases where debug info types are required to use extern variables: - extern types are required to have a suitable interface in libbpf (bpf loader) to provide kernel config parameters to bpf programs. https://lore.kernel.org/bpf/CAEf4BzYCNo5GeVGMhp3fhysQ=_axAf=23PtwaZs-yAyafmXC9g@mail.gmail.com/T/#t - extern types are required so kernel bpf verifier can verify program which uses external functions more precisely. This will make later link with actual external function no need to reverify. https://lore.kernel.org/bpf/[email protected]/T/#m8d5c3e87ffe7f2764e02d722cb0d8cbc136880ed This patch added clang support to emit debuginfo for extern variables with a TargetInfo hook to enable it. The debuginfo for the extern variable is emitted only if that extern variable is referenced in the current compilation unit. Currently, only BPF target enables to generate debug info for extern variables. The emission of such debuginfo is disabled for C++ at this moment since BPF only supports a subset of C language. Emission with C++ can be enabled later if an appropriate use case is identified. -fstandalone-debug permits us to see more debuginfo with the cost of bloated binary size. This patch did not add emission of extern variable debug info with -fstandalone-debug. This can be re-evaluated if there is a real need. Differential Revision: https://reviews.llvm.org/D70696
1 parent 9614a7c commit d77ae15

File tree

20 files changed

+170
-7
lines changed

20 files changed

+170
-7
lines changed

clang/include/clang/AST/ASTConsumer.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,11 @@ class ASTConsumer {
102102
/// modified by the introduction of an implicit zero initializer.
103103
virtual void CompleteTentativeDefinition(VarDecl *D) {}
104104

105+
/// CompleteExternalDeclaration - Callback invoked at the end of a translation
106+
/// unit to notify the consumer that the given external declaration should be
107+
/// completed.
108+
virtual void CompleteExternalDeclaration(VarDecl *D) {}
109+
105110
/// Callback invoked when an MSInheritanceAttr has been attached to a
106111
/// CXXRecordDecl.
107112
virtual void AssignInheritanceModel(CXXRecordDecl *RD) {}

clang/include/clang/Basic/TargetInfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1389,6 +1389,9 @@ class TargetInfo : public virtual TransferrableTargetInfo,
13891389

13901390
virtual void setAuxTarget(const TargetInfo *Aux) {}
13911391

1392+
/// Whether target allows debuginfo types for decl only variables.
1393+
virtual bool allowDebugInfoForExternalVar() const { return false; }
1394+
13921395
protected:
13931396
/// Copy type and layout related info.
13941397
void copyAuxTarget(const TargetInfo *Aux);

clang/include/clang/Sema/Sema.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -667,6 +667,9 @@ class Sema final {
667667
/// All the tentative definitions encountered in the TU.
668668
TentativeDefinitionsType TentativeDefinitions;
669669

670+
/// All the external declarations encoutered and used in the TU.
671+
SmallVector<VarDecl *, 4> ExternalDeclarations;
672+
670673
typedef LazyVector<const DeclaratorDecl *, ExternalSemaSource,
671674
&ExternalSemaSource::ReadUnusedFileScopedDecls, 2, 2>
672675
UnusedFileScopedDeclsType;

clang/lib/Basic/Targets/BPF.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,8 @@ class LLVM_LIBRARY_VISIBILITY BPFTargetInfo : public TargetInfo {
7676
return None;
7777
}
7878

79+
bool allowDebugInfoForExternalVar() const override { return true; }
80+
7981
CallingConvCheckResult checkCallingConvention(CallingConv CC) const override {
8082
switch (CC) {
8183
default:

clang/lib/CodeGen/CGDebugInfo.cpp

Lines changed: 21 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4482,7 +4482,7 @@ void CGDebugInfo::EmitGlobalVariable(llvm::GlobalVariable *Var,
44824482

44834483
GVE = DBuilder.createGlobalVariableExpression(
44844484
DContext, DeclName, LinkageName, Unit, LineNo, getOrCreateType(T, Unit),
4485-
Var->hasLocalLinkage(),
4485+
Var->hasLocalLinkage(), true,
44864486
Expr.empty() ? nullptr : DBuilder.createExpression(Expr),
44874487
getOrCreateStaticDataMemberDeclarationOrNull(D), TemplateParameters,
44884488
Align);
@@ -4585,10 +4585,29 @@ void CGDebugInfo::EmitGlobalVariable(const ValueDecl *VD, const APValue &Init) {
45854585

45864586
GV.reset(DBuilder.createGlobalVariableExpression(
45874587
DContext, Name, StringRef(), Unit, getLineNumber(VD->getLocation()), Ty,
4588-
true, InitExpr, getOrCreateStaticDataMemberDeclarationOrNull(VarD),
4588+
true, true, InitExpr, getOrCreateStaticDataMemberDeclarationOrNull(VarD),
45894589
TemplateParameters, Align));
45904590
}
45914591

4592+
void CGDebugInfo::EmitExternalVariable(llvm::GlobalVariable *Var,
4593+
const VarDecl *D) {
4594+
assert(DebugKind >= codegenoptions::LimitedDebugInfo);
4595+
if (D->hasAttr<NoDebugAttr>())
4596+
return;
4597+
4598+
auto Align = getDeclAlignIfRequired(D, CGM.getContext());
4599+
llvm::DIFile *Unit = getOrCreateFile(D->getLocation());
4600+
StringRef Name = D->getName();
4601+
llvm::DIType *Ty = getOrCreateType(D->getType(), Unit);
4602+
4603+
llvm::DIScope *DContext = getDeclContextDescriptor(D);
4604+
llvm::DIGlobalVariableExpression *GVE =
4605+
DBuilder.createGlobalVariableExpression(
4606+
DContext, Name, StringRef(), Unit, getLineNumber(D->getLocation()),
4607+
Ty, false, false, nullptr, nullptr, nullptr, Align);
4608+
Var->addDebugInfo(GVE);
4609+
}
4610+
45924611
llvm::DIScope *CGDebugInfo::getCurrentContextDescriptor(const Decl *D) {
45934612
if (!LexicalBlockStack.empty())
45944613
return LexicalBlockStack.back();

clang/lib/CodeGen/CGDebugInfo.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -478,6 +478,9 @@ class CGDebugInfo {
478478
/// Emit a constant global variable's debug info.
479479
void EmitGlobalVariable(const ValueDecl *VD, const APValue &Init);
480480

481+
/// Emit information about an external variable.
482+
void EmitExternalVariable(llvm::GlobalVariable *GV, const VarDecl *Decl);
483+
481484
/// Emit C++ using directive.
482485
void EmitUsingDirective(const UsingDirectiveDecl &UD);
483486

clang/lib/CodeGen/CodeGenAction.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,10 @@ namespace clang {
336336
Gen->CompleteTentativeDefinition(D);
337337
}
338338

339+
void CompleteExternalDeclaration(VarDecl *D) override {
340+
Gen->CompleteExternalDeclaration(D);
341+
}
342+
339343
void AssignInheritanceModel(CXXRecordDecl *RD) override {
340344
Gen->AssignInheritanceModel(RD);
341345
}

clang/lib/CodeGen/CodeGenModule.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3715,6 +3715,10 @@ void CodeGenModule::EmitTentativeDefinition(const VarDecl *D) {
37153715
EmitGlobalVarDefinition(D);
37163716
}
37173717

3718+
void CodeGenModule::EmitExternalDeclaration(const VarDecl *D) {
3719+
EmitExternalVarDeclaration(D);
3720+
}
3721+
37183722
CharUnits CodeGenModule::GetTargetTypeStoreSize(llvm::Type *Ty) const {
37193723
return Context.toCharUnitsFromBits(
37203724
getDataLayout().getTypeStoreSizeInBits(Ty));
@@ -4098,6 +4102,19 @@ void CodeGenModule::EmitGlobalVarDefinition(const VarDecl *D,
40984102
DI->EmitGlobalVariable(GV, D);
40994103
}
41004104

4105+
void CodeGenModule::EmitExternalVarDeclaration(const VarDecl *D) {
4106+
if (CGDebugInfo *DI = getModuleDebugInfo())
4107+
if (getCodeGenOpts().getDebugInfo() >= codegenoptions::LimitedDebugInfo) {
4108+
QualType ASTTy = D->getType();
4109+
llvm::Type *Ty = getTypes().ConvertTypeForMem(D->getType());
4110+
llvm::PointerType *PTy =
4111+
llvm::PointerType::get(Ty, getContext().getTargetAddressSpace(ASTTy));
4112+
llvm::Constant *GV = GetOrCreateLLVMGlobal(D->getName(), PTy, D);
4113+
DI->EmitExternalVariable(
4114+
cast<llvm::GlobalVariable>(GV->stripPointerCasts()), D);
4115+
}
4116+
}
4117+
41014118
static bool isVarDeclStrongDefinition(const ASTContext &Context,
41024119
CodeGenModule &CGM, const VarDecl *D,
41034120
bool NoCommon) {

clang/lib/CodeGen/CodeGenModule.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1165,6 +1165,8 @@ class CodeGenModule : public CodeGenTypeCache {
11651165

11661166
void EmitTentativeDefinition(const VarDecl *D);
11671167

1168+
void EmitExternalDeclaration(const VarDecl *D);
1169+
11681170
void EmitVTable(CXXRecordDecl *Class);
11691171

11701172
void RefreshTypeCacheForClass(const CXXRecordDecl *Class);
@@ -1400,6 +1402,7 @@ class CodeGenModule : public CodeGenTypeCache {
14001402
void EmitMultiVersionFunctionDefinition(GlobalDecl GD, llvm::GlobalValue *GV);
14011403

14021404
void EmitGlobalVarDefinition(const VarDecl *D, bool IsTentative = false);
1405+
void EmitExternalVarDeclaration(const VarDecl *D);
14031406
void EmitAliasDefinition(GlobalDecl GD);
14041407
void emitIFuncDefinition(GlobalDecl GD);
14051408
void emitCPUDispatchDefinition(GlobalDecl GD);

clang/lib/CodeGen/ModuleBuilder.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -290,6 +290,10 @@ namespace {
290290
Builder->EmitTentativeDefinition(D);
291291
}
292292

293+
void CompleteExternalDeclaration(VarDecl *D) override {
294+
Builder->EmitExternalDeclaration(D);
295+
}
296+
293297
void HandleVTable(CXXRecordDecl *RD) override {
294298
if (Diags.hasErrorOccurred())
295299
return;

clang/lib/Sema/Sema.cpp

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1137,6 +1137,13 @@ void Sema::ActOnEndOfTranslationUnit() {
11371137
Consumer.CompleteTentativeDefinition(VD);
11381138
}
11391139

1140+
for (auto D : ExternalDeclarations) {
1141+
if (!D || D->isInvalidDecl() || D->getPreviousDecl() || !D->isUsed())
1142+
continue;
1143+
1144+
Consumer.CompleteExternalDeclaration(D);
1145+
}
1146+
11401147
// If there were errors, disable 'unused' warnings since they will mostly be
11411148
// noise. Don't warn for a use from a module: either we should warn on all
11421149
// file-scope declarations in modules or not at all, but whether the

clang/lib/Sema/SemaDecl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12200,6 +12200,10 @@ void Sema::ActOnUninitializedDecl(Decl *RealDecl) {
1220012200
Diag(Var->getLocation(), diag::note_private_extern);
1220112201
}
1220212202

12203+
if (Context.getTargetInfo().allowDebugInfoForExternalVar() &&
12204+
!Var->isInvalidDecl() && !getLangOpts().CPlusPlus)
12205+
ExternalDeclarations.push_back(Var);
12206+
1220312207
return;
1220412208

1220512209
case VarDecl::TentativeDefinition:
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// REQUIRES: bpf-registered-target
2+
// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s
3+
4+
extern char ch;
5+
int test() {
6+
return ch;
7+
}
8+
9+
int test2() {
10+
extern char ch2;
11+
return ch2;
12+
}
13+
14+
extern int (*foo)(int);
15+
int test3() {
16+
return foo(0);
17+
}
18+
19+
// CHECK: distinct !DIGlobalVariable(name: "ch",{{.*}} type: ![[CHART:[0-9]+]], isLocal: false, isDefinition: false
20+
// CHECK: distinct !DIGlobalVariable(name: "ch2",{{.*}} type: ![[CHART]], isLocal: false, isDefinition: false
21+
// CHECK: ![[CHART]] = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
22+
23+
// CHECK: distinct !DIGlobalVariable(name: "foo",{{.*}} type: ![[FUNC:[0-9]+]], isLocal: false, isDefinition: false)
24+
// CHECK: ![[FUNC]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[SUB:[0-9]+]], size: 64)
25+
// CHECK: ![[SUB]] = !DISubroutineType(types: ![[TYPES:[0-9]+]])
26+
// CHECK: ![[TYPES]] = !{![[BASET:[0-9]+]], ![[BASET]]}
27+
// CHECK: ![[BASET]] = !DIBasicType(name: "int", size: 32, encoding: DW_ATE_signed)
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
// REQUIRES: bpf-registered-target
2+
// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s
3+
4+
extern char ch;
5+
extern char ch;
6+
int test() {
7+
return ch;
8+
}
9+
10+
// CHECK: distinct !DIGlobalVariable(name: "ch",{{.*}} type: ![[T:[0-9]+]], isLocal: false, isDefinition: false
11+
// CHECK-NOT: distinct !DIGlobalVariable(name: "ch"
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// REQUIRES: bpf-registered-target
2+
// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s
3+
4+
extern char ch;
5+
int test() {
6+
extern short sh;
7+
return ch + sh;
8+
}
9+
10+
extern char (*foo)(char);
11+
int test2() {
12+
return foo(0) + ch;
13+
}
14+
15+
// CHECK: distinct !DIGlobalVariable(name: "ch",{{.*}} type: ![[Tch:[0-9]+]], isLocal: false, isDefinition: false
16+
// CHECK: distinct !DIGlobalVariable(name: "sh",{{.*}} type: ![[Tsh:[0-9]+]], isLocal: false, isDefinition: false
17+
// CHECK: ![[Tsh]] = !DIBasicType(name: "short", size: 16, encoding: DW_ATE_signed)
18+
19+
// CHECK: distinct !DIGlobalVariable(name: "foo",{{.*}} type: ![[Tptr:[0-9]+]], isLocal: false, isDefinition: false
20+
// ![[Tptr]] = !DIDerivedType(tag: DW_TAG_pointer_type, baseType: ![[Tsub:[0-9]+]], size: 64)
21+
// ![[Tsub]] = !DISubroutineType(types: ![[Tproto:[0-9]+]])
22+
// ![[Tproto]] = !{![[Tch]], ![[Tch]]}
23+
// CHECK: ![[Tch]] = !DIBasicType(name: "char", size: 8, encoding: DW_ATE_signed_char)
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
// REQUIRES: bpf-registered-target
2+
// RUN: %clang -target bpf -emit-llvm -S -g %s -o - | FileCheck %s
3+
4+
extern char ch;
5+
int test() {
6+
return 0;
7+
}
8+
9+
int test2() {
10+
extern char ch2;
11+
return 0;
12+
}
13+
14+
extern int (*foo)(int);
15+
int test3() {
16+
return 0;
17+
}
18+
19+
int test4() {
20+
extern int (*foo2)(int);
21+
return 0;
22+
}
23+
24+
// CHECK-NOT: distinct !DIGlobalVariable(name: "ch"
25+
// CHECK-NOT: distinct !DIGlobalVariable(name: "ch2"
26+
// CHECK-NOT: distinct !DIGlobalVariable(name: "foo"
27+
// CHECK-NOT: distinct !DIGlobalVariable(name: "foo2"

llvm/include/llvm/IR/DIBuilder.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -583,7 +583,7 @@ namespace llvm {
583583
/// specified)
584584
DIGlobalVariableExpression *createGlobalVariableExpression(
585585
DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *File,
586-
unsigned LineNo, DIType *Ty, bool isLocalToUnit,
586+
unsigned LineNo, DIType *Ty, bool isLocalToUnit, bool isDefined = true,
587587
DIExpression *Expr = nullptr, MDNode *Decl = nullptr,
588588
MDTuple *templateParams = nullptr, uint32_t AlignInBits = 0);
589589

llvm/lib/IR/DIBuilder.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -640,13 +640,14 @@ static void checkGlobalVariableScope(DIScope *Context) {
640640

641641
DIGlobalVariableExpression *DIBuilder::createGlobalVariableExpression(
642642
DIScope *Context, StringRef Name, StringRef LinkageName, DIFile *F,
643-
unsigned LineNumber, DIType *Ty, bool isLocalToUnit, DIExpression *Expr,
643+
unsigned LineNumber, DIType *Ty, bool isLocalToUnit,
644+
bool isDefined, DIExpression *Expr,
644645
MDNode *Decl, MDTuple *templateParams, uint32_t AlignInBits) {
645646
checkGlobalVariableScope(Context);
646647

647648
auto *GV = DIGlobalVariable::getDistinct(
648649
VMContext, cast_or_null<DIScope>(Context), Name, LinkageName, F,
649-
LineNumber, Ty, isLocalToUnit, true, cast_or_null<DIDerivedType>(Decl),
650+
LineNumber, Ty, isLocalToUnit, isDefined, cast_or_null<DIDerivedType>(Decl),
650651
templateParams, AlignInBits);
651652
if (!Expr)
652653
Expr = createExpression();

llvm/lib/IR/DebugInfo.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1289,7 +1289,7 @@ LLVMMetadataRef LLVMDIBuilderCreateGlobalVariableExpression(
12891289
return wrap(unwrap(Builder)->createGlobalVariableExpression(
12901290
unwrapDI<DIScope>(Scope), {Name, NameLen}, {Linkage, LinkLen},
12911291
unwrapDI<DIFile>(File), LineNo, unwrapDI<DIType>(Ty), LocalToUnit,
1292-
unwrap<DIExpression>(Expr), unwrapDI<MDNode>(Decl),
1292+
true, unwrap<DIExpression>(Expr), unwrapDI<MDNode>(Decl),
12931293
nullptr, AlignInBits));
12941294
}
12951295

llvm/unittests/Transforms/Utils/CloningTest.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -764,7 +764,7 @@ class CloneModule : public ::testing::Test {
764764

765765
DBuilder.createGlobalVariableExpression(
766766
Subprogram, "unattached", "unattached", File, 1,
767-
DBuilder.createNullPtrType(), false, Expr);
767+
DBuilder.createNullPtrType(), false, true, Expr);
768768

769769
auto *Entry = BasicBlock::Create(C, "", F);
770770
IBuilder.SetInsertPoint(Entry);

0 commit comments

Comments
 (0)