0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012 #include "clang/Basic/Version.h"
0013 #include "clang/CodeGen/CodeGenAction.h"
0014 #include "clang/Frontend/CompilerInvocation.h"
0015 #include "clang/Frontend/CompilerInstance.h"
0016 #include "clang/Frontend/TextDiagnosticPrinter.h"
0017 #include "clang/Tooling/Tooling.h"
0018 #include "llvm/IR/LegacyPassManager.h"
0019 #include "llvm/IR/Module.h"
0020 #include "llvm/Option/Option.h"
0021 #include "llvm/Support/FileSystem.h"
0022 #include "llvm/Support/ManagedStatic.h"
0023 #if CLANG_VERSION_MAJOR >= 14
0024 #include "llvm/MC/TargetRegistry.h"
0025 #else
0026 #include "llvm/Support/TargetRegistry.h"
0027 #endif
0028 #include "llvm/Support/TargetSelect.h"
0029 #include "llvm/Target/TargetMachine.h"
0030 #include "llvm/Target/TargetOptions.h"
0031 #include <memory>
0032
0033 #include "clang.h"
0034 #include "clang-c.h"
0035
0036 namespace perf {
0037
0038 static std::unique_ptr<llvm::LLVMContext> LLVMCtx;
0039
0040 using namespace clang;
0041
0042 static CompilerInvocation *
0043 createCompilerInvocation(llvm::opt::ArgStringList CFlags, StringRef& Path,
0044 DiagnosticsEngine& Diags)
0045 {
0046 llvm::opt::ArgStringList CCArgs {
0047 "-cc1",
0048 "-triple", "bpf-pc-linux",
0049 "-fsyntax-only",
0050 "-O2",
0051 "-nostdsysteminc",
0052 "-nobuiltininc",
0053 "-vectorize-loops",
0054 "-vectorize-slp",
0055 "-Wno-unused-value",
0056 "-Wno-pointer-sign",
0057 "-x", "c"};
0058
0059 CCArgs.append(CFlags.begin(), CFlags.end());
0060 CompilerInvocation *CI = tooling::newInvocation(&Diags, CCArgs
0061 #if CLANG_VERSION_MAJOR >= 11
0062 ,nullptr
0063 #endif
0064 );
0065
0066 FrontendOptions& Opts = CI->getFrontendOpts();
0067 Opts.Inputs.clear();
0068 Opts.Inputs.emplace_back(Path,
0069 FrontendOptions::getInputKindForExtension("c"));
0070 return CI;
0071 }
0072
0073 static std::unique_ptr<llvm::Module>
0074 getModuleFromSource(llvm::opt::ArgStringList CFlags,
0075 StringRef Path, IntrusiveRefCntPtr<vfs::FileSystem> VFS)
0076 {
0077 CompilerInstance Clang;
0078 Clang.createDiagnostics();
0079
0080 #if CLANG_VERSION_MAJOR < 9
0081 Clang.setVirtualFileSystem(&*VFS);
0082 #else
0083 Clang.createFileManager(&*VFS);
0084 #endif
0085
0086 #if CLANG_VERSION_MAJOR < 4
0087 IntrusiveRefCntPtr<CompilerInvocation> CI =
0088 createCompilerInvocation(std::move(CFlags), Path,
0089 Clang.getDiagnostics());
0090 Clang.setInvocation(&*CI);
0091 #else
0092 std::shared_ptr<CompilerInvocation> CI(
0093 createCompilerInvocation(std::move(CFlags), Path,
0094 Clang.getDiagnostics()));
0095 Clang.setInvocation(CI);
0096 #endif
0097
0098 std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction(&*LLVMCtx));
0099 if (!Clang.ExecuteAction(*Act))
0100 return std::unique_ptr<llvm::Module>(nullptr);
0101
0102 return Act->takeModule();
0103 }
0104
0105 std::unique_ptr<llvm::Module>
0106 getModuleFromSource(llvm::opt::ArgStringList CFlags,
0107 StringRef Name, StringRef Content)
0108 {
0109 using namespace vfs;
0110
0111 llvm::IntrusiveRefCntPtr<OverlayFileSystem> OverlayFS(
0112 new OverlayFileSystem(getRealFileSystem()));
0113 llvm::IntrusiveRefCntPtr<InMemoryFileSystem> MemFS(
0114 new InMemoryFileSystem(true));
0115
0116
0117
0118
0119
0120 OverlayFS->pushOverlay(MemFS);
0121 MemFS->addFile(Twine(Name), 0, llvm::MemoryBuffer::getMemBuffer(Content));
0122
0123 return getModuleFromSource(std::move(CFlags), Name, OverlayFS);
0124 }
0125
0126 std::unique_ptr<llvm::Module>
0127 getModuleFromSource(llvm::opt::ArgStringList CFlags, StringRef Path)
0128 {
0129 IntrusiveRefCntPtr<vfs::FileSystem> VFS(vfs::getRealFileSystem());
0130 return getModuleFromSource(std::move(CFlags), Path, VFS);
0131 }
0132
0133 std::unique_ptr<llvm::SmallVectorImpl<char>>
0134 getBPFObjectFromModule(llvm::Module *Module)
0135 {
0136 using namespace llvm;
0137
0138 std::string TargetTriple("bpf-pc-linux");
0139 std::string Error;
0140 const Target* Target = TargetRegistry::lookupTarget(TargetTriple, Error);
0141 if (!Target) {
0142 llvm::errs() << Error;
0143 return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);
0144 }
0145
0146 llvm::TargetOptions Opt;
0147 TargetMachine *TargetMachine =
0148 Target->createTargetMachine(TargetTriple,
0149 "generic", "",
0150 Opt, Reloc::Static);
0151
0152 Module->setDataLayout(TargetMachine->createDataLayout());
0153 Module->setTargetTriple(TargetTriple);
0154
0155 std::unique_ptr<SmallVectorImpl<char>> Buffer(new SmallVector<char, 0>());
0156 raw_svector_ostream ostream(*Buffer);
0157
0158 legacy::PassManager PM;
0159 bool NotAdded;
0160 NotAdded = TargetMachine->addPassesToEmitFile(PM, ostream
0161 #if CLANG_VERSION_MAJOR >= 7
0162 , nullptr
0163 #endif
0164 #if CLANG_VERSION_MAJOR < 10
0165 , TargetMachine::CGFT_ObjectFile
0166 #else
0167 , llvm::CGFT_ObjectFile
0168 #endif
0169 );
0170 if (NotAdded) {
0171 llvm::errs() << "TargetMachine can't emit a file of this type\n";
0172 return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);
0173 }
0174 PM.run(*Module);
0175
0176 return Buffer;
0177 }
0178
0179 }
0180
0181 extern "C" {
0182 void perf_clang__init(void)
0183 {
0184 perf::LLVMCtx.reset(new llvm::LLVMContext());
0185 LLVMInitializeBPFTargetInfo();
0186 LLVMInitializeBPFTarget();
0187 LLVMInitializeBPFTargetMC();
0188 LLVMInitializeBPFAsmPrinter();
0189 }
0190
0191 void perf_clang__cleanup(void)
0192 {
0193 perf::LLVMCtx.reset(nullptr);
0194 llvm::llvm_shutdown();
0195 }
0196
0197 int perf_clang__compile_bpf(const char *filename,
0198 void **p_obj_buf,
0199 size_t *p_obj_buf_sz)
0200 {
0201 using namespace perf;
0202
0203 if (!p_obj_buf || !p_obj_buf_sz)
0204 return -EINVAL;
0205
0206 llvm::opt::ArgStringList CFlags;
0207 auto M = getModuleFromSource(std::move(CFlags), filename);
0208 if (!M)
0209 return -EINVAL;
0210 auto O = getBPFObjectFromModule(&*M);
0211 if (!O)
0212 return -EINVAL;
0213
0214 size_t size = O->size_in_bytes();
0215 void *buffer;
0216
0217 buffer = malloc(size);
0218 if (!buffer)
0219 return -ENOMEM;
0220 memcpy(buffer, O->data(), size);
0221 *p_obj_buf = buffer;
0222 *p_obj_buf_sz = size;
0223 return 0;
0224 }
0225 }