Skip to content

Commit

Permalink
Merge pull request iovisor#1569 from joelagnel/bcc-cross-compile
Browse files Browse the repository at this point in the history
BCC cross compilation support
  • Loading branch information
yonghong-song committed Feb 8, 2018
2 parents 3613ff8 + 1086952 commit e01c993
Show file tree
Hide file tree
Showing 5 changed files with 201 additions and 31 deletions.
38 changes: 34 additions & 4 deletions src/cc/export/helpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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_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_PARM2(ctx) ((ctx)->gpr[4])
#define PT_REGS_PARM3(ctx) ((ctx)->gpr[5])
Expand All @@ -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_IP(ctx) ((ctx)->nip)
#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_PARM2(x) ((x)->gprs[3])
#define PT_REGS_PARM3(x) ((x)->gprs[4])
Expand All @@ -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_SP(x) ((x)->gprs[15])
#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_PARM2(ctx) ((ctx)->si)
#define PT_REGS_PARM3(ctx) ((ctx)->dx)
Expand All @@ -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_IP(ctx) ((ctx)->ip)
#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_PARM2(x) ((x)->regs[1])
#define PT_REGS_PARM3(x) ((x)->regs[2])
Expand Down
65 changes: 65 additions & 0 deletions src/cc/frontends/clang/arch_helper.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
/*
* 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:https://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);
}
}
43 changes: 33 additions & 10 deletions src/cc/frontends/clang/b_frontend_action.cc
Original file line number Diff line number Diff line change
Expand Up @@ -17,6 +17,7 @@
#include <linux/version.h>
#include <sys/utsname.h>
#include <unistd.h>
#include <stdlib.h>

#include <clang/AST/ASTConsumer.h>
#include <clang/AST/ASTContext.h>
Expand All @@ -30,6 +31,7 @@
#include "common.h"
#include "loader.h"
#include "table_storage.h"
#include "arch_helper.h"

#include "libbpf.h"

Expand All @@ -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]",
"regs[3]", "regs[4]", "regs[5]"};
// todo: support more archs
#if defined(__powerpc__)
const char **calling_conv_regs = calling_conv_regs_ppc;
#elif defined(__s390x__)
const char **calling_conv_regs = calling_conv_regs_s390x;
#elif defined(__aarch64__)
const char **calling_conv_regs = calling_conv_regs_arm64;
#else
const char **calling_conv_regs = calling_conv_regs_x86;
#endif

void *get_call_conv_cb(bcc_arch_t arch)
{
const char **ret;

switch(arch) {
case BCC_ARCH_PPC:
case BCC_ARCH_PPC_LE:
ret = calling_conv_regs_ppc;
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::move;
Expand Down Expand Up @@ -256,6 +277,8 @@ BTypeVisitor::BTypeVisitor(ASTContext &C, BFrontendAction &fe)
: C(C), diag_(C.getDiagnostics()), fe_(fe), rewriter_(fe.rewriter()), out_(llvm::errs()) {}

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
// extracted by the MemoryManager
auto real_start_loc = rewriter_.getSourceMgr().getFileLoc(D->getLocStart());
Expand Down
14 changes: 14 additions & 0 deletions src/cc/frontends/clang/kbuild_helper.cc
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,9 @@
* limitations under the License.
*/
#include <fcntl.h>
#include <stdlib.h>
#include <ftw.h>
#include <iostream>
#include "kbuild_helper.h"

namespace ebpf {
Expand All @@ -34,6 +36,8 @@ int KBuildHelper::get_flags(const char *uname_machine, vector<string> *cflags) {
// -e s/aarch64.*/arm64/

string arch = uname_machine;
const char *archenv;

if (!strncmp(uname_machine, "x86_64", 6)) {
arch = "x86";
} else if (uname_machine[0] == 'i' && !strncmp(&uname_machine[2], "86", 2)) {
Expand All @@ -56,6 +60,11 @@ int KBuildHelper::get_flags(const char *uname_machine, vector<string> *cflags) {
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("-isystem");
cflags->push_back("/virtual/lib/clang/include");
Expand Down Expand Up @@ -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_BSWAP32__");
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-pointer-sign");
cflags->push_back("-fno-stack-protector");
Expand Down
72 changes: 55 additions & 17 deletions src/cc/frontends/clang/loader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@
#include <unistd.h>
#include <utility>
#include <vector>
#include <iostream>
#include <linux/bpf.h>

#include <clang/Basic/FileManager.h>
Expand Down Expand Up @@ -56,6 +57,7 @@
#include "b_frontend_action.h"
#include "tp_frontend_action.h"
#include "loader.h"
#include "arch_helper.h"

using std::map;
using std::string;
Expand Down Expand Up @@ -108,11 +110,24 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts,
unique_ptr<llvm::MemoryBuffer> main_buf;
struct utsname un;
uname(&un);
string kdir = string(KERNEL_MODULES_DIR) + "/" + un.release;
auto kernel_path_info = get_kernel_path_info (kdir);
string kdir, kpath;
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
DirStack dstack(kdir + "/" + kernel_path_info.second);
DirStack dstack(kpath);
if (!dstack.ok())
return -1;

Expand Down Expand Up @@ -143,7 +158,8 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts,
"-fno-asynchronous-unwind-tables",
"-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;
if (kbuild_helper.get_flags(un.machine, &kflags))
return -1;
Expand Down Expand Up @@ -186,6 +202,37 @@ int ClangLoader::parse(unique_ptr<llvm::Module> *mod, TableStorage &ts,
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,
bool in_memory,
const vector<const char *> &flags_cstr_in,
Expand All @@ -212,19 +259,10 @@ int ClangLoader::do_compile(unique_ptr<llvm::Module> *mod, TableStorage &ts,
DiagnosticsEngine diags(DiagID, &*diag_opts, diag_client);

// set up the command line argument wrapper
#if defined(__powerpc64__)
#if defined(_CALL_ELF) && _CALL_ELF == 2
driver::Driver drv("", "powerpc64le-unknown-linux-gnu", 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

string target_triple = get_clang_target();
driver::Driver drv("", target_triple, diags);

drv.setTitle("bcc-clang-driver");
drv.setCheckInputsExist(false);

Expand Down

0 comments on commit e01c993

Please sign in to comment.