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/IR/DebugInfoMetadata.h"
16#include "llvm/IR/GlobalVariable.h"
17#include "llvm/IR/Instruction.h"
18#include "llvm/IR/Instructions.h"
19#include "llvm/IR/Module.h"
20#include "llvm/IR/Type.h"
21#include "llvm/IR/User.h"
22#include "llvm/IR/Value.h"
23#include "llvm/Pass.h"
24#include "llvm/Transforms/Utils/BasicBlockUtils.h"
25
26#define DEBUG_TYPE "bpf-preserve-di-type"
27
28namespace llvm {
29constexpr StringRef BPFCoreSharedInfo::TypeIdAttr;
30} // namespace llvm
31
32using namespace llvm;
33
34namespace {
35
36class BPFPreserveDIType final : public ModulePass {
37  StringRef getPassName() const override {
38    return "BPF Preserve DebugInfo Type";
39  }
40
41  bool runOnModule(Module &M) override;
42
43public:
44  static char ID;
45  BPFPreserveDIType() : ModulePass(ID) {}
46
47private:
48  bool doTransformation(Module &M);
49};
50} // End anonymous namespace
51
52char BPFPreserveDIType::ID = 0;
53INITIALIZE_PASS(BPFPreserveDIType, DEBUG_TYPE, "preserve debuginfo type", false,
54                false)
55
56ModulePass *llvm::createBPFPreserveDIType() { return new BPFPreserveDIType(); }
57
58bool BPFPreserveDIType::runOnModule(Module &M) {
59  LLVM_DEBUG(dbgs() << "********** preserve debuginfo type **********\n");
60
61  // Bail out if no debug info.
62  if (M.debug_compile_units().empty())
63    return false;
64
65  return doTransformation(M);
66}
67
68bool BPFPreserveDIType::doTransformation(Module &M) {
69  std::vector<CallInst *> PreserveDITypeCalls;
70
71  for (auto &F : M) {
72    for (auto &BB : F) {
73      for (auto &I : BB) {
74        auto *Call = dyn_cast<CallInst>(&I);
75        if (!Call)
76          continue;
77
78        const auto *GV = dyn_cast<GlobalValue>(Call->getCalledOperand());
79        if (!GV)
80          continue;
81
82        if (GV->getName().startswith("llvm.bpf.btf.type.id")) {
83          if (!Call->getMetadata(LLVMContext::MD_preserve_access_index))
84            report_fatal_error(
85                "Missing metadata for llvm.bpf.btf.type.id intrinsic");
86          PreserveDITypeCalls.push_back(Call);
87        }
88      }
89    }
90  }
91
92  if (PreserveDITypeCalls.empty())
93    return false;
94
95  std::string BaseName = "llvm.btf_type_id.";
96  int Count = 0;
97  for (auto Call : PreserveDITypeCalls) {
98    const ConstantInt *Flag = dyn_cast<ConstantInt>(Call->getArgOperand(2));
99    assert(Flag);
100    uint64_t FlagValue = Flag->getValue().getZExtValue();
101
102    if (FlagValue >= BPFCoreSharedInfo::MAX_BTF_TYPE_ID_FLAG)
103      report_fatal_error("Incorrect flag for llvm.bpf.btf.type.id intrinsic");
104
105    uint32_t Reloc;
106    if (FlagValue == BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL_RELOC)
107      Reloc = BPFCoreSharedInfo::BTF_TYPE_ID_LOCAL;
108    else
109      Reloc = BPFCoreSharedInfo::BTF_TYPE_ID_REMOTE;
110
111    BasicBlock *BB = Call->getParent();
112    IntegerType *VarType = Type::getInt32Ty(BB->getContext());
113    std::string GVName = BaseName + std::to_string(Count) + "$" +
114        std::to_string(Reloc);
115    GlobalVariable *GV =
116        new GlobalVariable(M, VarType, false, GlobalVariable::ExternalLinkage,
117                           NULL, GVName);
118    GV->addAttribute(BPFCoreSharedInfo::TypeIdAttr);
119    MDNode *MD = Call->getMetadata(LLVMContext::MD_preserve_access_index);
120    GV->setMetadata(LLVMContext::MD_preserve_access_index, MD);
121
122    // Load the global variable which represents the type info.
123    auto *LDInst = new LoadInst(Type::getInt32Ty(BB->getContext()), GV, "",
124                                Call);
125    Call->replaceAllUsesWith(LDInst);
126    Call->eraseFromParent();
127    Count++;
128  }
129
130  return true;
131}
132