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>(Val: &I); |
52 | if (!Call) |
53 | continue; |
54 | |
55 | const auto *GV = dyn_cast<GlobalValue>(Val: Call->getCalledOperand()); |
56 | if (!GV) |
57 | continue; |
58 | |
59 | if (GV->getName().starts_with(Prefix: "llvm.bpf.btf.type.id" )) { |
60 | if (!Call->getMetadata(KindID: LLVMContext::MD_preserve_access_index)) |
61 | report_fatal_error( |
62 | reason: "Missing metadata for llvm.bpf.btf.type.id intrinsic" ); |
63 | PreserveDITypeCalls.push_back(x: 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>(Val: Call->getArgOperand(i: 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(reason: "Incorrect flag for llvm.bpf.btf.type.id intrinsic" ); |
80 | |
81 | MDNode *MD = Call->getMetadata(KindID: 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>(Val: MD); |
90 | while (auto *DTy = dyn_cast<DIDerivedType>(Val: 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>(Val: Ty)) |
100 | report_fatal_error( |
101 | reason: "SubroutineType not supported for BTF_TYPE_ID_REMOTE reloc" ); |
102 | else |
103 | report_fatal_error(reason: "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(C&: BB->getContext()); |
110 | std::string GVName = |
111 | BaseName + std::to_string(val: Count) + "$" + std::to_string(val: Reloc); |
112 | GlobalVariable *GV = new GlobalVariable( |
113 | *M, VarType, false, GlobalVariable::ExternalLinkage, nullptr, GVName); |
114 | GV->addAttribute(Kind: BPFCoreSharedInfo::TypeIdAttr); |
115 | GV->setMetadata(KindID: LLVMContext::MD_preserve_access_index, Node: MD); |
116 | |
117 | // Load the global variable which represents the type info. |
118 | auto *LDInst = new LoadInst(Type::getInt64Ty(C&: BB->getContext()), GV, "" , |
119 | Call->getIterator()); |
120 | Instruction *PassThroughInst = |
121 | BPFCoreSharedInfo::insertPassThrough(M, BB, Input: LDInst, Before: Call); |
122 | Call->replaceAllUsesWith(V: 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 | |