cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

clang.cpp (5950B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * llvm C frontend for perf. Support dynamically compile C file
      4 *
      5 * Inspired by clang example code:
      6 * http://llvm.org/svn/llvm-project/cfe/trunk/examples/clang-interpreter/main.cpp
      7 *
      8 * Copyright (C) 2016 Wang Nan <wangnan0@huawei.com>
      9 * Copyright (C) 2016 Huawei Inc.
     10 */
     11
     12#include "clang/Basic/Version.h"
     13#include "clang/CodeGen/CodeGenAction.h"
     14#include "clang/Frontend/CompilerInvocation.h"
     15#include "clang/Frontend/CompilerInstance.h"
     16#include "clang/Frontend/TextDiagnosticPrinter.h"
     17#include "clang/Tooling/Tooling.h"
     18#include "llvm/IR/LegacyPassManager.h"
     19#include "llvm/IR/Module.h"
     20#include "llvm/Option/Option.h"
     21#include "llvm/Support/FileSystem.h"
     22#include "llvm/Support/ManagedStatic.h"
     23#if CLANG_VERSION_MAJOR >= 14
     24#include "llvm/MC/TargetRegistry.h"
     25#else
     26#include "llvm/Support/TargetRegistry.h"
     27#endif
     28#include "llvm/Support/TargetSelect.h"
     29#include "llvm/Target/TargetMachine.h"
     30#include "llvm/Target/TargetOptions.h"
     31#include <memory>
     32
     33#include "clang.h"
     34#include "clang-c.h"
     35
     36namespace perf {
     37
     38static std::unique_ptr<llvm::LLVMContext> LLVMCtx;
     39
     40using namespace clang;
     41
     42static CompilerInvocation *
     43createCompilerInvocation(llvm::opt::ArgStringList CFlags, StringRef& Path,
     44			 DiagnosticsEngine& Diags)
     45{
     46	llvm::opt::ArgStringList CCArgs {
     47		"-cc1",
     48		"-triple", "bpf-pc-linux",
     49		"-fsyntax-only",
     50		"-O2",
     51		"-nostdsysteminc",
     52		"-nobuiltininc",
     53		"-vectorize-loops",
     54		"-vectorize-slp",
     55		"-Wno-unused-value",
     56		"-Wno-pointer-sign",
     57		"-x", "c"};
     58
     59	CCArgs.append(CFlags.begin(), CFlags.end());
     60	CompilerInvocation *CI = tooling::newInvocation(&Diags, CCArgs
     61#if CLANG_VERSION_MAJOR >= 11
     62                                                        ,/*BinaryName=*/nullptr
     63#endif
     64                                                        );
     65
     66	FrontendOptions& Opts = CI->getFrontendOpts();
     67	Opts.Inputs.clear();
     68	Opts.Inputs.emplace_back(Path,
     69			FrontendOptions::getInputKindForExtension("c"));
     70	return CI;
     71}
     72
     73static std::unique_ptr<llvm::Module>
     74getModuleFromSource(llvm::opt::ArgStringList CFlags,
     75		    StringRef Path, IntrusiveRefCntPtr<vfs::FileSystem> VFS)
     76{
     77	CompilerInstance Clang;
     78	Clang.createDiagnostics();
     79
     80#if CLANG_VERSION_MAJOR < 9
     81	Clang.setVirtualFileSystem(&*VFS);
     82#else
     83	Clang.createFileManager(&*VFS);
     84#endif
     85
     86#if CLANG_VERSION_MAJOR < 4
     87	IntrusiveRefCntPtr<CompilerInvocation> CI =
     88		createCompilerInvocation(std::move(CFlags), Path,
     89					 Clang.getDiagnostics());
     90	Clang.setInvocation(&*CI);
     91#else
     92	std::shared_ptr<CompilerInvocation> CI(
     93		createCompilerInvocation(std::move(CFlags), Path,
     94					 Clang.getDiagnostics()));
     95	Clang.setInvocation(CI);
     96#endif
     97
     98	std::unique_ptr<CodeGenAction> Act(new EmitLLVMOnlyAction(&*LLVMCtx));
     99	if (!Clang.ExecuteAction(*Act))
    100		return std::unique_ptr<llvm::Module>(nullptr);
    101
    102	return Act->takeModule();
    103}
    104
    105std::unique_ptr<llvm::Module>
    106getModuleFromSource(llvm::opt::ArgStringList CFlags,
    107		    StringRef Name, StringRef Content)
    108{
    109	using namespace vfs;
    110
    111	llvm::IntrusiveRefCntPtr<OverlayFileSystem> OverlayFS(
    112			new OverlayFileSystem(getRealFileSystem()));
    113	llvm::IntrusiveRefCntPtr<InMemoryFileSystem> MemFS(
    114			new InMemoryFileSystem(true));
    115
    116	/*
    117	 * pushOverlay helps setting working dir for MemFS. Must call
    118	 * before addFile.
    119	 */
    120	OverlayFS->pushOverlay(MemFS);
    121	MemFS->addFile(Twine(Name), 0, llvm::MemoryBuffer::getMemBuffer(Content));
    122
    123	return getModuleFromSource(std::move(CFlags), Name, OverlayFS);
    124}
    125
    126std::unique_ptr<llvm::Module>
    127getModuleFromSource(llvm::opt::ArgStringList CFlags, StringRef Path)
    128{
    129	IntrusiveRefCntPtr<vfs::FileSystem> VFS(vfs::getRealFileSystem());
    130	return getModuleFromSource(std::move(CFlags), Path, VFS);
    131}
    132
    133std::unique_ptr<llvm::SmallVectorImpl<char>>
    134getBPFObjectFromModule(llvm::Module *Module)
    135{
    136	using namespace llvm;
    137
    138	std::string TargetTriple("bpf-pc-linux");
    139	std::string Error;
    140	const Target* Target = TargetRegistry::lookupTarget(TargetTriple, Error);
    141	if (!Target) {
    142		llvm::errs() << Error;
    143		return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);
    144	}
    145
    146	llvm::TargetOptions Opt;
    147	TargetMachine *TargetMachine =
    148		Target->createTargetMachine(TargetTriple,
    149					    "generic", "",
    150					    Opt, Reloc::Static);
    151
    152	Module->setDataLayout(TargetMachine->createDataLayout());
    153	Module->setTargetTriple(TargetTriple);
    154
    155	std::unique_ptr<SmallVectorImpl<char>> Buffer(new SmallVector<char, 0>());
    156	raw_svector_ostream ostream(*Buffer);
    157
    158	legacy::PassManager PM;
    159	bool NotAdded;
    160	NotAdded = TargetMachine->addPassesToEmitFile(PM, ostream
    161#if CLANG_VERSION_MAJOR >= 7
    162                                                      , /*DwoOut=*/nullptr
    163#endif
    164#if CLANG_VERSION_MAJOR < 10
    165                                                      , TargetMachine::CGFT_ObjectFile
    166#else
    167                                                      , llvm::CGFT_ObjectFile
    168#endif
    169                                                      );
    170	if (NotAdded) {
    171		llvm::errs() << "TargetMachine can't emit a file of this type\n";
    172		return std::unique_ptr<llvm::SmallVectorImpl<char>>(nullptr);
    173	}
    174	PM.run(*Module);
    175
    176	return Buffer;
    177}
    178
    179}
    180
    181extern "C" {
    182void perf_clang__init(void)
    183{
    184	perf::LLVMCtx.reset(new llvm::LLVMContext());
    185	LLVMInitializeBPFTargetInfo();
    186	LLVMInitializeBPFTarget();
    187	LLVMInitializeBPFTargetMC();
    188	LLVMInitializeBPFAsmPrinter();
    189}
    190
    191void perf_clang__cleanup(void)
    192{
    193	perf::LLVMCtx.reset(nullptr);
    194	llvm::llvm_shutdown();
    195}
    196
    197int perf_clang__compile_bpf(const char *filename,
    198			    void **p_obj_buf,
    199			    size_t *p_obj_buf_sz)
    200{
    201	using namespace perf;
    202
    203	if (!p_obj_buf || !p_obj_buf_sz)
    204		return -EINVAL;
    205
    206	llvm::opt::ArgStringList CFlags;
    207	auto M = getModuleFromSource(std::move(CFlags), filename);
    208	if (!M)
    209		return  -EINVAL;
    210	auto O = getBPFObjectFromModule(&*M);
    211	if (!O)
    212		return -EINVAL;
    213
    214	size_t size = O->size_in_bytes();
    215	void *buffer;
    216
    217	buffer = malloc(size);
    218	if (!buffer)
    219		return -ENOMEM;
    220	memcpy(buffer, O->data(), size);
    221	*p_obj_buf = buffer;
    222	*p_obj_buf_sz = size;
    223	return 0;
    224}
    225}