1 //===----------- BPFPreserveDIType.cpp - Preserve DebugInfo Types ---------===//
2 //
3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4 // See https://llvm.org/LICENSE.txt for license information.
5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6 //
7 //===----------------------------------------------------------------------===//
8 //
9 // Preserve Debuginfo types encoded in __builtin_btf_type_id() metadata.
10 //
11 //===----------------------------------------------------------------------===//
12 
13 #include "BPF.h"
14 #include "BPFCORE.h"
15 #include "llvm/IR/DebugInfoMetadata.h"
16 #include "llvm/IR/GlobalVariable.h"
17 #include "llvm/IR/Instruction.h"
18 #include "llvm/IR/Instructions.h"
19 #include "llvm/IR/Module.h"
20 #include "llvm/IR/PassManager.h"
21 #include "llvm/IR/Type.h"
22 #include "llvm/IR/User.h"
23 #include "llvm/IR/Value.h"
24 #include "llvm/Pass.h"
25 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
26 
27 #define DEBUG_TYPE "bpf-preserve-di-type"
28 
29 namespace llvm {
30 constexpr StringRef BPFCoreSharedInfo::TypeIdAttr;
31 } // namespace llvm
32 
33 using namespace llvm;
34 
35 namespace {
36 
BPFPreserveDITypeImpl(Function & F)37 static bool BPFPreserveDITypeImpl(Function &F) {
38   LLVM_DEBUG(dbgs() << "********** preserve debuginfo type **********\n");
39 
40   Module *M = F.getParent();
41 
42   // Bail out if no debug info.
43   if (M->debug_compile_units().empty())
44     return false;
45 
46   std::vector<CallInst *> PreserveDITypeCalls;
47 
48   for (auto &BB : F) {
49     for (auto &I : BB) {
50       auto *Call = dyn_cast<CallInst>(&I);
51       if (!Call)
52         continue;
53 
54       const auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand());
55       if (!GV)
56         continue;
57 
58       if (GV->getName().startswith("llvm.bpf.btf.type.id")) {
59         if (!Call->getMetadata(LLVMContext::MD_preserve_access_index))
60           report_fatal_error(
61               "Missing metadata for llvm.bpf.btf.type.id intrinsic");
62         PreserveDITypeCalls.push_back(Call);
63       }
64     }
65   }
66 
67   if (PreserveDITypeCalls.empty())
68     return false;
69 
70   std::string BaseName = "llvm.btf_type_id.";
71   static int Count = 0;
72   for (auto Call : PreserveDITypeCalls) {
73     const ConstantInt *Flag = dyn_cast<ConstantInt>(Call->getArgOperand(1));
74     assert(Flag);
75     uint64_t FlagValue = Flag->getValue().getZExtValue();
76 
77     if (FlagValue >= BPFCoreSharedInfo::MAX_BTF_TYPE_ID_FLAG)
78       report_fatal_error("Incorrect flag for llvm.bpf.btf.type.id intrinsic");
79 
80     MDNode *MD = Call->getMetadata(LLVMContext::MD_preserve_access_index);
81 
82     uint32_t Reloc;
83     if (FlagValue == BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL_RELOC) {
84       Reloc = BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL;
85     } else {
86       Reloc = BPFCoreSharedInfo::BTF_TYPE_ID_REMOTE;
87       DIType *Ty = cast<DIType>(MD);
88       if (Ty->getName().empty())
89         report_fatal_error("Empty type name for BTF_TYPE_ID_REMOTE reloc");
90     }
91 
92     BasicBlock *BB = Call->getParent();
93     IntegerType *VarType = Type::getInt64Ty(BB->getContext());
94     std::string GVName = BaseName + std::to_string(Count) + "$" +
95         std::to_string(Reloc);
96     GlobalVariable *GV = new GlobalVariable(
97         *M, VarType, false, GlobalVariable::ExternalLinkage, NULL, GVName);
98     GV->addAttribute(BPFCoreSharedInfo::TypeIdAttr);
99     GV->setMetadata(LLVMContext::MD_preserve_access_index, MD);
100 
101     // Load the global variable which represents the type info.
102     auto *LDInst =
103         new LoadInst(Type::getInt64Ty(BB->getContext()), GV, "", Call);
104     Instruction *PassThroughInst =
105         BPFCoreSharedInfo::insertPassThrough(M, BB, LDInst, Call);
106     Call->replaceAllUsesWith(PassThroughInst);
107     Call->eraseFromParent();
108     Count++;
109   }
110 
111   return true;
112 }
113 
114 class BPFPreserveDIType final : public FunctionPass {
115   bool runOnFunction(Function &F) override;
116 
117 public:
118   static char ID;
BPFPreserveDIType()119   BPFPreserveDIType() : FunctionPass(ID) {}
120 };
121 } // End anonymous namespace
122 
123 char BPFPreserveDIType::ID = 0;
124 INITIALIZE_PASS(BPFPreserveDIType, DEBUG_TYPE, "BPF Preserve Debuginfo Type",
125                 false, false)
126 
createBPFPreserveDIType()127 FunctionPass *llvm::createBPFPreserveDIType() {
128   return new BPFPreserveDIType();
129 }
130 
runOnFunction(Function & F)131 bool BPFPreserveDIType::runOnFunction(Function &F) {
132   return BPFPreserveDITypeImpl(F);
133 }
134 
run(Function & F,FunctionAnalysisManager & AM)135 PreservedAnalyses BPFPreserveDITypePass::run(Function &F,
136                                              FunctionAnalysisManager &AM) {
137   return BPFPreserveDITypeImpl(F) ? PreservedAnalyses::none()
138                                   : PreservedAnalyses::all();
139 }
140