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 | |
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>(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 | |
132 | PreservedAnalyses BPFPreserveDITypePass::run(Function &F, |
133 | FunctionAnalysisManager &AM) { |
134 | return BPFPreserveDITypeImpl(F) ? PreservedAnalyses::none() |
135 | : PreservedAnalyses::all(); |
136 | } |
137 | |