usdt: Use uprobe refcnt if available in usdt C++ API
#include <cstdio>
#include <cstring>
#include <exception>
+#include <fcntl.h>
#include <iostream>
#include <memory>
#include <sstream>
+#include <sys/stat.h>
+#include <sys/types.h>
#include <utility>
#include <vector>
#include "BPF.h"
+namespace {
+/*
+ * Kernels ~4.20 and later support specifying the ref_ctr_offset as an argument
+ * to attaching a uprobe, which negates the need to seek to this memory offset
+ * in userspace to manage semaphores, as the kernel will do it for us. This
+ * helper function checks if this support is available by reading the uprobe
+ * format for this value, added in a6ca88b241d5e929e6e60b12ad8cd288f0ffa
+*/
+bool uprobe_ref_ctr_supported() {
+ const char *ref_ctr_pmu_path =
+ "/sys/bus/event_source/devices/uprobe/format/ref_ctr_offset";
+ const char *ref_ctr_pmu_expected = "config:32-63\0";
+ char ref_ctr_pmu_fmt[64]; // in Linux source this buffer is compared vs
+ // PAGE_SIZE, but 64 is probably ample
+ int fd = open(ref_ctr_pmu_path, O_RDONLY);
+ if (fd < 0)
+ return false;
+
+ int ret = read(fd, ref_ctr_pmu_fmt, sizeof(ref_ctr_pmu_fmt));
+ close(fd);
+ if (ret < 0) {
+ return false;
+ }
+ if (strncmp(ref_ctr_pmu_expected, ref_ctr_pmu_fmt,
+ strlen(ref_ctr_pmu_expected)) == 0) {
+ return true;
+ }
+ return false;
+}
+} // namespace
+
namespace ebpf {
std::string uint_to_hex(uint64_t value) {
@@ -268,7 +302,7 @@ StatusTuple BPF::attach_uprobe(const std::string& binary_path,
StatusTuple BPF::attach_usdt_without_validation(const USDT& u, pid_t pid) {
auto& probe = *static_cast<::USDT::Probe*>(u.probe_.get());
- if (!probe.enable(u.probe_func_))
+ if (!uprobe_ref_ctr_supported() && !probe.enable(u.probe_func_))
return StatusTuple(-1, "Unable to enable USDT %s" + u.print_name());
bool failed = false;
@@ -276,7 +310,8 @@ StatusTuple BPF::attach_usdt_without_validation(const USDT& u, pid_t pid) {
int cnt = 0;
for (const auto& loc : probe.locations_) {
auto res = attach_uprobe(loc.bin_path_, std::string(), u.probe_func_,
- loc.address_, BPF_PROBE_ENTRY, pid);
+ loc.address_, BPF_PROBE_ENTRY, pid, 0,
+ probe.semaphore_offset());
if (!res.ok()) {
failed = true;
err_msg += "USDT " + u.print_name() + " at " + loc.bin_path_ +
@@ -507,7 +542,7 @@ StatusTuple BPF::detach_usdt_without_validation(const USDT& u, pid_t pid) {
}
}
- if (!probe.disable()) {
+ if (!uprobe_ref_ctr_supported() && !probe.disable()) {
failed = true;
err_msg += "Unable to disable USDT " + u.print_name();
}
