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/Type.h"
21 #include "llvm/IR/User.h"
22 #include "llvm/IR/Value.h"
23 #include "llvm/Pass.h"
24 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
25 
26 #define DEBUG_TYPE "bpf-preserve-di-type"
27 
28 namespace llvm {
29 constexpr StringRef BPFCoreSharedInfo::TypeIdAttr;
30 } // namespace llvm
31 
32 using namespace llvm;
33 
34 namespace {
35 
36 class BPFPreserveDIType final : public ModulePass {
37   StringRef getPassName() const override {
38     return "BPF Preserve DebugInfo Type";
39   }
40 
41   bool runOnModule(Module &M) override;
42 
43 public:
44   static char ID;
45   BPFPreserveDIType() : ModulePass(ID) {}
46 
47 private:
48   bool doTransformation(Module &M);
49 };
50 } // End anonymous namespace
51 
52 char BPFPreserveDIType::ID = 0;
53 INITIALIZE_PASS(BPFPreserveDIType, DEBUG_TYPE, "preserve debuginfo type", false,
54                 false)
55 
56 ModulePass *llvm::createBPFPreserveDIType() { return new BPFPreserveDIType(); }
57 
58 bool BPFPreserveDIType::runOnModule(Module &M) {
59   LLVM_DEBUG(dbgs() << "********** preserve debuginfo type **********\n");
60 
61   // Bail out if no debug info.
62   if (M.debug_compile_units().empty())
63     return false;
64 
65   return doTransformation(M);
66 }
67 
68 bool BPFPreserveDIType::doTransformation(Module &M) {
69   std::vector<CallInst *> PreserveDITypeCalls;
70 
71   for (auto &F : M) {
72     for (auto &BB : F) {
73       for (auto &I : BB) {
74         auto *Call = dyn_cast<CallInst>(&I);
75         if (!Call)
76           continue;
77 
78         const auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand());
79         if (!GV)
80           continue;
81 
82         if (GV->getName().startswith("llvm.bpf.btf.type.id")) {
83           if (!Call->getMetadata(LLVMContext::MD_preserve_access_index))
84             report_fatal_error(
85                 "Missing metadata for llvm.bpf.btf.type.id intrinsic");
86           PreserveDITypeCalls.push_back(Call);
87         }
88       }
89     }
90   }
91 
92   if (PreserveDITypeCalls.empty())
93     return false;
94 
95   std::string BaseName = "llvm.btf_type_id.";
96   int Count = 0;
97   for (auto Call : PreserveDITypeCalls) {
98     const ConstantInt *Flag = dyn_cast<ConstantInt>(Call->getArgOperand(2));
99     assert(Flag);
100     uint64_t FlagValue = Flag->getValue().getZExtValue();
101 
102     if (FlagValue >= BPFCoreSharedInfo::MAX_BTF_TYPE_ID_FLAG)
103       report_fatal_error("Incorrect flag for llvm.bpf.btf.type.id intrinsic");
104 
105     uint32_t Reloc;
106     if (FlagValue == BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL_RELOC)
107       Reloc = BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL;
108     else
109       Reloc = BPFCoreSharedInfo::BTF_TYPE_ID_REMOTE;
110 
111     BasicBlock *BB = Call->getParent();
112     IntegerType *VarType = Type::getInt32Ty(BB->getContext());
113     std::string GVName = BaseName + std::to_string(Count) + "$" +
114         std::to_string(Reloc);
115     GlobalVariable *GV =
116         new GlobalVariable(M, VarType, false, GlobalVariable::ExternalLinkage,
117                            NULL, GVName);
118     GV->addAttribute(BPFCoreSharedInfo::TypeIdAttr);
119     MDNode *MD = Call->getMetadata(LLVMContext::MD_preserve_access_index);
120     GV->setMetadata(LLVMContext::MD_preserve_access_index, MD);
121 
122     // Load the global variable which represents the type info.
123     auto *LDInst = new LoadInst(Type::getInt32Ty(BB->getContext()), GV, "",
124                                 Call);
125     Call->replaceAllUsesWith(LDInst);
126     Call->eraseFromParent();
127     Count++;
128   }
129 
130   return true;
131 }
132