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
31namespace llvm {
32constexpr StringRef BPFCoreSharedInfo::TypeIdAttr;
33} // namespace llvm
34
35using namespace llvm;
36
37namespace {
38
39static 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>(Val: &I);
53 if (!Call)
54 continue;
55
56 const auto *GV = dyn_cast<GlobalValue>(Val: Call->getCalledOperand());
57 if (!GV)
58 continue;
59
60 if (GV->getName().starts_with(Prefix: "llvm.bpf.btf.type.id")) {
61 if (!Call->getMetadata(KindID: LLVMContext::MD_preserve_access_index))
62 report_fatal_error(
63 reason: "Missing metadata for llvm.bpf.btf.type.id intrinsic");
64 PreserveDITypeCalls.push_back(x: 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>(Val: Call->getArgOperand(i: 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(reason: "Incorrect flag for llvm.bpf.btf.type.id intrinsic");
81
82 MDNode *MD = Call->getMetadata(KindID: 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>(Val: MD);
91 while (auto *DTy = dyn_cast<DIDerivedType>(Val: 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>(Val: Ty))
101 report_fatal_error(
102 reason: "SubroutineType not supported for BTF_TYPE_ID_REMOTE reloc");
103 else
104 report_fatal_error(reason: "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(C&: BB->getContext());
111 std::string GVName =
112 BaseName + std::to_string(val: Count) + "$" + std::to_string(val: Reloc);
113 GlobalVariable *GV = new GlobalVariable(
114 *M, VarType, false, GlobalVariable::ExternalLinkage, nullptr, GVName);
115 GV->addAttribute(Kind: BPFCoreSharedInfo::TypeIdAttr);
116 GV->setMetadata(KindID: LLVMContext::MD_preserve_access_index, Node: MD);
117
118 // Load the global variable which represents the type info.
119 auto *LDInst = new LoadInst(Type::getInt64Ty(C&: BB->getContext()), GV, "",
120 Call->getIterator());
121 Instruction *PassThroughInst =
122 BPFCoreSharedInfo::insertPassThrough(M, BB, Input: LDInst, Before: Call);
123 Call->replaceAllUsesWith(V: PassThroughInst);
124 Call->eraseFromParent();
125 Count++;
126 }
127
128 return true;
129}
130} // End anonymous namespace
131
132PreservedAnalyses BPFPreserveDITypePass::run(Function &F,
133 FunctionAnalysisManager &AM) {
134 return BPFPreserveDITypeImpl(F) ? PreservedAnalyses::none()
135 : PreservedAnalyses::all();
136}
137