Use device+inode to identify matching files; prepend /proc/pid/root to
paths for usdt.
diff --git a/examples/cpp/pyperf/PyPerfUtil.cc b/examples/cpp/pyperf/PyPerfUtil.cc
index 252a0fe..b1495bb 100644
--- a/examples/cpp/pyperf/PyPerfUtil.cc
+++ b/examples/cpp/pyperf/PyPerfUtil.cc
@@ -93,20 +93,19 @@
const static std::string kPy36LibName = "libpython3.6";
-int findPythonPathCallback(const char* name, uint64_t st, uint64_t en, uint64_t,
- bool, void* payload) {
+int findPythonPathCallback(mod_info *mod, int, void* payload) {
auto helper = static_cast<FindPythonPathHelper*>(payload);
- std::string file = name;
+ std::string file = mod->name;
auto pos = file.rfind("/");
if (pos != std::string::npos) {
file = file.substr(pos + 1);
}
if (file.find(kPy36LibName) == 0) {
- logInfo(1, "Found Python library %s loaded at %lx-%lx for PID %d\n", name,
- st, en, helper->pid);
+ logInfo(1, "Found Python library %s loaded at %lx-%lx for PID %d\n", mod->name,
+ mod->start_addr, mod->end_addr, helper->pid);
helper->found = true;
- helper->st = st;
- helper->en = en;
+ helper->st = mod->start_addr;
+ helper->en = mod->end_addr;
return -1;
}
return 0;
diff --git a/src/cc/CMakeLists.txt b/src/cc/CMakeLists.txt
index bd34fd4..571a463 100644
--- a/src/cc/CMakeLists.txt
+++ b/src/cc/CMakeLists.txt
@@ -47,11 +47,11 @@
endif()
set(bcc_table_sources table_storage.cc shared_table.cc bpffs_table.cc json_map_decl_visitor.cc)
-set(bcc_util_sources ns_guard.cc common.cc)
+set(bcc_util_sources common.cc)
set(bcc_sym_sources bcc_syms.cc bcc_elf.c bcc_perf_map.c bcc_proc.c)
set(bcc_common_headers libbpf.h perf_reader.h)
set(bcc_table_headers file_desc.h table_desc.h table_storage.h)
-set(bcc_api_headers bcc_common.h bpf_module.h bcc_exception.h bcc_syms.h bcc_elf.h)
+set(bcc_api_headers bcc_common.h bpf_module.h bcc_exception.h bcc_syms.h bcc_proc.h bcc_elf.h)
if(ENABLE_CLANG_JIT)
add_library(bcc-shared SHARED
diff --git a/src/cc/api/BPF.cc b/src/cc/api/BPF.cc
index db2436d..b5aa52b 100644
--- a/src/cc/api/BPF.cc
+++ b/src/cc/api/BPF.cc
@@ -740,7 +740,8 @@
pid_(-1),
provider_(provider),
name_(name),
- probe_func_(probe_func) {}
+ probe_func_(probe_func),
+ mod_match_inode_only_(0) {}
USDT::USDT(pid_t pid, const std::string& provider, const std::string& name,
const std::string& probe_func)
@@ -749,7 +750,8 @@
pid_(pid),
provider_(provider),
name_(name),
- probe_func_(probe_func) {}
+ probe_func_(probe_func),
+ mod_match_inode_only_(0) {}
USDT::USDT(const std::string& binary_path, pid_t pid,
const std::string& provider, const std::string& name,
@@ -759,7 +761,8 @@
pid_(pid),
provider_(provider),
name_(name),
- probe_func_(probe_func) {}
+ probe_func_(probe_func),
+ mod_match_inode_only_(0) {}
USDT::USDT(const USDT& usdt)
: initialized_(false),
@@ -767,7 +770,8 @@
pid_(usdt.pid_),
provider_(usdt.provider_),
name_(usdt.name_),
- probe_func_(usdt.probe_func_) {}
+ probe_func_(usdt.probe_func_),
+ mod_match_inode_only_(usdt.mod_match_inode_only_) {}
USDT::USDT(USDT&& usdt) noexcept
: initialized_(usdt.initialized_),
@@ -777,7 +781,8 @@
name_(std::move(usdt.name_)),
probe_func_(std::move(usdt.probe_func_)),
probe_(std::move(usdt.probe_)),
- program_text_(std::move(usdt.program_text_)) {
+ program_text_(std::move(usdt.program_text_)),
+ mod_match_inode_only_(usdt.mod_match_inode_only_) {
usdt.initialized_ = false;
}
@@ -787,14 +792,22 @@
(probe_func_ == other.probe_func_);
}
+int USDT::set_probe_matching_kludge(uint8_t kludge) {
+ if (kludge != 0 && kludge != 1)
+ return -1;
+
+ mod_match_inode_only_ = kludge;
+ return 0;
+}
+
StatusTuple USDT::init() {
std::unique_ptr<::USDT::Context> ctx;
if (!binary_path_.empty() && pid_ > 0)
- ctx.reset(new ::USDT::Context(pid_, binary_path_));
+ ctx.reset(new ::USDT::Context(pid_, binary_path_, mod_match_inode_only_));
else if (!binary_path_.empty())
- ctx.reset(new ::USDT::Context(binary_path_));
+ ctx.reset(new ::USDT::Context(binary_path_, mod_match_inode_only_));
else if (pid_ > 0)
- ctx.reset(new ::USDT::Context(pid_));
+ ctx.reset(new ::USDT::Context(pid_, mod_match_inode_only_));
else
return StatusTuple(-1, "No valid Binary Path or PID provided");
diff --git a/src/cc/api/BPF.h b/src/cc/api/BPF.h
index 4b26088..9c0ab19 100644
--- a/src/cc/api/BPF.h
+++ b/src/cc/api/BPF.h
@@ -287,6 +287,19 @@
<< usdt.probe_func_;
}
+ // When the kludge flag is set to 1, we will only match on inode
+ // when searching for modules in /proc/PID/maps that might contain the
+ // tracepoint we're looking for. Normally match is on inode and
+ // (dev_major, dev_minor), which is a more accurate way to uniquely
+ // identify a file.
+ //
+ // This hack exists because btrfs reports different device numbers for files
+ // in /proc/PID/maps vs stat syscall. Don't use it unless you're using btrfs
+ //
+ // set_probe_matching_kludge(1) must be called before USDTs are submitted to
+ // BPF::init()
+ int set_probe_matching_kludge(uint8_t kludge);
+
private:
bool initialized_;
@@ -300,6 +313,8 @@
std::unique_ptr<void, std::function<void(void*)>> probe_;
std::string program_text_;
+ uint8_t mod_match_inode_only_;
+
friend class BPF;
};
diff --git a/src/cc/bcc_elf.c b/src/cc/bcc_elf.c
index ba8fa1d..b9d25d8 100644
--- a/src/cc/bcc_elf.c
+++ b/src/cc/bcc_elf.c
@@ -684,17 +684,17 @@
// >0: Initialized
static int vdso_image_fd = -1;
-static int find_vdso(const char *name, uint64_t st, uint64_t en,
- uint64_t offset, bool enter_ns, void *payload) {
+static int find_vdso(struct mod_info *info, int enter_ns, void *payload) {
int fd;
char tmpfile[128];
- if (!bcc_elf_is_vdso(name))
+ if (!bcc_elf_is_vdso(info->name))
return 0;
- void *image = malloc(en - st);
+ uint64_t sz = info->end_addr - info->start_addr;
+ void *image = malloc(sz);
if (!image)
goto on_error;
- memcpy(image, (void *)st, en - st);
+ memcpy(image, (void *)info->start_addr, sz);
snprintf(tmpfile, sizeof(tmpfile), "/tmp/bcc_%d_vdso_image_XXXXXX", getpid());
fd = mkostemp(tmpfile, O_CLOEXEC);
@@ -706,7 +706,7 @@
if (unlink(tmpfile) == -1)
fprintf(stderr, "Unlink %s failed: %s\n", tmpfile, strerror(errno));
- if (write(fd, image, en - st) == -1) {
+ if (write(fd, image, sz) == -1) {
fprintf(stderr, "Failed to write to vDSO image: %s\n", strerror(errno));
close(fd);
goto on_error;
diff --git a/src/cc/bcc_proc.c b/src/cc/bcc_proc.c
index 6ce63de..c8f4041 100644
--- a/src/cc/bcc_proc.c
+++ b/src/cc/bcc_proc.c
@@ -121,6 +121,50 @@
return path;
}
+// return: 0 -> callback returned < 0, stopped iterating
+// -1 -> callback never indicated to stop
+int _procfs_maps_each_module(FILE *procmap, int pid,
+ bcc_procutils_modulecb callback, void *payload) {
+ char buf[PATH_MAX + 1], perm[5];
+ char *name;
+ mod_info mod;
+ uint8_t enter_ns;
+ while (true) {
+ enter_ns = 1;
+ buf[0] = '\0';
+ // From fs/proc/task_mmu.c:show_map_vma
+ if (fscanf(procmap, "%lx-%lx %4s %llx %lx:%lx %lu%[^\n]",
+ &mod.start_addr, &mod.end_addr, perm, &mod.file_offset,
+ &mod.dev_major, &mod.dev_minor, &mod.inode, buf) != 8)
+ break;
+
+ if (perm[2] != 'x')
+ continue;
+
+ name = buf;
+ while (isspace(*name))
+ name++;
+ mod.name = name;
+ if (!bcc_mapping_is_file_backed(name))
+ continue;
+
+ if (strstr(name, "/memfd:")) {
+ char *memfd_name = _procutils_memfd_path(pid, mod.inode);
+ if (memfd_name != NULL) {
+ strcpy(buf, memfd_name);
+ free(memfd_name);
+ mod.name = buf;
+ enter_ns = 0;
+ }
+ }
+
+ if (callback(&mod, enter_ns, payload) < 0)
+ return 0;
+ }
+
+ return -1;
+}
+
int bcc_procutils_each_module(int pid, bcc_procutils_modulecb callback,
void *payload) {
char procmap_filename[128];
@@ -131,56 +175,34 @@
if (!procmap)
return -1;
- char buf[PATH_MAX + 1], perm[5], dev[8];
- char *name;
- uint64_t begin, end, inode;
- unsigned long long offset;
- while (true) {
- buf[0] = '\0';
- // From fs/proc/task_mmu.c:show_map_vma
- if (fscanf(procmap, "%lx-%lx %4s %llx %7s %lu%[^\n]", &begin, &end, perm,
- &offset, dev, &inode, buf) != 7)
- break;
-
- if (perm[2] != 'x')
- continue;
-
- name = buf;
- while (isspace(*name))
- name++;
- if (!bcc_mapping_is_file_backed(name))
- continue;
-
- if (strstr(name, "/memfd:")) {
- char *memfd_name = _procutils_memfd_path(pid, inode);
- if (memfd_name != NULL) {
- strcpy(buf, memfd_name);
- free(memfd_name);
- name = buf;
- }
- }
-
- if (callback(name, begin, end, (uint64_t)offset, true, payload) < 0)
- break;
- }
-
- fclose(procmap);
+ _procfs_maps_each_module(procmap, pid, callback, payload);
// Address mapping for the entire address space maybe in /tmp/perf-<PID>.map
// This will be used if symbols aren't resolved in an earlier mapping.
char map_path[4096];
// Try perf-<PID>.map path with process's mount namespace, chroot and NSPID,
// in case it is generated by the process itself.
- if (bcc_perf_map_path(map_path, sizeof(map_path), pid))
- if (callback(map_path, 0, -1, 0, true, payload) < 0)
- return 0;
+ mod_info mod;
+ memset(&mod, 0, sizeof(mod_info));
+ if (bcc_perf_map_path(map_path, sizeof(map_path), pid)) {
+ mod.name = map_path;
+ mod.end_addr = -1;
+ if (callback(&mod, 1, payload) < 0)
+ goto done;
+ }
// Try perf-<PID>.map path with global root and PID, in case it is generated
// by other Process. Avoid checking mount namespace for this.
+ memset(&mod, 0, sizeof(mod_info));
int res = snprintf(map_path, 4096, "/tmp/perf-%d.map", pid);
- if (res > 0 && res < 4096)
- if (callback(map_path, 0, -1, 0, false, payload) < 0)
- return 0;
+ if (res > 0 && res < 4096) {
+ mod.name = map_path;
+ mod.end_addr = -1;
+ if (callback(&mod, 0, payload) < 0)
+ goto done;
+ }
+done:
+ fclose(procmap);
return 0;
}
diff --git a/src/cc/bcc_proc.h b/src/cc/bcc_proc.h
index 1e5a720..a56f680 100644
--- a/src/cc/bcc_proc.h
+++ b/src/cc/bcc_proc.h
@@ -23,13 +23,24 @@
#endif
#include <stdint.h>
+#include <stdio.h>
#include <stdbool.h>
-// Module name, start address, end address, file_offset,
-// whether to check mount namespace, payload
+
+typedef struct mod_info {
+ char *name;
+ uint64_t start_addr;
+ uint64_t end_addr;
+ long long unsigned int file_offset;
+ uint64_t dev_major;
+ uint64_t dev_minor;
+ uint64_t inode;
+} mod_info;
+
+// Module info, whether to check mount namespace, payload
// Callback returning a negative value indicates to stop the iteration
-typedef int (*bcc_procutils_modulecb)(const char *, uint64_t, uint64_t,
- uint64_t, bool, void *);
+typedef int (*bcc_procutils_modulecb)(mod_info *, int, void *);
+
// Symbol name, address, payload
typedef void (*bcc_procutils_ksymcb)(const char *, uint64_t, void *);
@@ -42,6 +53,9 @@
// Returns -1 on error, and 0 on success
int bcc_procutils_each_module(int pid, bcc_procutils_modulecb callback,
void *payload);
+
+int _procfs_maps_each_module(FILE *procmaps, int pid,
+ bcc_procutils_modulecb callback, void *payload);
// Iterate over all non-data Kernel symbols.
// Returns -1 on error, and 0 on success
int bcc_procutils_each_ksym(bcc_procutils_ksymcb callback, void *payload);
diff --git a/src/cc/bcc_syms.cc b/src/cc/bcc_syms.cc
index 96d431e..9fea636 100644
--- a/src/cc/bcc_syms.cc
+++ b/src/cc/bcc_syms.cc
@@ -20,6 +20,7 @@
#include <linux/elf.h>
#include <string.h>
#include <sys/stat.h>
+#include <sys/sysmacros.h>
#include <sys/types.h>
#include <unistd.h>
#include <cstdio>
@@ -102,7 +103,7 @@
}
ProcSyms::ProcSyms(int pid, struct bcc_symbol_option *option)
- : pid_(pid), procstat_(pid), mount_ns_instance_(new ProcMountNS(pid_)) {
+ : pid_(pid), procstat_(pid) {
if (option)
std::memcpy(&symbol_option_, option, sizeof(bcc_symbol_option));
else
@@ -122,9 +123,8 @@
}
void ProcSyms::load_exe() {
- ProcMountNSGuard g(mount_ns_instance_.get());
std::string exe = ebpf::get_pid_exe(pid_);
- Module module(exe.c_str(), mount_ns_instance_.get(), &symbol_option_);
+ Module module(exe.c_str(), exe.c_str(), &symbol_option_);
if (module.type_ != ModuleType::EXEC)
return;
@@ -143,35 +143,33 @@
void ProcSyms::refresh() {
modules_.clear();
- mount_ns_instance_.reset(new ProcMountNS(pid_));
load_modules();
procstat_.reset();
}
-int ProcSyms::_add_module(const char *modname, uint64_t start, uint64_t end,
- uint64_t offset, bool check_mount_ns, void *payload) {
+int ProcSyms::_add_module(mod_info *mod, int enter_ns, void *payload) {
ProcSyms *ps = static_cast<ProcSyms *>(payload);
+ std::string ns_relative_path = tfm::format("/proc/%d/root%s", ps->pid_, mod->name);
+ const char *modpath = enter_ns && ps->pid_ != -1 ? ns_relative_path.c_str() : mod->name;
auto it = std::find_if(
ps->modules_.begin(), ps->modules_.end(),
- [=](const ProcSyms::Module &m) { return m.name_ == modname; });
+ [=](const ProcSyms::Module &m) { return m.name_ == mod->name; });
if (it == ps->modules_.end()) {
auto module = Module(
- modname, check_mount_ns ? ps->mount_ns_instance_.get() : nullptr,
- &ps->symbol_option_);
+ mod->name, modpath, &ps->symbol_option_);
// pid/maps doesn't account for file_offset of text within the ELF.
// It only gives the mmap offset. We need the real offset for symbol
// lookup.
if (module.type_ == ModuleType::SO) {
- ProcMountNSGuard g(ps->mount_ns_instance_.get());
- if (bcc_elf_get_text_scn_info(modname, &module.elf_so_addr_,
+ if (bcc_elf_get_text_scn_info(modpath, &module.elf_so_addr_,
&module.elf_so_offset_) < 0) {
- fprintf(stderr, "WARNING: Couldn't find .text section in %s\n", modname);
- fprintf(stderr, "WARNING: BCC can't handle sym look ups for %s", modname);
+ fprintf(stderr, "WARNING: Couldn't find .text section in %s\n", modpath);
+ fprintf(stderr, "WARNING: BCC can't handle sym look ups for %s", modpath);
}
}
- if (!bcc_is_perf_map(modname) || module.type_ != ModuleType::UNKNOWN)
+ if (!bcc_is_perf_map(modpath) || module.type_ != ModuleType::UNKNOWN)
// Always add the module even if we can't read it, so that we could
// report correct module name. Unless it's a perf map that we only
// add readable ones.
@@ -179,7 +177,7 @@
else
return 0;
}
- it->ranges_.emplace_back(start, end, offset);
+ it->ranges_.emplace_back(mod->start_addr, mod->end_addr, mod->file_offset);
// perf-PID map is added last. We try both inside the Process's mount
// namespace + chroot, and in global /tmp. Make sure we only add one.
if (it->type_ == ModuleType::PERF_MAP)
@@ -242,15 +240,14 @@
return false;
}
-ProcSyms::Module::Module(const char *name, ProcMountNS *mount_ns,
- struct bcc_symbol_option *option)
+ProcSyms::Module::Module(const char *name, const char *path,
+ struct bcc_symbol_option *option)
: name_(name),
+ path_(path),
loaded_(false),
- mount_ns_(mount_ns),
symbol_option_(option),
type_(ModuleType::UNKNOWN) {
- ProcMountNSGuard g(mount_ns_);
- int elf_type = bcc_elf_get_type(name_.c_str());
+ int elf_type = bcc_elf_get_type(path_.c_str());
// The Module is an ELF file
if (elf_type >= 0) {
if (elf_type == ET_EXEC)
@@ -260,9 +257,9 @@
return;
}
// Other symbol files
- if (bcc_is_valid_perf_map(name_.c_str()) == 1)
+ if (bcc_is_valid_perf_map(path_.c_str()) == 1)
type_ = ModuleType::PERF_MAP;
- else if (bcc_elf_is_vdso(name_.c_str()) == 1)
+ else if (bcc_elf_is_vdso(path_.c_str()) == 1)
type_ = ModuleType::VDSO;
// Will be stored later
@@ -286,12 +283,10 @@
if (type_ == ModuleType::UNKNOWN)
return;
- ProcMountNSGuard g(mount_ns_);
-
if (type_ == ModuleType::PERF_MAP)
- bcc_perf_map_foreach_sym(name_.c_str(), _add_symbol, this);
+ bcc_perf_map_foreach_sym(path_.c_str(), _add_symbol, this);
if (type_ == ModuleType::EXEC || type_ == ModuleType::SO)
- bcc_elf_foreach_sym(name_.c_str(), _add_symbol, symbol_option_, this);
+ bcc_elf_foreach_sym(path_.c_str(), _add_symbol, symbol_option_, this);
if (type_ == ModuleType::VDSO)
bcc_elf_foreach_vdso_sym(_add_symbol, this);
@@ -547,27 +542,60 @@
return bsym->resolve_addr(build_id, trace->offset, sym) ? 0 : -1;
}
-struct mod_st {
+struct mod_search {
const char *name;
+ uint64_t inode;
+ uint64_t dev_major;
+ uint64_t dev_minor;
+ uint64_t addr;
+ uint8_t inode_match_only;
+
uint64_t start;
uint64_t file_offset;
};
-static int _find_module(const char *modname, uint64_t start, uint64_t end,
- uint64_t offset, bool, void *p) {
- struct mod_st *mod = (struct mod_st *)p;
- if (!strcmp(modname, mod->name)) {
- mod->start = start;
- mod->file_offset = offset;
- return -1;
+int _bcc_syms_find_module(mod_info *info, int enter_ns, void *p) {
+ struct mod_search *mod = (struct mod_search *)p;
+ // use inode + dev to determine match if inode set
+ if (mod->inode) {
+ if (mod->inode != info->inode)
+ return 0;
+
+ // look at comment on USDT::set_probe_matching_kludge
+ // in api/BPF.h for explanation of why this might be
+ // necessary
+ if (mod->inode_match_only)
+ goto file_match;
+
+ if(mod->dev_major == info->dev_major
+ && mod->dev_minor == info->dev_minor)
+ goto file_match;
+
+ return 0;
}
+
+ // fallback to name match
+ if (!strcmp(info->name, mod->name))
+ goto file_match;
+
return 0;
+
+file_match:
+ mod->start = info->start_addr;
+ mod->file_offset = info->file_offset;
+ return -1;
}
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 ||
+ uint8_t inode_match_only, uint64_t *global) {
+ struct stat s;
+ if (stat(module, &s))
+ return -1;
+
+ struct mod_search mod = {module, s.st_ino, major(s.st_dev), minor(s.st_dev),
+ address, inode_match_only,
+ 0x0, 0x0};
+ if (bcc_procutils_each_module(pid, _bcc_syms_find_module, &mod) < 0 ||
mod.start == 0x0)
return -1;
@@ -645,8 +673,11 @@
}
if (sym->module == NULL)
return -1;
-
- ProcMountNSGuard g(pid);
+ if (pid != 0 && pid != -1) {
+ char *temp = (char*)sym->module;
+ sym->module = strdup(tfm::format("/proc/%d/root%s", pid, sym->module).c_str());
+ free(temp);
+ }
sym->name = symname;
sym->offset = addr;
diff --git a/src/cc/bcc_syms.h b/src/cc/bcc_syms.h
index c213f10..12b3cfa 100644
--- a/src/cc/bcc_syms.h
+++ b/src/cc/bcc_syms.h
@@ -22,6 +22,7 @@
#include <stdint.h>
#include "linux/bpf.h"
+#include "bcc_proc.h"
struct bcc_symbol {
const char *name;
@@ -65,8 +66,9 @@
const char *name, uint64_t *addr);
void bcc_symcache_refresh(void *resolver);
+int _bcc_syms_find_module(struct mod_info *info, int enter_ns, void *p);
int bcc_resolve_global_addr(int pid, const char *module, const uint64_t address,
- uint64_t *global);
+ uint8_t inode_match_only, uint64_t *global);
/*bcc APIs for build_id stackmap support*/
void *bcc_buildsymcache_new(void);
diff --git a/src/cc/libbpf.c b/src/cc/libbpf.c
index 5de772b..9054bef 100644
--- a/src/cc/libbpf.c
+++ b/src/cc/libbpf.c
@@ -941,7 +941,7 @@
const char *event_type, pid_t pid, int maxactive)
{
int kfd = -1, res = -1, ns_fd = -1;
- char ev_alias[128];
+ char ev_alias[256];
bool is_kprobe = strncmp("kprobe", event_type, 6) == 0;
snprintf(buf, PATH_MAX, "/sys/kernel/debug/tracing/%s_events", event_type);
diff --git a/src/cc/ns_guard.cc b/src/cc/ns_guard.cc
deleted file mode 100644
index c5baf5a..0000000
--- a/src/cc/ns_guard.cc
+++ /dev/null
@@ -1,77 +0,0 @@
-/*
- * Copyright (c) 2017 Facebook, Inc.
- * Copyright (c) 2017 VMware, 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 <fcntl.h>
-#include <sched.h>
-#include <sys/stat.h>
-#include <string>
-
-#include "ns_guard.h"
-
-// TODO: Remove this when CentOS 6 support is not needed anymore
-#include "setns.h"
-
-ProcMountNS::ProcMountNS(int pid) : target_ino_(0) {
- if (pid < 0)
- return;
-
- std::string target_path = "/proc/" + std::to_string(pid) + "/ns/mnt";
- ebpf::FileDesc target_fd(open(target_path.c_str(), O_RDONLY));
- ebpf::FileDesc self_fd(open("/proc/self/ns/mnt", O_RDONLY));
-
- if (self_fd < 0 || target_fd < 0)
- return;
-
- struct stat self_stat, target_stat;
- if (fstat(self_fd, &self_stat) != 0)
- return;
- if (fstat(target_fd, &target_stat) != 0)
- return;
-
- target_ino_ = target_stat.st_ino;
- if (self_stat.st_ino == target_stat.st_ino)
- // Both current and target Process are in same mount namespace
- return;
-
- self_fd_ = std::move(self_fd);
- target_fd_ = std::move(target_fd);
-}
-
-ProcMountNSGuard::ProcMountNSGuard(ProcMountNS *mount_ns)
- : mount_ns_instance_(nullptr), mount_ns_(mount_ns), entered_(false) {
- init();
-}
-
-ProcMountNSGuard::ProcMountNSGuard(int pid)
- : mount_ns_instance_(pid > 0 ? new ProcMountNS(pid) : nullptr),
- mount_ns_(mount_ns_instance_.get()),
- entered_(false) {
- init();
-}
-
-void ProcMountNSGuard::init() {
- if (!mount_ns_ || mount_ns_->self() < 0 || mount_ns_->target() < 0)
- return;
-
- if (setns(mount_ns_->target(), CLONE_NEWNS) == 0)
- entered_ = true;
-}
-
-ProcMountNSGuard::~ProcMountNSGuard() {
- if (mount_ns_ && entered_ && mount_ns_->self() >= 0)
- setns(mount_ns_->self(), CLONE_NEWNS);
-}
diff --git a/src/cc/ns_guard.h b/src/cc/ns_guard.h
deleted file mode 100644
index ce4b61b..0000000
--- a/src/cc/ns_guard.h
+++ /dev/null
@@ -1,59 +0,0 @@
-/*
- * Copyright (c) 2017 Facebook, Inc.
- * Copyright (c) 2017 VMware, 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.
- */
-
-#pragma once
-
-#include <memory>
-#include <sys/types.h>
-
-#include "file_desc.h"
-
-class ProcMountNSGuard;
-
-// ProcMountNS opens an fd corresponding to the current mount namespace and the
-// mount namespace of the target process.
-// The fds will remain uninitialized (<0) if the open fails, or if the current
-// and target namespaces are identical.
-class ProcMountNS {
- public:
- explicit ProcMountNS(int pid);
- int self() const { return self_fd_; }
- int target() const { return target_fd_; }
- ino_t target_ino() const { return target_ino_; }
-
- private:
- ebpf::FileDesc self_fd_;
- ebpf::FileDesc target_fd_;
- ino_t target_ino_;
-};
-
-// ProcMountNSGuard switches to the target mount namespace and restores the
-// original upon going out of scope.
-class ProcMountNSGuard {
- public:
- explicit ProcMountNSGuard(ProcMountNS *mount_ns);
- explicit ProcMountNSGuard(int pid);
-
- ~ProcMountNSGuard();
-
- private:
- void init();
-
- std::unique_ptr<ProcMountNS> mount_ns_instance_;
- ProcMountNS *mount_ns_;
- bool entered_;
-};
diff --git a/src/cc/syms.h b/src/cc/syms.h
index b533741..ac7e8fb 100644
--- a/src/cc/syms.h
+++ b/src/cc/syms.h
@@ -23,9 +23,9 @@
#include <unordered_set>
#include <vector>
+#include "bcc_proc.h"
#include "bcc_syms.h"
#include "file_desc.h"
-#include "ns_guard.h"
class ProcStat {
std::string procfs_;
@@ -98,13 +98,12 @@
: start(s), end(e), file_offset(f) {}
};
- Module(const char *name, ProcMountNS *mount_ns,
- struct bcc_symbol_option *option);
+ Module(const char *name, const char *path, struct bcc_symbol_option *option);
std::string name_;
+ std::string path_;
std::vector<Range> ranges_;
bool loaded_;
- ProcMountNS *mount_ns_;
bcc_symbol_option *symbol_option_;
ModuleType type_;
@@ -130,13 +129,11 @@
int pid_;
std::vector<Module> modules_;
ProcStat procstat_;
- std::unique_ptr<ProcMountNS> mount_ns_instance_;
bcc_symbol_option symbol_option_;
static int _add_load_sections(uint64_t v_addr, uint64_t mem_sz,
uint64_t file_offset, void *payload);
- static int _add_module(const char *, uint64_t, uint64_t, uint64_t, bool,
- void *);
+ static int _add_module(mod_info *, int, void *);
void load_exe();
void load_modules();
diff --git a/src/cc/usdt.h b/src/cc/usdt.h
index f1dac48..428bc35 100644
--- a/src/cc/usdt.h
+++ b/src/cc/usdt.h
@@ -20,7 +20,7 @@
#include <unordered_map>
#include <vector>
-#include "ns_guard.h"
+#include "bcc_proc.h"
#include "syms.h"
#include "vendor/optional.hpp"
@@ -196,11 +196,11 @@
std::vector<Location> locations_;
optional<int> pid_;
- ProcMountNS *mount_ns_;
std::unordered_map<std::string, bool> object_type_map_; // bin_path => is shared lib?
optional<std::string> attached_to_;
optional<uint64_t> attached_semaphore_;
+ uint8_t mod_match_inode_only_;
std::string largest_arg_type(size_t arg_n);
@@ -212,7 +212,7 @@
public:
Probe(const char *bin_path, const char *provider, const char *name,
- uint64_t semaphore, const optional<int> &pid, ProcMountNS *ns);
+ uint64_t semaphore, const optional<int> &pid, uint8_t mod_match_inode_only = 0);
size_t num_locations() const { return locations_.size(); }
size_t num_arguments() const { return locations_.front().arguments_.size(); }
@@ -251,29 +251,30 @@
optional<int> pid_;
optional<ProcStat> pid_stat_;
- std::unique_ptr<ProcMountNS> mount_ns_instance_;
std::string cmd_bin_path_;
bool loaded_;
static void _each_probe(const char *binpath, const struct bcc_elf_usdt *probe,
void *p);
- static int _each_module(const char *modpath, uint64_t, uint64_t, uint64_t,
- bool, void *p);
+ static int _each_module(mod_info *, int enter_ns, void *p);
void add_probe(const char *binpath, const struct bcc_elf_usdt *probe);
std::string resolve_bin_path(const std::string &bin_path);
+private:
+ uint8_t mod_match_inode_only_;
+
public:
- Context(const std::string &bin_path);
- Context(int pid);
- Context(int pid, const std::string &bin_path);
+ Context(const std::string &bin_path, uint8_t mod_match_inode_only = 0);
+ Context(int pid, uint8_t mod_match_inode_only = 0);
+ Context(int pid, const std::string &bin_path,
+ uint8_t mod_match_inode_only = 0);
~Context();
optional<int> pid() const { return pid_; }
bool loaded() const { return loaded_; }
size_t num_probes() const { return probes_.size(); }
const std::string & cmd_bin_path() const { return cmd_bin_path_; }
- ino_t inode() const { return mount_ns_instance_->target_ino(); }
Probe *get(const std::string &probe_name);
Probe *get(const std::string &provider_name, const std::string &probe_name);
diff --git a/src/cc/usdt/usdt.cc b/src/cc/usdt/usdt.cc
index 09b204e..ab51cb5 100644
--- a/src/cc/usdt/usdt.cc
+++ b/src/cc/usdt/usdt.cc
@@ -54,17 +54,18 @@
}
Probe::Probe(const char *bin_path, const char *provider, const char *name,
- uint64_t semaphore, const optional<int> &pid, ProcMountNS *ns)
+ uint64_t semaphore, const optional<int> &pid,
+ uint8_t mod_match_inode_only)
: bin_path_(bin_path),
provider_(provider),
name_(name),
semaphore_(semaphore),
pid_(pid),
- mount_ns_(ns) {}
+ mod_match_inode_only_(mod_match_inode_only)
+ {}
bool Probe::in_shared_object(const std::string &bin_path) {
if (object_type_map_.find(bin_path) == object_type_map_.end()) {
- ProcMountNSGuard g(mount_ns_);
return (object_type_map_[bin_path] = bcc_elf_is_shared_obj(bin_path.c_str()));
}
return object_type_map_[bin_path];
@@ -74,7 +75,7 @@
const uint64_t addr) {
if (in_shared_object(bin_path)) {
return (pid_ &&
- !bcc_resolve_global_addr(*pid_, bin_path.c_str(), addr, global));
+ !bcc_resolve_global_addr(*pid_, bin_path.c_str(), addr, mod_match_inode_only_, global));
}
*global = addr;
@@ -235,15 +236,19 @@
ctx->add_probe(binpath, probe);
}
-int Context::_each_module(const char *modpath, uint64_t, uint64_t, uint64_t,
- bool, void *p) {
+int Context::_each_module(mod_info *mod, int enter_ns, void *p) {
Context *ctx = static_cast<Context *>(p);
+
+ std::string path = mod->name;
+ if (ctx->pid_ && *ctx->pid_ != -1 && enter_ns) {
+ path = tfm::format("/proc/%d/root%s", *ctx->pid_, path);
+ }
+
// Modules may be reported multiple times if they contain more than one
// executable region. We are going to parse the ELF on disk anyway, so we
// don't need these duplicates.
- if (ctx->modules_.insert(modpath).second /*inserted new?*/) {
- ProcMountNSGuard g(ctx->mount_ns_instance_.get());
- bcc_elf_foreach_usdt(modpath, _each_probe, p);
+ if (ctx->modules_.insert(path).second /*inserted new?*/) {
+ bcc_elf_foreach_usdt(path.c_str(), _each_probe, p);
}
return 0;
}
@@ -257,8 +262,9 @@
}
probes_.emplace_back(
- new Probe(binpath, probe->provider, probe->name, probe->semaphore, pid_,
- mount_ns_instance_.get()));
+ new Probe(binpath, probe->provider, probe->name, probe->semaphore, pid_,
+ mod_match_inode_only_)
+ );
probes_.back()->add_location(probe->pc, binpath, probe->arg_fmt);
}
@@ -273,6 +279,10 @@
::free(which_so);
}
+ if (!result.empty() && pid_ && *pid_ != -1) {
+ result = tfm::format("/proc/%d/root%s", *pid_, result);
+ }
+
return result;
}
@@ -348,8 +358,8 @@
}
}
-Context::Context(const std::string &bin_path)
- : mount_ns_instance_(new ProcMountNS(-1)), loaded_(false) {
+Context::Context(const std::string &bin_path, uint8_t mod_match_inode_only)
+ : loaded_(false), mod_match_inode_only_(mod_match_inode_only) {
std::string full_path = resolve_bin_path(bin_path);
if (!full_path.empty()) {
if (bcc_elf_foreach_usdt(full_path.c_str(), _each_probe, this) == 0) {
@@ -361,8 +371,9 @@
probe->finalize_locations();
}
-Context::Context(int pid) : pid_(pid), pid_stat_(pid),
- mount_ns_instance_(new ProcMountNS(pid)), loaded_(false) {
+Context::Context(int pid, uint8_t mod_match_inode_only)
+ : pid_(pid), pid_stat_(pid), loaded_(false),
+ mod_match_inode_only_(mod_match_inode_only) {
if (bcc_procutils_each_module(pid, _each_module, this) == 0) {
cmd_bin_path_ = ebpf::get_pid_exe(pid);
if (cmd_bin_path_.empty())
@@ -374,16 +385,13 @@
probe->finalize_locations();
}
-Context::Context(int pid, const std::string &bin_path)
- : pid_(pid), pid_stat_(pid),
- mount_ns_instance_(new ProcMountNS(pid)), loaded_(false) {
+Context::Context(int pid, const std::string &bin_path,
+ uint8_t mod_match_inode_only)
+ : pid_(pid), pid_stat_(pid), loaded_(false),
+ mod_match_inode_only_(mod_match_inode_only) {
std::string full_path = resolve_bin_path(bin_path);
if (!full_path.empty()) {
- int res;
- {
- ProcMountNSGuard g(mount_ns_instance_.get());
- res = bcc_elf_foreach_usdt(full_path.c_str(), _each_probe, this);
- }
+ int res = bcc_elf_foreach_usdt(full_path.c_str(), _each_probe, this);
if (res == 0) {
cmd_bin_path_ = ebpf::get_pid_exe(pid);
if (cmd_bin_path_.empty())
@@ -410,16 +418,13 @@
if (!path) {
ctx = new USDT::Context(pid);
} else {
- {
- ProcMountNSGuard g(new ProcMountNS(pid));
- struct stat buffer;
- if (strlen(path) >= 1 && path[0] != '/') {
- fprintf(stderr, "HINT: Binary path should be absolute.\n\n");
- return nullptr;
- } else if (stat(path, &buffer) == -1) {
- fprintf(stderr, "HINT: Specified binary doesn't exist.\n\n");
- return nullptr;
- }
+ struct stat buffer;
+ if (strlen(path) >= 1 && path[0] != '/') {
+ fprintf(stderr, "HINT: Binary path should be absolute.\n\n");
+ return nullptr;
+ } else if (stat(path, &buffer) == -1) {
+ fprintf(stderr, "HINT: Specified binary doesn't exist.\n\n");
+ return nullptr;
}
ctx = new USDT::Context(pid, path);
}
@@ -469,7 +474,7 @@
stream << USDT::USDT_PROGRAM_HEADER;
// Generate genargs codes for an array of USDT Contexts.
//
- // Each mnt_point + cmd_bin_path + probe_provider + probe_name
+ // Each cmd_bin_path + probe_provider + probe_name
// uniquely identifies a probe.
std::unordered_set<std::string> generated_probes;
for (int i = 0; i < len; i++) {
@@ -478,8 +483,8 @@
for (size_t j = 0; j < ctx->num_probes(); j++) {
USDT::Probe *p = ctx->get(j);
if (p->enabled()) {
- std::string key = std::to_string(ctx->inode()) + "*"
- + ctx->cmd_bin_path() + "*" + p->provider() + "*" + p->name();
+ auto pid = ctx->pid();
+ std::string key = ctx->cmd_bin_path() + "*" + p->provider() + "*" + p->name();
if (generated_probes.find(key) != generated_probes.end())
continue;
if (!p->usdt_getarg(stream))
diff --git a/tests/cc/CMakeLists.txt b/tests/cc/CMakeLists.txt
index 66e484d..f4eb399 100644
--- a/tests/cc/CMakeLists.txt
+++ b/tests/cc/CMakeLists.txt
@@ -4,6 +4,7 @@
include_directories(${CMAKE_SOURCE_DIR}/src/cc)
include_directories(${CMAKE_SOURCE_DIR}/src/cc/api)
include_directories(${CMAKE_SOURCE_DIR}/src/cc/libbpf/include/uapi)
+include_directories(${CMAKE_SOURCE_DIR}/tests/python/include)
add_executable(test_static test_static.c)
target_link_libraries(test_static bcc-static)
@@ -27,12 +28,10 @@
test_usdt_args.cc
test_usdt_probes.cc
utils.cc)
+file(COPY dummy_proc_map.txt DESTINATION ${CMAKE_CURRENT_BINARY_DIR})
+add_library(usdt_test_lib SHARED usdt_test_lib.c)
-target_link_libraries(test_libbcc bcc-shared dl)
+target_link_libraries(test_libbcc bcc-shared dl usdt_test_lib)
add_test(NAME test_libbcc COMMAND ${TEST_WRAPPER} c_test_all sudo ${CMAKE_CURRENT_BINARY_DIR}/test_libbcc)
-find_path(SDT_HEADER NAMES "sys/sdt.h")
-if (SDT_HEADER)
- target_compile_definitions(test_libbcc PRIVATE HAVE_SDT_HEADER=1)
-endif()
endif(ENABLE_USDT)
diff --git a/tests/cc/dummy_proc_map.txt b/tests/cc/dummy_proc_map.txt
new file mode 100644
index 0000000..4ff28c8
--- /dev/null
+++ b/tests/cc/dummy_proc_map.txt
@@ -0,0 +1,45 @@
+00400000-007c8000 r-xp 00000000 00:1b 11644523 /opt/some/path/tobinary/bin/binary
+7f151476e000-7f1514779000 r-xp 00000000 00:1b 72809479 /some/other/path/tolibs/lib/libnss_files-2.26.so
+7f1514779000-7f1514978000 ---p 0000b000 00:1b 72809479 /some/other/path/tolibs/lib/libnss_files-2.26.so
+7f1514978000-7f1514979000 r--p 0000a000 00:1b 72809479 /some/other/path/tolibs/lib/libnss_files-2.26.so
+7f1514979000-7f151497a000 rw-p 0000b000 00:1b 72809479 /some/other/path/tolibs/lib/libnss_files-2.26.so
+7f1515b7e000-7f1515b7f000 rw-p 00009000 00:1b 72809418 /some/other/path/tolibs/lib/libcrypt-2.26.so
+7f1515bad000-7f1515baf000 r-xp 00000000 00:1b 72809526 /some/other/path/tolibs/lib/libutil-2.26.so
+7f1515baf000-7f1515dae000 ---p 00002000 00:1b 72809526 /some/other/path/tolibs/lib/libutil-2.26.so
+7f1515dae000-7f1515daf000 r--p 00001000 00:1b 72809526 /some/other/path/tolibs/lib/libutil-2.26.so
+7f1515daf000-7f1515db0000 rw-p 00002000 00:1b 72809526 /some/other/path/tolibs/lib/libutil-2.26.so
+7f1515db0000-7f151601c000 r-xp 00000000 00:1b 72809420 /some/other/path/tolibs/lib/libcrypto.so.1.1
+7f151601c000-7f151621c000 ---p 0026c000 00:1b 72809420 /some/other/path/tolibs/lib/libcrypto.so.1.1
+7f151621c000-7f151623a000 r--p 0026c000 00:1b 72809420 /some/other/path/tolibs/lib/libcrypto.so.1.1
+7f151623a000-7f1516244000 rw-p 0028a000 00:1b 72809420 /some/other/path/tolibs/lib/libcrypto.so.1.1
+7f1516247000-7f15162ac000 r-xp 00000000 00:1b 72809514 /some/other/path/tolibs/lib/libssl.so.1.1
+7f15162ac000-7f15164ab000 ---p 00065000 00:1b 72809514 /some/other/path/tolibs/lib/libssl.so.1.1
+7f15164ab000-7f15164af000 r--p 00064000 00:1b 72809514 /some/other/path/tolibs/lib/libssl.so.1.1
+7f15164af000-7f15164b5000 rw-p 00068000 00:1b 72809514 /some/other/path/tolibs/lib/libssl.so.1.1
+7f15164b5000-7f15164cf000 r-xp 00000000 00:1b 72809538 /some/other/path/tolibs/lib/libz.so.1.2.8
+7f15164cf000-7f15166ce000 ---p 0001a000 00:1b 72809538 /some/other/path/tolibs/lib/libz.so.1.2.8
+7f15166ce000-7f15166cf000 r--p 00019000 00:1b 72809538 /some/other/path/tolibs/lib/libz.so.1.2.8
+7f15166cf000-7f15166d0000 rw-p 0001a000 00:1b 72809538 /some/other/path/tolibs/lib/libz.so.1.2.8
+7f15166d0000-7f15166d1000 r-xp 0001b064 00:1b 72809538 /some/other/path/tolibs/lib/libz.so.1.2.8
+7f15168d4000-7f1516a23000 r-xp 00000000 00:1b 72809463 /some/other/path/tolibs/lib/libm-2.26.so
+7f1516a23000-7f1516c22000 ---p 0014f000 00:1b 72809463 /some/other/path/tolibs/lib/libm-2.26.so
+7f1516c22000-7f1516c23000 r--p 0014e000 00:1b 72809463 /some/other/path/tolibs/lib/libm-2.26.so
+7f1516c23000-7f1516c24000 rw-p 0014f000 00:1b 72809463 /some/other/path/tolibs/lib/libm-2.26.so
+7f1516c24000-7f1516c3e000 r-xp 00000000 00:1b 72809495 /some/other/path/tolibs/lib/libpthread-2.26.so
+7f1516c3e000-7f1516e3d000 ---p 0001a000 00:1b 72809495 /some/other/path/tolibs/lib/libpthread-2.26.so
+7f1516e3d000-7f1516e3e000 r--p 00019000 00:1b 72809495 /some/other/path/tolibs/lib/libpthread-2.26.so
+7f1516e3e000-7f1516e3f000 rw-p 0001a000 00:1b 72809495 /some/other/path/tolibs/lib/libpthread-2.26.so
+7f1516e43000-7f1516e6a000 r-xp 00000000 00:1b 72809393 /some/other/path/tolibs/lib/ld-2.26.so
+7f1517010000-7f1517011000 rw-s 00000000 00:05 1117877022 /dev/zero (deleted)
+7f1517011000-7f1517012000 rw-s 00000000 00:05 1117877021 /dev/zero (deleted)
+7f1517012000-7f1517013000 rw-s 00000000 00:05 1117877020 /dev/zero (deleted)
+7f1517013000-7f151701c000 rw-s 00000000 00:05 1117899207 /dev/zero (deleted)
+7f151701c000-7f1517069000 rw-p 00000000 00:00 0
+7f1517069000-7f151706a000 r--p 00026000 00:1b 72809393 /some/other/path/tolibs/lib/ld-2.26.so
+7f151706a000-7f151706b000 rw-p 00027000 00:1b 72809393 /some/other/path/tolibs/lib/ld-2.26.so
+7f151706b000-7f151706c000 rw-p 00000000 00:00 0
+7ffd5070d000-7ffd5073d000 rwxp 00000000 00:00 0 [stack]
+7ffd5073d000-7ffd5073e000 rw-p 00000000 00:00 0
+7ffd507d7000-7ffd507da000 r--p 00000000 00:00 0 [vvar]
+7ffd507da000-7ffd507dc000 r-xp 00000000 00:00 0 [vdso]
+ffffffffff600000-ffffffffff601000 r-xp 00000000 00:00 0 [vsyscall]
diff --git a/tests/cc/test_c_api.cc b/tests/cc/test_c_api.cc
index 60804a0..31dc5ec 100644
--- a/tests/cc/test_c_api.cc
+++ b/tests/cc/test_c_api.cc
@@ -439,6 +439,133 @@
munmap(map_addr, map_sz);
}
+// must match exactly the defitinion of mod_search in bcc_syms.cc
+struct mod_search {
+ const char *name;
+ uint64_t inode;
+ uint64_t dev_major;
+ uint64_t dev_minor;
+ uint64_t addr;
+ uint8_t inode_match_only;
+
+ uint64_t start;
+ uint64_t file_offset;
+};
+
+TEST_CASE("searching for modules in /proc/[pid]/maps", "[c_api]") {
+ FILE *dummy_maps = fopen("dummy_proc_map.txt", "r");
+ REQUIRE(dummy_maps != NULL);
+
+ SECTION("name match") {
+ fseek(dummy_maps, 0, SEEK_SET);
+
+ struct mod_search search;
+ memset(&search, 0, sizeof(struct mod_search));
+ search.name = "/some/other/path/tolibs/lib/libutil-2.26.so";
+ search.addr = 0x1;
+ int res = _procfs_maps_each_module(dummy_maps, 42, _bcc_syms_find_module,
+ &search);
+ REQUIRE(res == 0);
+ REQUIRE(search.start == 0x7f1515bad000);
+ }
+
+ SECTION("expected failure to match (name only search)") {
+ fseek(dummy_maps, 0, SEEK_SET);
+
+ struct mod_search search;
+ memset(&search, 0, sizeof(struct mod_search));
+ search.name = "/lib/that/isnt/in/maps/libdoesntexist.so";
+ search.addr = 0x1;
+ int res = _procfs_maps_each_module(dummy_maps, 42, _bcc_syms_find_module,
+ &search);
+ REQUIRE(res == -1);
+ }
+
+ SECTION("inode+dev match, names different") {
+ fseek(dummy_maps, 0, SEEK_SET);
+
+ struct mod_search search;
+ memset(&search, 0, sizeof(struct mod_search));
+ search.name = "/proc/5/root/some/other/path/tolibs/lib/libz.so.1.2.8";
+ search.inode = 72809538;
+ search.dev_major = 0x00;
+ search.dev_minor = 0x1b;
+ search.addr = 0x2;
+ int res = _procfs_maps_each_module(dummy_maps, 42, _bcc_syms_find_module,
+ &search);
+ REQUIRE(res == 0);
+ REQUIRE(search.start == 0x7f15164b5000);
+ }
+
+ SECTION("inode+dev don't match, names same") {
+ fseek(dummy_maps, 0, SEEK_SET);
+
+ struct mod_search search;
+ memset(&search, 0, sizeof(struct mod_search));
+ search.name = "/some/other/path/tolibs/lib/libutil-2.26.so";
+ search.inode = 9999999;
+ search.dev_major = 0x42;
+ search.dev_minor = 0x1b;
+ search.addr = 0x2;
+ int res = _procfs_maps_each_module(dummy_maps, 42, _bcc_syms_find_module,
+ &search);
+ REQUIRE(res == -1);
+ }
+
+ SECTION("inodes match, dev_major/minor don't, expected failure") {
+ fseek(dummy_maps, 0, SEEK_SET);
+
+ struct mod_search search;
+ memset(&search, 0, sizeof(struct mod_search));
+ search.name = "/some/other/path/tolibs/lib/libutil-2.26.so";
+ search.inode = 72809526;
+ search.dev_major = 0x11;
+ search.dev_minor = 0x11;
+ search.addr = 0x2;
+ int res = _procfs_maps_each_module(dummy_maps, 42, _bcc_syms_find_module,
+ &search);
+ REQUIRE(res == -1);
+ }
+
+ SECTION("inodes match, dev_major/minor don't, match inode only") {
+ fseek(dummy_maps, 0, SEEK_SET);
+
+ struct mod_search search;
+ memset(&search, 0, sizeof(struct mod_search));
+ search.name = "/some/other/path/tolibs/lib/libutil-2.26.so";
+ search.inode = 72809526;
+ search.dev_major = 0x11;
+ search.dev_minor = 0x11;
+ search.addr = 0x2;
+ search.inode_match_only = 1;
+ int res = _procfs_maps_each_module(dummy_maps, 42, _bcc_syms_find_module,
+ &search);
+ REQUIRE(res == 0);
+ REQUIRE(search.start == 0x7f1515bad000);
+ }
+
+ fclose(dummy_maps);
+}
+
+TEST_CASE("resolve global addr in libc in this process", "[c_api]") {
+ int pid = getpid();
+ char *sopath = bcc_procutils_which_so("c", pid);
+ uint64_t local_addr = 0x15;
+ uint64_t global_addr;
+
+ struct mod_search search;
+ memset(&search, 0, sizeof(struct mod_search));
+ search.name = sopath;
+
+ int res = bcc_procutils_each_module(pid, _bcc_syms_find_module,
+ &search);
+ REQUIRE(res == 0);
+ REQUIRE(search.start != 0);
+
+ res = bcc_resolve_global_addr(pid, sopath, local_addr, 0, &global_addr);
+ REQUIRE(res == 0);
+ REQUIRE(global_addr == (search.start + local_addr - search.file_offset));
+}
TEST_CASE("get online CPUs", "[c_api]") {
std::vector<int> cpus = ebpf::get_online_cpus();
diff --git a/tests/cc/test_usdt_probes.cc b/tests/cc/test_usdt_probes.cc
index 3e42633..71c75a1 100644
--- a/tests/cc/test_usdt_probes.cc
+++ b/tests/cc/test_usdt_probes.cc
@@ -22,19 +22,24 @@
#include "usdt.h"
#include "api/BPF.h"
-#ifdef HAVE_SDT_HEADER
/* required to insert USDT probes on this very executable --
* we're gonna be testing them live! */
-#include <sys/sdt.h>
+#include "folly/tracing/StaticTracepoint.h"
static int a_probed_function() {
int an_int = 23 + getpid();
void *a_pointer = malloc(4);
- DTRACE_PROBE2(libbcc_test, sample_probe_1, an_int, a_pointer);
+ FOLLY_SDT(libbcc_test, sample_probe_1, an_int, a_pointer);
free(a_pointer);
return an_int;
}
+extern "C" int lib_probed_function();
+
+int call_shared_lib_func() {
+ return lib_probed_function();
+}
+
TEST_CASE("test finding a probe in our own process", "[usdt]") {
USDT::Context ctx(getpid());
REQUIRE(ctx.num_probes() >= 1);
@@ -43,7 +48,8 @@
auto probe = ctx.get("sample_probe_1");
REQUIRE(probe);
- REQUIRE(probe->in_shared_object(probe->bin_path()) == false);
+ if(probe->in_shared_object(probe->bin_path()))
+ return;
REQUIRE(probe->name() == "sample_probe_1");
REQUIRE(probe->provider() == "libbcc_test");
REQUIRE(probe->bin_path().find("/test_libbcc") != std::string::npos);
@@ -83,7 +89,15 @@
res = bpf.detach_usdt(u);
REQUIRE(res.code() == 0);
}
-#endif // HAVE_SDT_HEADER
+
+TEST_CASE("test find a probe in our process' shared libs with c++ API", "[usdt]") {
+ ebpf::BPF bpf;
+ ebpf::USDT u(::getpid(), "libbcc_test", "sample_lib_probe_1", "on_event");
+
+ auto res = bpf.init("int on_event() { return 0; }", {}, {u});
+ REQUIRE(res.msg() == "");
+ REQUIRE(res.code() == 0);
+}
class ChildProcess {
pid_t pid_;
diff --git a/tests/cc/usdt_test_lib.c b/tests/cc/usdt_test_lib.c
new file mode 100644
index 0000000..799ad9b
--- /dev/null
+++ b/tests/cc/usdt_test_lib.c
@@ -0,0 +1,10 @@
+#include <sys/types.h>
+#include <unistd.h>
+
+#include "folly/tracing/StaticTracepoint.h"
+
+int lib_probed_function() {
+ int an_int = 42 + getpid();
+ FOLLY_SDT(libbcc_test, sample_lib_probe_1, an_int);
+ return an_int;
+}