Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

bpftime trace: tracepipe support for bpf_printk #253

Open
wants to merge 7 commits into
base: master
Choose a base branch
from
33 changes: 31 additions & 2 deletions runtime/src/bpf_helper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,9 @@
#include <cstring>
#include <time.h>
#include <unistd.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <ctime>
#include <filesystem>
#include "bpftime.hpp"
Expand Down Expand Up @@ -47,8 +50,34 @@ uint64_t bpftime_trace_printk(uint64_t fmt, uint64_t fmt_size, ...)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wformat-nonliteral"
#pragma GCC diagnostic ignored "-Wvarargs"
va_start(args, fmt_str);
long ret = vprintf(fmt_str, args);
const char *tracepipe = getenv("TRACEPIPE_PATH");
if (tracepipe != NULL) {
std::string tracepipe_path(getenv("TRACEPIPE_PATH"));
if (tracepipe_path.empty()) {
va_start(args, fmt_str);
long ret = vprintf(fmt_str, args);
} else {
const char *pipepath = tracepipe_path.c_str();
mode_t permission = 0666;
if (mkfifo(pipepath, permission) == -1) {
if (errno != EEXIST) {
SPDLOG_ERROR("mkfifo error: {}", strerror(errno));
return 1;
}
}
int fd = open(pipepath, O_WRONLY);
if (fd == -1) {
SPDLOG_ERROR("open error: {}", strerror(errno));
return 1;
}
va_start(args, fmt_str);
long ret = vdprintf(fd, fmt_str, args);
close(fd);
}
} else {
va_start(args, fmt_str);
long ret = vprintf(fmt_str, args);
}
#pragma GCC diagnostic pop
va_end(args);
return 0;
Expand Down
102 changes: 88 additions & 14 deletions tools/cli/main.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,11 @@
#include <utility>
#include <tuple>
#include <sys/wait.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>

#define STR_MAX 1024

static int subprocess_pid = 0;

Expand All @@ -25,37 +30,49 @@ static bool str_starts_with(const char *main, const char *pat)
}

static int run_command(const char *path, const std::vector<std::string> &argv,
const char *ld_preload, const char *agent_so)
const char *ld_preload, const char *agent_so,
const char *tracepipe_path)
{
int pid = fork();
if (pid == 0) {
std::string ld_preload_str("LD_PRELOAD=");
std::string agent_so_str("AGENT_SO=");
std::string tracepipe_path_str("TRACEPIPE_PATH=");
ld_preload_str += ld_preload;

if (agent_so) {
agent_so_str += agent_so;
}
if (tracepipe_path) {
tracepipe_path_str += tracepipe_path;
}
std::vector<const char *> env_arr;
char **p = environ;
while (*p) {
env_arr.push_back(*p);
p++;
}
bool ld_preload_set = false, agent_so_set = false;
bool ld_preload_set = false, agent_so_set = false,
tracepipe_path_set = false;
for (auto &s : env_arr) {
if (str_starts_with(s, "LD_PRELOAD=")) {
s = ld_preload_str.c_str();
ld_preload_set = true;
} else if (str_starts_with(s, "AGENT_SO=")) {
s = agent_so_str.c_str();
agent_so_set = true;
}
} else if (str_starts_with(s, "TRACEPIPE_PATH=")) {
s = tracepipe_path_str.c_str();
tracepipe_path_set = true;
}
}
if (!ld_preload_set)
env_arr.push_back(ld_preload_str.c_str());
if (!agent_so_set)
env_arr.push_back(agent_so_str.c_str());
if (!tracepipe_path_set) {
env_arr.push_back(tracepipe_path_str.c_str());
}

env_arr.push_back(nullptr);
std::vector<const char *> argv_arr;
Expand All @@ -82,6 +99,7 @@ static int run_command(const char *path, const std::vector<std::string> &argv,
}
return 1;
}

static int inject_by_frida(int pid, const char *inject_path, const char *arg)
{
spdlog::info("Injecting to {}", pid);
Expand Down Expand Up @@ -121,18 +139,47 @@ extract_path_and_args(const argparse::ArgumentParser &parser)
return { executable, items };
}

static void signal_handler(int sig)
static int read_tracepipe(const char *tracepipe_path)
{
if (subprocess_pid) {
kill(subprocess_pid, sig);
}
mode_t permission = 0666;
if (mkfifo(tracepipe_path, permission) == -1) {
if (errno != EEXIST) {
spdlog::error("Failed to create tracepipe: {}", strerror(errno));
return 1;
}
} else {
spdlog::info("Trace pipe created");
}

int fd = open(tracepipe_path, O_RDONLY);
if (fd == -1) {
spdlog::error(
"Failed to open tracepipe: {}",
strerror(errno));
return 2;
}

while (1) {
char data[STR_MAX];
ssize_t ret = read(fd, data, strnlen(data, STR_MAX));
if (ret == -1) {
spdlog::error(
"Failed to read from tracepipe: {}",
strerror(errno));
return 3;
} else {
if (ret > 0) {
std::cout << data;
}
}
}
return 0;
}


int main(int argc, const char **argv)
{
spdlog::cfg::load_env_levels();
signal(SIGINT, signal_handler);
signal(SIGTSTP, signal_handler);
argparse::ArgumentParser program(argv[0]);

if (auto home_env = getenv("HOME"); home_env) {
Expand Down Expand Up @@ -176,6 +223,9 @@ int main(int argc, const char **argv)
.nargs(argparse::nargs_pattern::at_least_one)
.remaining()
.help("Command to run");
start_command.add_argument("-p", "--print-to-trace-pipe")
.help("Whether to send output of bpf_printk to the tracepipe")
.flag();

argparse::ArgumentParser attach_command("attach");

Expand All @@ -185,9 +235,13 @@ int main(int argc, const char **argv)
.flag();
attach_command.add_argument("PID").scan<'i', int>();

argparse::ArgumentParser trace_command("trace");
trace_command.add_description("Read contents of tracepipe");

program.add_subparser(load_command);
program.add_subparser(start_command);
program.add_subparser(attach_command);
program.add_subparser(trace_command);
try {
program.parse_args(argc, argv);
} catch (const std::exception &err) {
Expand All @@ -208,8 +262,11 @@ int main(int argc, const char **argv)
}
auto [executable_path, extra_args] =
extract_path_and_args(load_command);
return run_command(executable_path.c_str(), extra_args,
so_path.c_str(), nullptr);
return run_command(executable_path.c_str(),
extra_args,
so_path.c_str(),
nullptr,
nullptr);
} else if (program.is_subcommand_used("start")) {
auto agent_path = install_path / "libbpftime-agent.so";
if (!std::filesystem::exists(agent_path)) {
Expand All @@ -219,6 +276,14 @@ int main(int argc, const char **argv)
}
auto [executable_path, extra_args] =
extract_path_and_args(start_command);
std::string tracepipe_path;
if (start_command.get<bool>("print-to-trace-pipe")) {
tracepipe_path = install_path / "tracepipe";
if (!std::filesystem::exists(tracepipe_path)) {
spdlog::error("Tracepipe not found: {}",
tracepipe_path.c_str());
}
}
if (start_command.get<bool>("enable-syscall-trace")) {
auto transformer_path =
install_path /
Expand All @@ -231,10 +296,12 @@ int main(int argc, const char **argv)

return run_command(executable_path.c_str(), extra_args,
transformer_path.c_str(),
agent_path.c_str());
agent_path.c_str(),
tracepipe_path.c_str());
} else {
return run_command(executable_path.c_str(), extra_args,
agent_path.c_str(), nullptr);
agent_path.c_str(), nullptr,
tracepipe_path.c_str());
}
} else if (program.is_subcommand_used("attach")) {
auto agent_path = install_path / "libbpftime-agent.so";
Expand All @@ -258,6 +325,13 @@ int main(int argc, const char **argv)
} else {
return inject_by_frida(pid, agent_path.c_str(), "");
}
}
} else if (program.is_subcommand_used("trace")) {
auto tracepipe_path = install_path / "tracepipe";
if (!std::filesystem::exists(tracepipe_path)) {
spdlog::error("Tracepipe not found: {}",
tracepipe_path.c_str());
}
return read_tracepipe(tracepipe_path.c_str());
}
return 0;
}
Loading