xref: /freebsd/contrib/llvm-project/llvm/lib/Target/BPF/BPFPreserveDIType.cpp (revision 0fca6ea1d4eea4c934cfff25ac9ee8ad6fe95583)
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/BinaryFormat/Dwarf.h"
16 #include "llvm/DebugInfo/BTF/BTF.h"
17 #include "llvm/IR/DebugInfoMetadata.h"
18 #include "llvm/IR/GlobalVariable.h"
19 #include "llvm/IR/Instruction.h"
20 #include "llvm/IR/Instructions.h"
21 #include "llvm/IR/Module.h"
22 #include "llvm/IR/PassManager.h"
23 #include "llvm/IR/Type.h"
24 #include "llvm/IR/User.h"
25 #include "llvm/IR/Value.h"
26 #include "llvm/Pass.h"
27 #include "llvm/Transforms/Utils/BasicBlockUtils.h"
28 
29 #define DEBUG_TYPE "bpf-preserve-di-type"
30 
31 namespace llvm {
32 constexpr StringRef BPFCoreSharedInfo::TypeIdAttr;
33 } // namespace llvm
34 
35 using namespace llvm;
36 
37 namespace {
38 
BPFPreserveDITypeImpl(Function & F)39 static bool BPFPreserveDITypeImpl(Function &F) {
40   LLVM_DEBUG(dbgs() << "********** preserve debuginfo type **********\n");
41 
42   Module *M = F.getParent();
43 
44   // Bail out if no debug info.
45   if (M->debug_compile_units().empty())
46     return false;
47 
48   std::vector<CallInst *> PreserveDITypeCalls;
49 
50   for (auto &BB : F) {
51     for (auto &I : BB) {
52       auto *Call = dyn_cast<CallInst>(&I);
53       if (!Call)
54         continue;
55 
56       const auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand());
57       if (!GV)
58         continue;
59 
60       if (GV->getName().starts_with("llvm.bpf.btf.type.id")) {
61         if (!Call->getMetadata(LLVMContext::MD_preserve_access_index))
62           report_fatal_error(
63               "Missing metadata for llvm.bpf.btf.type.id intrinsic");
64         PreserveDITypeCalls.push_back(Call);
65       }
66     }
67   }
68 
69   if (PreserveDITypeCalls.empty())
70     return false;
71 
72   std::string BaseName = "llvm.btf_type_id.";
73   static int Count = 0;
74   for (auto *Call : PreserveDITypeCalls) {
75     const ConstantInt *Flag = dyn_cast<ConstantInt>(Call->getArgOperand(1));
76     assert(Flag);
77     uint64_t FlagValue = Flag->getValue().getZExtValue();
78 
79     if (FlagValue >= BPFCoreSharedInfo::MAX_BTF_TYPE_ID_FLAG)
80       report_fatal_error("Incorrect flag for llvm.bpf.btf.type.id intrinsic");
81 
82     MDNode *MD = Call->getMetadata(LLVMContext::MD_preserve_access_index);
83 
84     uint32_t Reloc;
85     if (FlagValue == BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL_RELOC) {
86       Reloc = BTF::BTF_TYPE_ID_LOCAL;
87     } else {
88       Reloc = BTF::BTF_TYPE_ID_REMOTE;
89     }
90     DIType *Ty = cast<DIType>(MD);
91     while (auto *DTy = dyn_cast<DIDerivedType>(Ty)) {
92       unsigned Tag = DTy->getTag();
93       if (Tag != dwarf::DW_TAG_const_type && Tag != dwarf::DW_TAG_volatile_type)
94         break;
95       Ty = DTy->getBaseType();
96     }
97 
98     if (Reloc == BTF::BTF_TYPE_ID_REMOTE) {
99       if (Ty->getName().empty()) {
100         if (isa<DISubroutineType>(Ty))
101           report_fatal_error(
102               "SubroutineType not supported for BTF_TYPE_ID_REMOTE reloc");
103         else
104           report_fatal_error("Empty type name for BTF_TYPE_ID_REMOTE reloc");
105       }
106     }
107     MD = Ty;
108 
109     BasicBlock *BB = Call->getParent();
110     IntegerType *VarType = Type::getInt64Ty(BB->getContext());
111     std::string GVName =
112         BaseName + std::to_string(Count) + "$" + std::to_string(Reloc);
113     GlobalVariable *GV = new GlobalVariable(
114         *M, VarType, false, GlobalVariable::ExternalLinkage, nullptr, GVName);
115     GV->addAttribute(BPFCoreSharedInfo::TypeIdAttr);
116     GV->setMetadata(LLVMContext::MD_preserve_access_index, MD);
117 
118     // Load the global variable which represents the type info.
119     auto *LDInst = new LoadInst(Type::getInt64Ty(BB->getContext()), GV, "",
120                                 Call->getIterator());
121     Instruction *PassThroughInst =
122         BPFCoreSharedInfo::insertPassThrough(M, BB, LDInst, Call);
123     Call->replaceAllUsesWith(PassThroughInst);
124     Call->eraseFromParent();
125     Count++;
126   }
127 
128   return true;
129 }
130 } // End anonymous namespace
131 
run(Function & F,FunctionAnalysisManager & AM)132 PreservedAnalyses BPFPreserveDITypePass::run(Function &F,
133                                              FunctionAnalysisManager &AM) {
134   return BPFPreserveDITypeImpl(F) ? PreservedAnalyses::none()
135                                   : PreservedAnalyses::all();
136 }
137