Commit e01c993a authored by yonghong-song's avatar yonghong-song Committed by GitHub

Merge pull request #1569 from joelagnel/bcc-cross-compile

BCC cross compilation support
parents 3613ff82 10869523
...@@ -572,7 +572,37 @@ struct pt_regs; ...@@ -572,7 +572,37 @@ struct pt_regs;
int bpf_usdt_readarg(int argc, struct pt_regs *ctx, void *arg) asm("llvm.bpf.extra"); int bpf_usdt_readarg(int argc, struct pt_regs *ctx, void *arg) asm("llvm.bpf.extra");
int bpf_usdt_readarg_p(int argc, struct pt_regs *ctx, void *buf, u64 len) asm("llvm.bpf.extra"); int bpf_usdt_readarg_p(int argc, struct pt_regs *ctx, void *buf, u64 len) asm("llvm.bpf.extra");
#ifdef __powerpc__ /* Scan the ARCH passed in from ARCH env variable (see kbuild_helper.cc) */
#if defined(__TARGET_ARCH_x86)
#define bpf_target_x86
#define bpf_target_defined
#elif defined(__TARGET_ARCH_s930x)
#define bpf_target_s930x
#define bpf_target_defined
#elif defined(__TARGET_ARCH_arm64)
#define bpf_target_arm64
#define bpf_target_defined
#elif defined(__TARGET_ARCH_powerpc)
#define bpf_target_powerpc
#define bpf_target_defined
#else
#undef bpf_target_defined
#endif
/* Fall back to what the compiler says */
#ifndef bpf_target_defined
#if defined(__x86_64__)
#define bpf_target_x86
#elif defined(__s390x__)
#define bpf_target_s930x
#elif defined(__aarch64__)
#define bpf_target_arm64
#elif defined(__powerpc__)
#define bpf_target_powerpc
#endif
#endif
#if defined(bpf_target_powerpc)
#define PT_REGS_PARM1(ctx) ((ctx)->gpr[3]) #define PT_REGS_PARM1(ctx) ((ctx)->gpr[3])
#define PT_REGS_PARM2(ctx) ((ctx)->gpr[4]) #define PT_REGS_PARM2(ctx) ((ctx)->gpr[4])
#define PT_REGS_PARM3(ctx) ((ctx)->gpr[5]) #define PT_REGS_PARM3(ctx) ((ctx)->gpr[5])
...@@ -582,7 +612,7 @@ int bpf_usdt_readarg_p(int argc, struct pt_regs *ctx, void *buf, u64 len) asm("l ...@@ -582,7 +612,7 @@ int bpf_usdt_readarg_p(int argc, struct pt_regs *ctx, void *buf, u64 len) asm("l
#define PT_REGS_RC(ctx) ((ctx)->gpr[3]) #define PT_REGS_RC(ctx) ((ctx)->gpr[3])
#define PT_REGS_IP(ctx) ((ctx)->nip) #define PT_REGS_IP(ctx) ((ctx)->nip)
#define PT_REGS_SP(ctx) ((ctx)->gpr[1]) #define PT_REGS_SP(ctx) ((ctx)->gpr[1])
#elif defined(__s390x__) #elif defined(bpf_target_s930x)
#define PT_REGS_PARM1(x) ((x)->gprs[2]) #define PT_REGS_PARM1(x) ((x)->gprs[2])
#define PT_REGS_PARM2(x) ((x)->gprs[3]) #define PT_REGS_PARM2(x) ((x)->gprs[3])
#define PT_REGS_PARM3(x) ((x)->gprs[4]) #define PT_REGS_PARM3(x) ((x)->gprs[4])
...@@ -593,7 +623,7 @@ int bpf_usdt_readarg_p(int argc, struct pt_regs *ctx, void *buf, u64 len) asm("l ...@@ -593,7 +623,7 @@ int bpf_usdt_readarg_p(int argc, struct pt_regs *ctx, void *buf, u64 len) asm("l
#define PT_REGS_RC(x) ((x)->gprs[2]) #define PT_REGS_RC(x) ((x)->gprs[2])
#define PT_REGS_SP(x) ((x)->gprs[15]) #define PT_REGS_SP(x) ((x)->gprs[15])
#define PT_REGS_IP(x) ((x)->psw.addr) #define PT_REGS_IP(x) ((x)->psw.addr)
#elif defined(__x86_64__) #elif defined(bpf_target_x86)
#define PT_REGS_PARM1(ctx) ((ctx)->di) #define PT_REGS_PARM1(ctx) ((ctx)->di)
#define PT_REGS_PARM2(ctx) ((ctx)->si) #define PT_REGS_PARM2(ctx) ((ctx)->si)
#define PT_REGS_PARM3(ctx) ((ctx)->dx) #define PT_REGS_PARM3(ctx) ((ctx)->dx)
...@@ -604,7 +634,7 @@ int bpf_usdt_readarg_p(int argc, struct pt_regs *ctx, void *buf, u64 len) asm("l ...@@ -604,7 +634,7 @@ int bpf_usdt_readarg_p(int argc, struct pt_regs *ctx, void *buf, u64 len) asm("l
#define PT_REGS_RC(ctx) ((ctx)->ax) #define PT_REGS_RC(ctx) ((ctx)->ax)
#define PT_REGS_IP(ctx) ((ctx)->ip) #define PT_REGS_IP(ctx) ((ctx)->ip)
#define PT_REGS_SP(ctx) ((ctx)->sp) #define PT_REGS_SP(ctx) ((ctx)->sp)
#elif defined(__aarch64__) #elif defined(bpf_target_arm64)
#define PT_REGS_PARM1(x) ((x)->regs[0]) #define PT_REGS_PARM1(x) ((x)->regs[0])
#define PT_REGS_PARM2(x) ((x)->regs[1]) #define PT_REGS_PARM2(x) ((x)->regs[1])
#define PT_REGS_PARM3(x) ((x)->regs[2]) #define PT_REGS_PARM3(x) ((x)->regs[2])
......
/*
* Copyright (c) 2018 Google, Inc.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
#include <string.h>
#include <stdlib.h>
typedef enum {
BCC_ARCH_PPC,
BCC_ARCH_PPC_LE,
BCC_ARCH_S390X,
BCC_ARCH_ARM64,
BCC_ARCH_X86
} bcc_arch_t;
typedef void *(*arch_callback_t)(bcc_arch_t arch);
static void *run_arch_callback(arch_callback_t fn)
{
const char *archenv = getenv("ARCH");
/* If ARCH is not set, detect from local arch clang is running on */
if (!archenv) {
#if defined(__powerpc64__)
#if defined(_CALL_ELF) && _CALL_ELF == 2
return fn(BCC_ARCH_PPC_LE);
#else
return fn(BCC_ARCH_PPC);
#endif
#elif defined(__s390x__)
return fn(BCC_ARCH_S390X);
#elif defined(__aarch64__)
return fn(BCC_ARCH_ARM64);
#else
return fn(BCC_ARCH_X86);
#endif
}
/* Otherwise read it from ARCH */
if (!strcmp(archenv, "powerpc")) {
#if defined(_CALL_ELF) && _CALL_ELF == 2
return fn(BCC_ARCH_PPC_LE);
#else
return fn(BCC_ARCH_PPC);
#endif
} else if (!strcmp(archenv, "s390x")) {
return fn(BCC_ARCH_S390X);
} else if (!strcmp(archenv, "arm64")) {
return fn(BCC_ARCH_ARM64);
} else {
return fn(BCC_ARCH_X86);
}
}
...@@ -17,6 +17,7 @@ ...@@ -17,6 +17,7 @@
#include <linux/version.h> #include <linux/version.h>
#include <sys/utsname.h> #include <sys/utsname.h>
#include <unistd.h> #include <unistd.h>
#include <stdlib.h>
#include <clang/AST/ASTConsumer.h> #include <clang/AST/ASTConsumer.h>
#include <clang/AST/ASTContext.h> #include <clang/AST/ASTContext.h>
...@@ -30,6 +31,7 @@ ...@@ -30,6 +31,7 @@
#include "common.h" #include "common.h"
#include "loader.h" #include "loader.h"
#include "table_storage.h" #include "table_storage.h"
#include "arch_helper.h"
#include "libbpf.h" #include "libbpf.h"
...@@ -47,16 +49,35 @@ const char *calling_conv_regs_s390x[] = {"gprs[2]", "gprs[3]", "gprs[4]", ...@@ -47,16 +49,35 @@ const char *calling_conv_regs_s390x[] = {"gprs[2]", "gprs[3]", "gprs[4]",
const char *calling_conv_regs_arm64[] = {"regs[0]", "regs[1]", "regs[2]", const char *calling_conv_regs_arm64[] = {"regs[0]", "regs[1]", "regs[2]",
"regs[3]", "regs[4]", "regs[5]"}; "regs[3]", "regs[4]", "regs[5]"};
// todo: support more archs
#if defined(__powerpc__) void *get_call_conv_cb(bcc_arch_t arch)
const char **calling_conv_regs = calling_conv_regs_ppc; {
#elif defined(__s390x__) const char **ret;
const char **calling_conv_regs = calling_conv_regs_s390x;
#elif defined(__aarch64__) switch(arch) {
const char **calling_conv_regs = calling_conv_regs_arm64; case BCC_ARCH_PPC:
#else case BCC_ARCH_PPC_LE:
const char **calling_conv_regs = calling_conv_regs_x86; ret = calling_conv_regs_ppc;
#endif break;
case BCC_ARCH_S390X:
ret = calling_conv_regs_s390x;
break;
case BCC_ARCH_ARM64:
ret = calling_conv_regs_arm64;
break;
default:
ret = calling_conv_regs_x86;
}
return (void *)ret;
}
const char **get_call_conv(void) {
const char **ret;
ret = (const char **)run_arch_callback(get_call_conv_cb);
return ret;
}
using std::map; using std::map;
using std::move; using std::move;
...@@ -256,6 +277,8 @@ BTypeVisitor::BTypeVisitor(ASTContext &C, BFrontendAction &fe) ...@@ -256,6 +277,8 @@ BTypeVisitor::BTypeVisitor(ASTContext &C, BFrontendAction &fe)
: C(C), diag_(C.getDiagnostics()), fe_(fe), rewriter_(fe.rewriter()), out_(llvm::errs()) {} : C(C), diag_(C.getDiagnostics()), fe_(fe), rewriter_(fe.rewriter()), out_(llvm::errs()) {}
bool BTypeVisitor::VisitFunctionDecl(FunctionDecl *D) { bool BTypeVisitor::VisitFunctionDecl(FunctionDecl *D) {
const char **calling_conv_regs = get_call_conv();
// put each non-static non-inline function decl in its own section, to be // put each non-static non-inline function decl in its own section, to be
// extracted by the MemoryManager // extracted by the MemoryManager
auto real_start_loc = rewriter_.getSourceMgr().getFileLoc(D->getLocStart()); auto real_start_loc = rewriter_.getSourceMgr().getFileLoc(D->getLocStart());
......
...@@ -14,7 +14,9 @@ ...@@ -14,7 +14,9 @@
* limitations under the License. * limitations under the License.
*/ */
#include <fcntl.h> #include <fcntl.h>
#include <stdlib.h>
#include <ftw.h> #include <ftw.h>
#include <iostream>
#include "kbuild_helper.h" #include "kbuild_helper.h"
namespace ebpf { namespace ebpf {
...@@ -34,6 +36,8 @@ int KBuildHelper::get_flags(const char *uname_machine, vector<string> *cflags) { ...@@ -34,6 +36,8 @@ int KBuildHelper::get_flags(const char *uname_machine, vector<string> *cflags) {
// -e s/aarch64.*/arm64/ // -e s/aarch64.*/arm64/
string arch = uname_machine; string arch = uname_machine;
const char *archenv;
if (!strncmp(uname_machine, "x86_64", 6)) { if (!strncmp(uname_machine, "x86_64", 6)) {
arch = "x86"; arch = "x86";
} else if (uname_machine[0] == 'i' && !strncmp(&uname_machine[2], "86", 2)) { } else if (uname_machine[0] == 'i' && !strncmp(&uname_machine[2], "86", 2)) {
...@@ -56,6 +60,11 @@ int KBuildHelper::get_flags(const char *uname_machine, vector<string> *cflags) { ...@@ -56,6 +60,11 @@ int KBuildHelper::get_flags(const char *uname_machine, vector<string> *cflags) {
arch = "arm64"; arch = "arm64";
} }
// If ARCH env is defined, use it over uname
archenv = getenv("ARCH");
if (archenv)
arch = string(archenv);
cflags->push_back("-nostdinc"); cflags->push_back("-nostdinc");
cflags->push_back("-isystem"); cflags->push_back("-isystem");
cflags->push_back("/virtual/lib/clang/include"); cflags->push_back("/virtual/lib/clang/include");
...@@ -87,6 +96,11 @@ int KBuildHelper::get_flags(const char *uname_machine, vector<string> *cflags) { ...@@ -87,6 +96,11 @@ int KBuildHelper::get_flags(const char *uname_machine, vector<string> *cflags) {
cflags->push_back("-D__HAVE_BUILTIN_BSWAP16__"); cflags->push_back("-D__HAVE_BUILTIN_BSWAP16__");
cflags->push_back("-D__HAVE_BUILTIN_BSWAP32__"); cflags->push_back("-D__HAVE_BUILTIN_BSWAP32__");
cflags->push_back("-D__HAVE_BUILTIN_BSWAP64__"); cflags->push_back("-D__HAVE_BUILTIN_BSWAP64__");
// If ARCH env variable is set, pass this along.
if (archenv)
cflags->push_back("-D__TARGET_ARCH_" + arch);
cflags->push_back("-Wno-unused-value"); cflags->push_back("-Wno-unused-value");
cflags->push_back("-Wno-pointer-sign"); cflags->push_back("-Wno-pointer-sign");
cflags->push_back("-fno-stack-protector"); cflags->push_back("-fno-stack-protector");
......
...@@ -29,6 +29,7 @@ ...@@ -29,6 +29,7 @@
#include <unistd.h> #include <unistd.h>
#include <utility> #include <utility>
#include <vector> #include <vector>
#include <iostream>
#include <linux/bpf.h> #include <linux/bpf.h>
#include <clang/Basic/FileManager.h> #include <clang/Basic/FileManager.h>
...@@ -56,6 +57,7 @@ ...@@ -56,6 +57,7 @@
#include "b_frontend_action.h" #include "b_frontend_action.h"
#include "tp_frontend_action.h" #include "tp_frontend_action.h"
#include "loader.h" #include "loader.h"
#include "arch_helper.h"
using std::map; using std::map;
using std::string; using std::string;
...@@ -108,11 +110,24 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts, ...@@ -108,11 +110,24 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts,
unique_ptr<llvm::MemoryBuffer> main_buf; unique_ptr<llvm::MemoryBuffer> main_buf;
struct utsname un; struct utsname un;
uname(&un); uname(&un);
string kdir = string(KERNEL_MODULES_DIR) + "/" + un.release; string kdir, kpath;
auto kernel_path_info = get_kernel_path_info (kdir); const char *kpath_env = ::getenv("BCC_KERNEL_SOURCE");
bool has_kpath_source = false;
if (kpath_env) {
kpath = string(kpath_env);
} else {
kdir = string(KERNEL_MODULES_DIR) + "/" + un.release;
auto kernel_path_info = get_kernel_path_info(kdir);
has_kpath_source = kernel_path_info.first;
kpath = kdir + "/" + kernel_path_info.second;
}
if (flags_ & DEBUG_PREPROCESSOR)
std::cout << "Running from kernel directory at: " << kpath.c_str() << "\n";
// clang needs to run inside the kernel dir // clang needs to run inside the kernel dir
DirStack dstack(kdir + "/" + kernel_path_info.second); DirStack dstack(kpath);
if (!dstack.ok()) if (!dstack.ok())
return -1; return -1;
...@@ -143,7 +158,8 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts, ...@@ -143,7 +158,8 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts,
"-fno-asynchronous-unwind-tables", "-fno-asynchronous-unwind-tables",
"-x", "c", "-c", abs_file.c_str()}); "-x", "c", "-c", abs_file.c_str()});
KBuildHelper kbuild_helper(kdir, kernel_path_info.first); KBuildHelper kbuild_helper(kpath_env ? kpath : kdir, has_kpath_source);
vector<string> kflags; vector<string> kflags;
if (kbuild_helper.get_flags(un.machine, &kflags)) if (kbuild_helper.get_flags(un.machine, &kflags))
return -1; return -1;
...@@ -186,6 +202,37 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts, ...@@ -186,6 +202,37 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts,
return 0; return 0;
} }
void *get_clang_target_cb(bcc_arch_t arch)
{
const char *ret;
switch(arch) {
case BCC_ARCH_PPC_LE:
ret = "powerpc64le-unknown-linux-gnu";
break;
case BCC_ARCH_PPC:
ret = "powerpc64-unknown-linux-gnu";
break;
case BCC_ARCH_S390X:
ret = "s390x-ibm-linux-gnu";
break;
case BCC_ARCH_ARM64:
ret = "aarch64-unknown-linux-gnu";
break;
default:
ret = "x86_64-unknown-linux-gnu";
}
return (void *)ret;
}
string get_clang_target(void) {
const char *ret;
ret = (const char *)run_arch_callback(get_clang_target_cb);
return string(ret);
}
int ClangLoader::do_compile(unique_ptr<llvm::Module> *mod, TableStorage &ts, int ClangLoader::do_compile(unique_ptr<llvm::Module> *mod, TableStorage &ts,
bool in_memory, bool in_memory,
const vector<const char *> &flags_cstr_in, const vector<const char *> &flags_cstr_in,
...@@ -212,19 +259,10 @@ int ClangLoader::do_compile(unique_ptr<llvm::Module> *mod, TableStorage &ts, ...@@ -212,19 +259,10 @@ int ClangLoader::do_compile(unique_ptr<llvm::Module> *mod, TableStorage &ts,
DiagnosticsEngine diags(DiagID, &*diag_opts, diag_client); DiagnosticsEngine diags(DiagID, &*diag_opts, diag_client);
// set up the command line argument wrapper // set up the command line argument wrapper
#if defined(__powerpc64__)
#if defined(_CALL_ELF) && _CALL_ELF == 2 string target_triple = get_clang_target();
driver::Driver drv("", "powerpc64le-unknown-linux-gnu", diags); driver::Driver drv("", target_triple, diags);
#else
driver::Driver drv("", "powerpc64-unknown-linux-gnu", diags);
#endif
#elif defined(__s390x__)
driver::Driver drv("", "s390x-ibm-linux-gnu", diags);
#elif defined(__aarch64__)
driver::Driver drv("", "aarch64-unknown-linux-gnu", diags);
#else
driver::Driver drv("", "x86_64-unknown-linux-gnu", diags);
#endif
drv.setTitle("bcc-clang-driver"); drv.setTitle("bcc-clang-driver");
drv.setCheckInputsExist(false); drv.setCheckInputsExist(false);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment