local program = [[
#include <uapi/linux/ptrace.h>
int trace_method(struct pt_regs *ctx) {
- char fn_name[128] = {};
- bpf_usdt_readarg_p(method__entry_2, ctx, &fn_name, sizeof(fn_name));
- bpf_trace_printk("%s(...)\n", &fn_name);
- return 0;
+ uint64_t addr;
+ bpf_usdt_readarg(2, ctx, &addr);
+
+ char fn_name[128] = {};
+ bpf_probe_read(&fn_name, sizeof(fn_name), (void *)addr);
+
+ bpf_trace_printk("%s(...)\n", fn_name);
+ return 0;
};
]]
int incr_cksum_l4(void *off, u64 oldval, u64 newval, u64 flags) asm("llvm.bpf.extra");
int bpf_num_cpus() asm("llvm.bpf.extra");
-#define lock_xadd(ptr, val) ((void)__sync_fetch_and_add(ptr, val))
+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__
#define PT_REGS_PARM1(ctx) ((ctx)->gpr[3])
#error "bcc does not support this platform yet"
#endif
-#define bpf_usdt_readarg(probearg, ctx) _bpf_readarg_##probearg(ctx)
-#define bpf_usdt_readarg_p(probearg, ctx, buf, len) {\
- u64 __addr = bpf_usdt_readarg(probearg, ctx); \
- bpf_probe_read(buf, len, (void *)__addr); }
+#define lock_xadd(ptr, val) ((void)__sync_fetch_and_add(ptr, val))
#endif
)********"
// put each non-static non-inline function decl in its own section, to be
// extracted by the MemoryManager
if (D->isExternallyVisible() && D->hasBody()) {
+ current_fn_ = D->getName();
string attr = string("__attribute__((section(\"") + BPF_FN_PREFIX + D->getName().str() + "\")))\n";
rewriter_.InsertText(D->getLocStart(), attr);
if (D->param_size() > MAX_CALLING_CONV_REGS + 1) {
numcpu = 1;
text = to_string(numcpu);
rewriter_.ReplaceText(SourceRange(Call->getLocStart(), Call->getLocEnd()), text);
- }
+ } else if (Decl->getName() == "bpf_usdt_readarg_p") {
+ text = "({ u64 __addr = 0x0; ";
+ text += "_bpf_readarg_" + current_fn_ + "_" + args[0] + "(" +
+ args[1] + ", &__addr, sizeof(__addr));";
+ text += "bpf_probe_read(" + args[2] + ", " + args[3] +
+ ", (void *)__addr);";
+ text += "})";
+ rewriter_.ReplaceText(
+ SourceRange(Call->getLocStart(), Call->getLocEnd()), text);
+ } else if (Decl->getName() == "bpf_usdt_readarg") {
+ text = "_bpf_readarg_" + current_fn_ + "_" + args[0] + "(" +
+ args[1] + ", " + args[2] + ", sizeof(*(" + args[2] + ")))";
+ rewriter_.ReplaceText(
+ SourceRange(Call->getLocStart(), Call->getLocEnd()), text);
+ }
}
}
}
std::vector<TableDesc> &tables_; /// store the open FDs
std::vector<clang::ParmVarDecl *> fn_args_;
std::set<clang::Expr *> visited_;
+ std::string current_fn_;
};
// Do a depth-first search to rewrite all pointers that need to be probed
return result;
}
-bool Probe::usdt_thunks(std::ostream &stream, const std::string &prefix) {
- assert(!locations_.empty());
- for (size_t i = 0; i < locations_.size(); ++i) {
- tfm::format(
- stream,
- "int %s_thunk_%d(struct pt_regs *ctx) { return %s(ctx, %d); }\n",
- prefix, i, prefix, i);
- }
- return true;
-}
-
-bool Probe::usdt_cases(std::ostream &stream, const optional<int> &pid) {
- assert(!locations_.empty());
- const size_t arg_count = locations_[0].arguments_.size();
-
- for (size_t arg_n = 0; arg_n < arg_count; ++arg_n) {
- tfm::format(stream, "%s arg%d = 0;\n", largest_arg_type(arg_n), arg_n + 1);
- }
-
- for (size_t loc_n = 0; loc_n < locations_.size(); ++loc_n) {
- Location &location = locations_[loc_n];
- tfm::format(stream, "if (__loc_id == %d) {\n", loc_n);
-
- for (size_t arg_n = 0; arg_n < location.arguments_.size(); ++arg_n) {
- Argument &arg = location.arguments_[arg_n];
- if (!arg.assign_to_local(stream, tfm::format("arg%d", arg_n + 1),
- bin_path_, pid))
- return false;
- }
- stream << "}\n";
- }
- return true;
-}
-
std::string Probe::largest_arg_type(size_t arg_n) {
Argument *largest = nullptr;
for (Location &location : locations_) {
return largest->ctype();
}
-bool Probe::usdt_getarg(std::ostream &stream, const optional<int> &pid) {
+bool Probe::usdt_getarg(std::ostream &stream,
+ const std::string &fn_name, const optional<int> &pid) {
const size_t arg_count = locations_[0].arguments_.size();
if (arg_count == 0)
for (size_t arg_n = 0; arg_n < arg_count; ++arg_n) {
std::string ctype = largest_arg_type(arg_n);
+ std::string cptr = tfm::format("*((%s *)dest)", ctype);
+
tfm::format(stream,
- "static inline %s _bpf_readarg_%s_%d(struct pt_regs *ctx) {\n"
- " %s result = 0x0;\n",
- ctype, name_, arg_n + 1, ctype);
+ "static inline int _bpf_readarg_%s_%d("
+ "struct pt_regs *ctx, void *dest, size_t len) {\n"
+ " if (len != sizeof(%s)) return -1;\n",
+ fn_name, arg_n + 1, ctype);
if (locations_.size() == 1) {
Location &location = locations_.front();
stream << " ";
- if (!location.arguments_[arg_n].assign_to_local(stream, "result",
+ if (!location.arguments_[arg_n].assign_to_local(stream, cptr,
bin_path_, pid))
return false;
- stream << "\n";
+ stream << "\n return 0;\n}\n";
} else {
stream << " switch(ctx->ip) {\n";
for (Location &location : locations_) {
return false;
tfm::format(stream, " case 0x%xULL: ", global_address);
- if (!location.arguments_[arg_n].assign_to_local(stream, "result",
+ if (!location.arguments_[arg_n].assign_to_local(stream, cptr,
bin_path_, pid))
return false;
- stream << " break;\n";
+ stream << " return 0;\n";
}
stream << " }\n";
+ stream << " return -1;\n}\n";
}
- stream << " return result;\n}\n";
}
return true;
}
bool Context::generate_usdt_args(std::ostream &stream) {
stream << "#include <uapi/linux/ptrace.h>\n";
for (auto &p : uprobes_) {
- if (!p.first->usdt_getarg(stream, pid_))
+ if (!p.first->usdt_getarg(stream, p.second, pid_))
return false;
}
return true;
size_t num_arguments() const { return locations_.front().arguments_.size(); }
uint64_t address(size_t n = 0) const { return locations_[n].address_; }
-
- bool usdt_thunks(std::ostream &stream, const std::string &prefix);
- bool usdt_cases(std::ostream &stream, const optional<int> &pid = nullopt);
- bool usdt_getarg(std::ostream &stream, const optional<int> &pid = nullopt);
+ bool usdt_getarg(std::ostream &stream, const std::string &fn_name, const optional<int> &pid = nullopt);
bool need_enable() const { return semaphore_ != 0x0; }
bool enable(int pid);
REQUIRE(probe->need_enable() == false);
REQUIRE(a_probed_function() != 0);
-
- std::ostringstream case_stream;
- REQUIRE(probe->usdt_cases(case_stream));
-
- std::string cases = case_stream.str();
- REQUIRE(cases.find("int32_t arg1") != std::string::npos);
- REQUIRE(cases.find("uint64_t arg2") != std::string::npos);
}
}
#endif // HAVE_SDT_HEADER
REQUIRE(probe->num_locations() == 1);
REQUIRE(probe->num_arguments() == 3);
REQUIRE(probe->need_enable() == true);
-
- std::ostringstream thunks_stream;
- REQUIRE(probe->usdt_thunks(thunks_stream, "ruby_usdt"));
-
- std::string thunks = thunks_stream.str();
- REQUIRE(std::count(thunks.begin(), thunks.end(), '\n') == 1);
- REQUIRE(thunks.find("ruby_usdt_thunk_0") != std::string::npos);
-
- std::ostringstream case_stream;
- REQUIRE(probe->usdt_cases(case_stream));
-
- std::string cases = case_stream.str();
- REQUIRE(countsubs(cases, "arg1") == 2);
- REQUIRE(countsubs(cases, "arg2") == 2);
- REQUIRE(countsubs(cases, "arg3") == 2);
-
- REQUIRE(countsubs(cases, "uint64_t") == 4);
- REQUIRE(countsubs(cases, "int32_t") == 2);
}
SECTION("array creation probe") {
REQUIRE(probe->num_locations() == 7);
REQUIRE(probe->num_arguments() == 3);
REQUIRE(probe->need_enable() == true);
-
- std::ostringstream thunks_stream;
- REQUIRE(probe->usdt_thunks(thunks_stream, "ruby_usdt"));
-
- std::string thunks = thunks_stream.str();
- REQUIRE(std::count(thunks.begin(), thunks.end(), '\n') == 7);
- REQUIRE(thunks.find("ruby_usdt_thunk_0") != std::string::npos);
- REQUIRE(thunks.find("ruby_usdt_thunk_6") != std::string::npos);
- REQUIRE(thunks.find("ruby_usdt_thunk_7") == std::string::npos);
-
- std::ostringstream case_stream;
- REQUIRE(probe->usdt_cases(case_stream));
-
- std::string cases = case_stream.str();
- REQUIRE(countsubs(cases, "arg1") == 8);
- REQUIRE(countsubs(cases, "arg2") == 8);
- REQUIRE(countsubs(cases, "arg3") == 8);
-
- REQUIRE(countsubs(cases, "__loc_id") == 7);
- REQUIRE(cases.find("int64_t arg1 =") != std::string::npos);
}
}