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