Commit 63ff0b46 authored by Brenden Blanco's avatar Brenden Blanco

Merge pull request #518 from vmg/vmg/lua-usdt-2

[RFC] New USDT API
parents 7575c64d 11606086
#!/usr/bin/env bcc-lua
--[[
Copyright 2016 GitHub, 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.
]]
local program = [[
#include <uapi/linux/ptrace.h>
int trace_method(struct pt_regs *ctx) {
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;
};
]]
return function(BPF, util)
if not arg[1] then
print("usage: rubysyms.lua PID")
return
end
local u = util.USDT:new{pid=tonumber(arg[1])}
u:enable_probe{probe="method__entry", fn_name="trace_method"}
local b = BPF:new{text=program, usdt=u}
local pipe = b:pipe()
while true do
print(pipe:trace_fields())
end
end
...@@ -24,17 +24,15 @@ ...@@ -24,17 +24,15 @@
#include "bcc_syms.h" #include "bcc_syms.h"
#include "syms.h" #include "syms.h"
#include "vendor/tinyformat.hpp"
ino_t ProcStat::getinode_() { ino_t ProcStat::getinode_() {
struct stat s; struct stat s;
return (!stat(procfs_.c_str(), &s)) ? s.st_ino : -1; return (!stat(procfs_.c_str(), &s)) ? s.st_ino : -1;
} }
ProcStat::ProcStat(int pid) : inode_(-1) { ProcStat::ProcStat(int pid)
char buffer[128]; : procfs_(tfm::format("/proc/%d/exe", pid)), inode_(getinode_()) {}
snprintf(buffer, sizeof(buffer), "/proc/%d/exe", pid);
procfs_ = buffer;
}
void KSyms::_add_symbol(const char *symname, uint64_t addr, void *p) { void KSyms::_add_symbol(const char *symname, uint64_t addr, void *p) {
KSyms *ks = static_cast<KSyms *>(p); KSyms *ks = static_cast<KSyms *>(p);
...@@ -84,11 +82,15 @@ bool KSyms::resolve_name(const char *_unused, const char *name, ...@@ -84,11 +82,15 @@ bool KSyms::resolve_name(const char *_unused, const char *name,
return true; return true;
} }
ProcSyms::ProcSyms(int pid) : pid_(pid), procstat_(pid) { refresh(); } ProcSyms::ProcSyms(int pid) : pid_(pid), procstat_(pid) { load_modules(); }
bool ProcSyms::load_modules() {
return bcc_procutils_each_module(pid_, _add_module, this) == 0;
}
void ProcSyms::refresh() { void ProcSyms::refresh() {
modules_.clear(); modules_.clear();
bcc_procutils_each_module(pid_, _add_module, this); load_modules();
procstat_.reset(); procstat_.reset();
} }
...@@ -199,6 +201,32 @@ void bcc_symcache_refresh(void *resolver) { ...@@ -199,6 +201,32 @@ void bcc_symcache_refresh(void *resolver) {
cache->refresh(); cache->refresh();
} }
struct mod_st {
const char *name;
uint64_t start;
};
static int _find_module(const char *modname, uint64_t start, uint64_t end,
void *p) {
struct mod_st *mod = (struct mod_st *)p;
if (!strcmp(modname, mod->name)) {
mod->start = start;
return -1;
}
return 0;
}
int bcc_resolve_global_addr(int pid, const char *module, const uint64_t address,
uint64_t *global) {
struct mod_st mod = {module, 0x0};
if (bcc_procutils_each_module(pid, _find_module, &mod) < 0 ||
mod.start == 0x0)
return -1;
*global = mod.start + address;
return 0;
}
static int _find_sym(const char *symname, uint64_t addr, uint64_t end, static int _find_sym(const char *symname, uint64_t addr, uint64_t end,
int flags, void *payload) { int flags, void *payload) {
struct bcc_symbol *sym = (struct bcc_symbol *)payload; struct bcc_symbol *sym = (struct bcc_symbol *)payload;
......
...@@ -33,6 +33,8 @@ int bcc_symcache_resolve(void *symcache, uint64_t addr, struct bcc_symbol *sym); ...@@ -33,6 +33,8 @@ int bcc_symcache_resolve(void *symcache, uint64_t addr, struct bcc_symbol *sym);
int bcc_symcache_resolve_name(void *resolver, const char *name, uint64_t *addr); int bcc_symcache_resolve_name(void *resolver, const char *name, uint64_t *addr);
void bcc_symcache_refresh(void *resolver); void bcc_symcache_refresh(void *resolver);
int bcc_resolve_global_addr(int pid, const char *module, const uint64_t address,
uint64_t *global);
int bcc_find_symbol_addr(struct bcc_symbol *sym); int bcc_find_symbol_addr(struct bcc_symbol *sym);
int bcc_resolve_symname(const char *module, const char *symname, int bcc_resolve_symname(const char *module, const char *symname,
const uint64_t addr, struct bcc_symbol *sym); const uint64_t addr, struct bcc_symbol *sym);
......
/*
* Copyright (c) 2016 GitHub, 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.
*/
#ifndef LIBBCC_USDT_H
#define LIBBCC_USDT_H
#ifdef __cplusplus
extern "C" {
#endif
#include <stdint.h>
void *bcc_usdt_new_frompid(int pid);
void *bcc_usdt_new_frompath(const char *path);
void bcc_usdt_close(void *usdt);
int bcc_usdt_enable_probe(void *, const char *, const char *);
char *bcc_usdt_genargs(void *);
typedef void (*bcc_usdt_uprobe_cb)(const char *, const char *, uint64_t, int);
void bcc_usdt_foreach_uprobe(void *usdt, bcc_usdt_uprobe_cb callback);
#ifdef __cplusplus
}
#endif
#endif
...@@ -408,7 +408,9 @@ int incr_cksum_l3(void *off, u64 oldval, u64 newval) asm("llvm.bpf.extra"); ...@@ -408,7 +408,9 @@ int incr_cksum_l3(void *off, u64 oldval, u64 newval) asm("llvm.bpf.extra");
int incr_cksum_l4(void *off, u64 oldval, u64 newval, u64 flags) asm("llvm.bpf.extra"); int incr_cksum_l4(void *off, u64 oldval, u64 newval, u64 flags) asm("llvm.bpf.extra");
int bpf_num_cpus() 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__ #ifdef __powerpc__
#define PT_REGS_PARM1(ctx) ((ctx)->gpr[3]) #define PT_REGS_PARM1(ctx) ((ctx)->gpr[3])
...@@ -434,5 +436,7 @@ int bpf_num_cpus() asm("llvm.bpf.extra"); ...@@ -434,5 +436,7 @@ int bpf_num_cpus() asm("llvm.bpf.extra");
#error "bcc does not support this platform yet" #error "bcc does not support this platform yet"
#endif #endif
#define lock_xadd(ptr, val) ((void)__sync_fetch_and_add(ptr, val))
#endif #endif
)********" )********"
...@@ -254,6 +254,7 @@ bool BTypeVisitor::VisitFunctionDecl(FunctionDecl *D) { ...@@ -254,6 +254,7 @@ bool BTypeVisitor::VisitFunctionDecl(FunctionDecl *D) {
// 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
if (D->isExternallyVisible() && D->hasBody()) { if (D->isExternallyVisible() && D->hasBody()) {
current_fn_ = D->getName();
string attr = string("__attribute__((section(\"") + BPF_FN_PREFIX + D->getName().str() + "\")))\n"; string attr = string("__attribute__((section(\"") + BPF_FN_PREFIX + D->getName().str() + "\")))\n";
rewriter_.InsertText(D->getLocStart(), attr); rewriter_.InsertText(D->getLocStart(), attr);
if (D->param_size() > MAX_CALLING_CONV_REGS + 1) { if (D->param_size() > MAX_CALLING_CONV_REGS + 1) {
...@@ -470,6 +471,20 @@ bool BTypeVisitor::VisitCallExpr(CallExpr *Call) { ...@@ -470,6 +471,20 @@ bool BTypeVisitor::VisitCallExpr(CallExpr *Call) {
numcpu = 1; numcpu = 1;
text = to_string(numcpu); text = to_string(numcpu);
rewriter_.ReplaceText(SourceRange(Call->getLocStart(), Call->getLocEnd()), text); 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);
} }
} }
} }
......
...@@ -83,6 +83,7 @@ class BTypeVisitor : public clang::RecursiveASTVisitor<BTypeVisitor> { ...@@ -83,6 +83,7 @@ class BTypeVisitor : public clang::RecursiveASTVisitor<BTypeVisitor> {
std::vector<TableDesc> &tables_; /// store the open FDs std::vector<TableDesc> &tables_; /// store the open FDs
std::vector<clang::ParmVarDecl *> fn_args_; std::vector<clang::ParmVarDecl *> fn_args_;
std::set<clang::Expr *> visited_; std::set<clang::Expr *> visited_;
std::string current_fn_;
}; };
// Do a depth-first search to rewrite all pointers that need to be probed // Do a depth-first search to rewrite all pointers that need to be probed
......
...@@ -93,6 +93,7 @@ class ProcSyms : SymbolCache { ...@@ -93,6 +93,7 @@ class ProcSyms : SymbolCache {
ProcStat procstat_; ProcStat procstat_;
static int _add_module(const char *, uint64_t, uint64_t, void *); static int _add_module(const char *, uint64_t, uint64_t, void *);
bool load_modules();
public: public:
ProcSyms(int pid); ProcSyms(int pid);
......
This diff is collapsed.
...@@ -15,6 +15,7 @@ ...@@ -15,6 +15,7 @@
*/ */
#pragma once #pragma once
#include <memory>
#include <string> #include <string>
#include <unordered_map> #include <unordered_map>
#include <vector> #include <vector>
...@@ -122,32 +123,39 @@ class Probe { ...@@ -122,32 +123,39 @@ class Probe {
struct Location { struct Location {
uint64_t address_; uint64_t address_;
std::vector<Argument *> arguments_; std::vector<Argument> arguments_;
Location(uint64_t addr, const char *arg_fmt); Location(uint64_t addr, const char *arg_fmt);
}; };
std::vector<Location> locations_; std::vector<Location> locations_;
std::unordered_map<int, uint64_t> semaphores_;
std::unordered_map<int, ProcStat> enabled_semaphores_; optional<int> pid_;
optional<bool> in_shared_object_; optional<bool> in_shared_object_;
bool add_to_semaphore(int pid, int16_t val); optional<std::string> attached_to_;
bool lookup_semaphore_addr(uint64_t *address, int pid); optional<uint64_t> attached_semaphore_;
std::string largest_arg_type(size_t arg_n);
bool add_to_semaphore(int16_t val);
bool resolve_global_address(uint64_t *global, const uint64_t addr);
bool lookup_semaphore_addr(uint64_t *address);
void add_location(uint64_t addr, const char *fmt); void add_location(uint64_t addr, const char *fmt);
public: public:
Probe(const char *bin_path, const char *provider, const char *name, Probe(const char *bin_path, const char *provider, const char *name,
uint64_t semaphore); uint64_t semaphore, const optional<int> &pid);
size_t num_locations() const { return locations_.size(); } size_t num_locations() const { return locations_.size(); }
size_t num_arguments() const { return locations_.front().arguments_.size(); } size_t num_arguments() const { return locations_.front().arguments_.size(); }
bool usdt_thunks(std::ostream &stream, const std::string &prefix); uint64_t address(size_t n = 0) const { return locations_[n].address_; }
bool usdt_cases(std::ostream &stream, const optional<int> &pid = nullopt); bool usdt_getarg(std::ostream &stream);
bool need_enable() const { return semaphore_ != 0x0; } bool need_enable() const { return semaphore_ != 0x0; }
bool enable(int pid); bool enable(const std::string &fn_name);
bool disable(int pid); bool disable();
bool enabled() const { return !!attached_to_; }
bool in_shared_object(); bool in_shared_object();
const std::string &name() { return name_; } const std::string &name() { return name_; }
...@@ -158,7 +166,10 @@ public: ...@@ -158,7 +166,10 @@ public:
}; };
class Context { class Context {
std::vector<Probe *> probes_; std::vector<std::unique_ptr<Probe>> probes_;
optional<int> pid_;
optional<ProcStat> pid_stat_;
bool loaded_; bool loaded_;
static void _each_probe(const char *binpath, const struct bcc_elf_usdt *probe, static void _each_probe(const char *binpath, const struct bcc_elf_usdt *probe,
...@@ -171,9 +182,19 @@ class Context { ...@@ -171,9 +182,19 @@ class Context {
public: public:
Context(const std::string &bin_path); Context(const std::string &bin_path);
Context(int pid); Context(int pid);
~Context();
optional<int> pid() const { return pid_; }
bool loaded() const { return loaded_; } bool loaded() const { return loaded_; }
size_t num_probes() const { return probes_.size(); } size_t num_probes() const { return probes_.size(); }
Probe *find_probe(const std::string &probe_name);
Probe *get(const std::string &probe_name);
Probe *get(int pos) { return probes_[pos].get(); }
bool enable_probe(const std::string &probe_name, const std::string &fn_name);
bool generate_usdt_args(std::ostream &stream);
typedef void (*each_uprobe_cb)(const char *, const char *, uint64_t, int);
void each_uprobe(each_uprobe_cb callback);
}; };
} }
...@@ -55,37 +55,35 @@ bool Argument::assign_to_local(std::ostream &stream, ...@@ -55,37 +55,35 @@ bool Argument::assign_to_local(std::ostream &stream,
const std::string &binpath, const std::string &binpath,
const optional<int> &pid) const { const optional<int> &pid) const {
if (constant_) { if (constant_) {
tfm::format(stream, "%s = %d;\n", local_name, *constant_); tfm::format(stream, "%s = %d;", local_name, *constant_);
return true; return true;
} }
if (!deref_offset_) { if (!deref_offset_) {
tfm::format(stream, "%s = (%s)ctx->%s;\n", local_name, ctype(), tfm::format(stream, "%s = (%s)ctx->%s;", local_name, ctype(),
*register_name_); *register_name_);
return true; return true;
} }
if (deref_offset_ && !deref_ident_) { if (deref_offset_ && !deref_ident_) {
tfm::format(stream, tfm::format(stream,
"{\n" "{ u64 __addr = ctx->%s + (%d); %s __res = 0x0; "
" u64 __temp = ctx->%s + (%d);\n" "bpf_probe_read(&__res, sizeof(__res), (void *)__addr); "
" bpf_probe_read(&%s, sizeof(%s), (void *)__temp);\n" "%s = __res; }",
"}\n", *register_name_, *deref_offset_, ctype(), local_name);
*register_name_, *deref_offset_, local_name, local_name);
return true; return true;
} }
if (deref_offset_ && deref_ident_) { if (deref_offset_ && deref_ident_ && *register_name_ == "ip") {
uint64_t global_address; uint64_t global_address;
if (!get_global_address(&global_address, binpath, pid)) if (!get_global_address(&global_address, binpath, pid))
return false; return false;
tfm::format(stream, tfm::format(stream,
"{\n" "{ u64 __addr = 0x%xull + %d; %s __res = 0x0; "
" u64 __temp = 0x%xull + %d;\n" "bpf_probe_read(&__res, sizeof(__res), (void *)__addr); "
" bpf_probe_read(&%s, sizeof(%s), (void *)__temp);\n" "%s = __res; }",
"}\n", global_address, *deref_offset_, ctype(), local_name);
global_address, *deref_offset_, local_name, local_name);
return true; return true;
} }
......
...@@ -37,7 +37,7 @@ function Bpf.static.check_probe_quota(n) ...@@ -37,7 +37,7 @@ function Bpf.static.check_probe_quota(n)
assert(cur + n <= Bpf.static.KPROBE_LIMIT, "number of open probes would exceed quota") assert(cur + n <= Bpf.static.KPROBE_LIMIT, "number of open probes would exceed quota")
end end
function Bpf.static.cleanup_probes() function Bpf.static.cleanup()
local function detach_all(probe_type, all_probes) local function detach_all(probe_type, all_probes)
for key, probe in pairs(all_probes) do for key, probe in pairs(all_probes) do
libbcc.perf_reader_free(probe) libbcc.perf_reader_free(probe)
...@@ -102,10 +102,13 @@ local function _find_file(script_root, filename) ...@@ -102,10 +102,13 @@ local function _find_file(script_root, filename)
end end
function Bpf:initialize(args) function Bpf:initialize(args)
self.do_debug = args.debug or false
self.funcs = {} self.funcs = {}
self.tables = {} self.tables = {}
if args.usdt and args.text then
args.text = args.usdt:_get_text() .. args.text
end
local cflags = table.join(Bpf.DEFAULT_CFLAGS, args.cflags) local cflags = table.join(Bpf.DEFAULT_CFLAGS, args.cflags)
local cflags_ary = ffi.new("const char *[?]", #cflags, cflags) local cflags_ary = ffi.new("const char *[?]", #cflags, cflags)
...@@ -127,6 +130,10 @@ function Bpf:initialize(args) ...@@ -127,6 +130,10 @@ function Bpf:initialize(args)
end end
assert(self.module ~= nil, "failed to compile BPF module") assert(self.module ~= nil, "failed to compile BPF module")
if args.usdt then
args.usdt:_attach_uprobes(self)
end
end end
function Bpf:load_funcs(prog_type) function Bpf:load_funcs(prog_type)
......
...@@ -112,6 +112,18 @@ int bcc_symcache_resolve(void *symcache, uint64_t addr, struct bcc_symbol *sym); ...@@ -112,6 +112,18 @@ int bcc_symcache_resolve(void *symcache, uint64_t addr, struct bcc_symbol *sym);
void bcc_symcache_refresh(void *resolver); void bcc_symcache_refresh(void *resolver);
]] ]]
ffi.cdef[[
void *bcc_usdt_new_frompid(int pid);
void *bcc_usdt_new_frompath(const char *path);
void bcc_usdt_close(void *usdt);
int bcc_usdt_enable_probe(void *, const char *, const char *);
char *bcc_usdt_genargs(void *);
typedef void (*bcc_usdt_uprobe_cb)(const char *, const char *, uint64_t, int);
void bcc_usdt_foreach_uprobe(void *usdt, bcc_usdt_uprobe_cb callback);
]]
if rawget(_G, "BCC_STANDALONE") then if rawget(_G, "BCC_STANDALONE") then
return ffi.C return ffi.C
else else
......
...@@ -57,18 +57,21 @@ return function() ...@@ -57,18 +57,21 @@ return function()
local BPF = require("bcc.bpf") local BPF = require("bcc.bpf")
BPF.script_root(tracefile) BPF.script_root(tracefile)
local USDT = require("bcc.usdt")
local utils = { local utils = {
argparse = require("bcc.vendor.argparse"), argparse = require("bcc.vendor.argparse"),
posix = require("bcc.vendor.posix"), posix = require("bcc.vendor.posix"),
USDT = USDT,
} }
local command = dofile(tracefile) local command = dofile(tracefile)
local res, err = xpcall(command, debug.traceback, BPF, utils) local res, err = xpcall(command, debug.traceback, BPF, utils)
if not res then if not res and err ~= "interrupted!" then
io.stderr:write("[ERROR] "..err.."\n") io.stderr:write("[ERROR] "..err.."\n")
end end
BPF.cleanup_probes() BPF.cleanup()
USDT.cleanup()
return res, err return res, err
end end
--[[
Copyright 2016 GitHub, 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.
]]
local ffi = require("ffi")
ffi.cdef "void free(void *ptr);"
local libbcc = require("bcc.libbcc")
local Usdt = class("USDT")
Usdt.static.open_contexts = {}
function Usdt.static.cleanup()
for _, context in ipairs(Usdt.static.open_contexts) do
context:_cleanup()
end
end
function Usdt:initialize(args)
assert(args.pid or args.path)
if args.pid then
self.pid = args.pid
self.context = libbcc.bcc_usdt_new_frompid(args.pid)
elseif args.path then
self.path = args.path
self.context = libbcc.bcc_usdt_new_frompath(args.path)
end
assert(self.context ~= nil, "failed to create USDT context")
table.insert(Usdt.open_contexts, self)
end
function Usdt:enable_probe(args)
assert(args.probe and args.fn_name)
assert(libbcc.bcc_usdt_enable_probe(
self.context, args.probe, args.fn_name) == 0)
end
function Usdt:_cleanup()
libbcc.bcc_usdt_close(self.context)
self.context = nil
end
function Usdt:_get_text()
local argc = libbcc.bcc_usdt_genargs(self.context)
assert(argc ~= nil)
local text = ffi.string(argc)
ffi.C.free(argc)
return text
end
function Usdt:_attach_uprobes(bpf)
local uprobes = {}
local cb = ffi.cast("bcc_usdt_uprobe_cb",
function(binpath, fn_name, addr, pid)
table.insert(uprobes, {name=ffi.string(binpath),
addr=addr, fn_name=ffi.string(fn_name), pid=pid})
end)
libbcc.bcc_usdt_foreach_uprobe(self.context, cb)
cb:free()
for _, args in ipairs(uprobes) do
bpf:attach_uprobe(args)
end
end
return Usdt
...@@ -11,6 +11,7 @@ Module "bcc.sym" "bcc/sym.lua" ...@@ -11,6 +11,7 @@ Module "bcc.sym" "bcc/sym.lua"
Module "bcc.libbcc" "bcc/libbcc.lua" Module "bcc.libbcc" "bcc/libbcc.lua"
Module "bcc.tracerpipe" "bcc/tracerpipe.lua" Module "bcc.tracerpipe" "bcc/tracerpipe.lua"
Module "bcc.table" "bcc/table.lua" Module "bcc.table" "bcc/table.lua"
Module "bcc.usdt" "bcc/usdt.lua"
Main "bcc/run.lua" Main "bcc/run.lua"
Output "bcc.lua" Output "bcc.lua"
...@@ -39,8 +39,8 @@ TEST_CASE("test finding a probe in our own process", "[usdt]") { ...@@ -39,8 +39,8 @@ TEST_CASE("test finding a probe in our own process", "[usdt]") {
REQUIRE(ctx.num_probes() >= 1); REQUIRE(ctx.num_probes() >= 1);
SECTION("our test probe") { SECTION("our test probe") {
USDT::Probe *probe = ctx.find_probe("sample_probe_1"); auto probe = ctx.get("sample_probe_1");
REQUIRE(probe != nullptr); REQUIRE(probe);
REQUIRE(probe->in_shared_object() == false); REQUIRE(probe->in_shared_object() == false);
REQUIRE(probe->name() == "sample_probe_1"); REQUIRE(probe->name() == "sample_probe_1");
...@@ -52,13 +52,6 @@ TEST_CASE("test finding a probe in our own process", "[usdt]") { ...@@ -52,13 +52,6 @@ TEST_CASE("test finding a probe in our own process", "[usdt]") {
REQUIRE(probe->need_enable() == false); REQUIRE(probe->need_enable() == false);
REQUIRE(a_probed_function() != 0); 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 #endif // HAVE_SDT_HEADER
...@@ -115,8 +108,8 @@ TEST_CASE("test listing all USDT probes in Ruby/MRI", "[usdt]") { ...@@ -115,8 +108,8 @@ TEST_CASE("test listing all USDT probes in Ruby/MRI", "[usdt]") {
mri_probe_count = ctx.num_probes(); mri_probe_count = ctx.num_probes();
SECTION("GC static probe") { SECTION("GC static probe") {
USDT::Probe *probe = ctx.find_probe("gc__mark__begin"); auto probe = ctx.get("gc__mark__begin");
REQUIRE(probe != nullptr); REQUIRE(probe);
REQUIRE(probe->in_shared_object() == true); REQUIRE(probe->in_shared_object() == true);
REQUIRE(probe->name() == "gc__mark__begin"); REQUIRE(probe->name() == "gc__mark__begin");
...@@ -129,8 +122,8 @@ TEST_CASE("test listing all USDT probes in Ruby/MRI", "[usdt]") { ...@@ -129,8 +122,8 @@ TEST_CASE("test listing all USDT probes in Ruby/MRI", "[usdt]") {
} }
SECTION("object creation probe") { SECTION("object creation probe") {
USDT::Probe *probe = ctx.find_probe("object__create"); auto probe = ctx.get("object__create");
REQUIRE(probe != nullptr); REQUIRE(probe);
REQUIRE(probe->in_shared_object() == true); REQUIRE(probe->in_shared_object() == true);
REQUIRE(probe->name() == "object__create"); REQUIRE(probe->name() == "object__create");
...@@ -140,54 +133,16 @@ TEST_CASE("test listing all USDT probes in Ruby/MRI", "[usdt]") { ...@@ -140,54 +133,16 @@ TEST_CASE("test listing all USDT probes in Ruby/MRI", "[usdt]") {
REQUIRE(probe->num_locations() == 1); REQUIRE(probe->num_locations() == 1);
REQUIRE(probe->num_arguments() == 3); REQUIRE(probe->num_arguments() == 3);
REQUIRE(probe->need_enable() == true); 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") { SECTION("array creation probe") {
USDT::Probe *probe = ctx.find_probe("array__create"); auto probe = ctx.get("array__create");
REQUIRE(probe != nullptr); REQUIRE(probe);
REQUIRE(probe->name() == "array__create"); REQUIRE(probe->name() == "array__create");
REQUIRE(probe->num_locations() == 7); REQUIRE(probe->num_locations() == 7);
REQUIRE(probe->num_arguments() == 3); REQUIRE(probe->num_arguments() == 3);
REQUIRE(probe->need_enable() == true); 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);
} }
} }
...@@ -203,8 +158,8 @@ TEST_CASE("test listing all USDT probes in Ruby/MRI", "[usdt]") { ...@@ -203,8 +158,8 @@ TEST_CASE("test listing all USDT probes in Ruby/MRI", "[usdt]") {
REQUIRE(ctx.num_probes() >= mri_probe_count); REQUIRE(ctx.num_probes() >= mri_probe_count);
SECTION("get probe in running process") { SECTION("get probe in running process") {
USDT::Probe *probe = ctx.find_probe("gc__mark__begin"); auto probe = ctx.get("gc__mark__begin");
REQUIRE(probe != nullptr); REQUIRE(probe);
REQUIRE(probe->in_shared_object() == true); REQUIRE(probe->in_shared_object() == true);
REQUIRE(probe->name() == "gc__mark__begin"); REQUIRE(probe->name() == "gc__mark__begin");
......
...@@ -64,7 +64,7 @@ int count(struct pt_regs *ctx) { ...@@ -64,7 +64,7 @@ int count(struct pt_regs *ctx) {
end end
function TestUprobes:teardown() function TestUprobes:teardown()
BPF.cleanup_probes() BPF.cleanup()
end end
suite("TestUprobes", TestUprobes) suite("TestUprobes", TestUprobes)
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