Skip to content

Commit

Permalink
[uprobe] support for pid targeting for shared libs
Browse files Browse the repository at this point in the history
This adds support for specifying the pid even when targeting
a uprobe/uretprobe in a library shared by multiple pids.

Example:
```
sudo bpftrace -p 1899508 -e 'uprobe:libc:getaddrinfo {
  print((comm, pid));
}
```

[Issue 2817](#2817)
  • Loading branch information
Jordan Rome committed Nov 25, 2023
1 parent 4151bab commit c83afea
Show file tree
Hide file tree
Showing 9 changed files with 90 additions and 21 deletions.
2 changes: 2 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,8 @@ and this project adheres to
- [#2804](https://github.com/iovisor/bpftrace/pull/2804)
- Add fentry/fexit aliases for kfunc/kretfunc
- [#2844](https://github.com/iovisor/bpftrace/pull/2844)
- Add support for uprobe pid targeting
- [#2830](https://github.com/iovisor/bpftrace/pull/2830)
#### Changed
#### Deprecated
#### Removed
Expand Down
3 changes: 2 additions & 1 deletion man/adoc/bpftrace.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -118,7 +118,8 @@ u:lib.so:"fn(char const*)" { printf("arg0:%s\n", str(arg0));}

*-p* _PID_::
Attach to the process with _PID_. If the process terminates, bpftrace will also terminate.
When using USDT probes they will be attached to only this process. For uprobes/uretprobes if you also set the target to '*' the process's address space will be searched for the symbols.
When using USDT probes, uprobes, and uretprobes they will be attached to only this process.
For listing uprobes/uretprobes if you set the target to '*' the process's address space will be searched for the symbols.

*-c* _COMMAND_::
Run _COMMAND_ as a child process.
Expand Down
28 changes: 17 additions & 11 deletions src/attached_probe.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -191,7 +191,7 @@ AttachedProbe::AttachedProbe(Probe &probe,
// If BPF_PROG_TYPE_RAW_TRACEPOINT is available, no need to attach prog
// to anything -- we will simply BPF_PROG_RUN it
if (!feature.has_raw_tp_special())
attach_uprobe(safe_mode);
attach_uprobe(getpid(), safe_mode);
break;
case ProbeType::kprobe:
attach_kprobe(safe_mode);
Expand All @@ -200,10 +200,6 @@ AttachedProbe::AttachedProbe(Probe &probe,
check_banned_kretprobes(probe_.attach_point);
attach_kprobe(safe_mode);
break;
case ProbeType::uprobe:
case ProbeType::uretprobe:
attach_uprobe(safe_mode);
break;
case ProbeType::tracepoint:
attach_tracepoint();
break;
Expand Down Expand Up @@ -239,7 +235,8 @@ AttachedProbe::AttachedProbe(Probe &probe,
BpfProgram &&prog,
int pid,
BPFfeature &feature,
BTF &btf)
BTF &btf,
bool safe_mode)
: probe_(probe), prog_(std::move(prog)), btf_(btf)
{
load_prog(feature);
Expand All @@ -252,6 +249,10 @@ AttachedProbe::AttachedProbe(Probe &probe,
case ProbeType::asyncwatchpoint:
attach_watchpoint(pid, probe.mode);
break;
case ProbeType::uprobe:
case ProbeType::uretprobe:
attach_uprobe(pid, safe_mode);
break;
default:
LOG(FATAL) << "invalid attached probe type \""
<< probetypeName(probe_.type) << "\"";
Expand Down Expand Up @@ -1091,7 +1092,7 @@ static void resolve_offset_uprobe_multi(const std::string &path,
}
}

void AttachedProbe::attach_multi_uprobe(void)
void AttachedProbe::attach_multi_uprobe(int pid)
{
std::vector<std::string> syms;
std::vector<uint64_t> offsets;
Expand All @@ -1110,6 +1111,11 @@ void AttachedProbe::attach_multi_uprobe(void)
opts.uprobe_multi.flags = probe_.type == ProbeType::uretprobe
? BPF_F_UPROBE_MULTI_RETURN
: 0;
if (pid != 0)
{
opts.uprobe_multi.pid = pid;
}

if (bt_verbose)
{
std::cout << "Attaching to " << probe_.funcs.size() << " functions"
Expand All @@ -1135,16 +1141,16 @@ void AttachedProbe::attach_multi_uprobe(void)
}
}
#else
void AttachedProbe::attach_multi_uprobe(void)
void AttachedProbe::attach_multi_uprobe(int)
{
}
#endif // HAVE_LIBBPF_UPROBE_MULTI

void AttachedProbe::attach_uprobe(bool safe_mode)
void AttachedProbe::attach_uprobe(int pid, bool safe_mode)
{
if (!probe_.funcs.empty())
{
attach_multi_uprobe();
attach_multi_uprobe(pid);
return;
}

Expand All @@ -1156,7 +1162,7 @@ void AttachedProbe::attach_uprobe(bool safe_mode)
eventname().c_str(),
probe_.path.c_str(),
offset_,
probe_.pid,
pid == 0 ? -1 : pid,
0);

if (perf_event_fd < 0)
Expand Down
7 changes: 4 additions & 3 deletions src/attached_probe.h
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,8 @@ class AttachedProbe
BpfProgram &&prog,
int pid,
BPFfeature &feature,
BTF &btf);
BTF &btf,
bool safe_mode = true);
~AttachedProbe();
AttachedProbe(const AttachedProbe &) = delete;
AttachedProbe &operator=(const AttachedProbe &) = delete;
Expand All @@ -46,9 +47,9 @@ class AttachedProbe
bool resolve_offset_uprobe(bool safe_mode);
void load_prog(BPFfeature &feature);
void attach_multi_kprobe(void);
void attach_multi_uprobe(void);
void attach_multi_uprobe(int pid);
void attach_kprobe(bool safe_mode);
void attach_uprobe(bool safe_mode);
void attach_uprobe(int pid, bool safe_mode);

// Note: the following usdt attachment functions will only activate a
// semaphore if one exists.
Expand Down
11 changes: 7 additions & 4 deletions src/bpftrace.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1006,6 +1006,13 @@ std::vector<std::unique_ptr<AttachedProbe>> BPFtrace::attach_probe(

return ret;
}
else if (probe.type == ProbeType::uprobe ||
probe.type == ProbeType::uretprobe)
{
ret.emplace_back(std::make_unique<AttachedProbe>(
probe, std::move(*program), pid, *feature_, *btf_, safe_mode_));
return ret;
}
else if (probe.type == ProbeType::watchpoint ||
probe.type == ProbeType::asyncwatchpoint)
{
Expand Down Expand Up @@ -1085,10 +1092,6 @@ int BPFtrace::run_special_probe(std::string name,
{
if ((*probe).attach_point == name)
{
// This is only necessary for uprobe fallback case but it doesn't hurt
// to set for raw_tp
probe->pid = getpid();

auto aps = attach_probe(*probe, bytecode);
if (aps.size() != 1)
return -1;
Expand Down
2 changes: 0 additions & 2 deletions src/types.h
Original file line number Diff line number Diff line change
Expand Up @@ -532,7 +532,6 @@ struct Probe
uint64_t log_size = 1000000;
int index = 0;
int freq = 0;
pid_t pid = -1;
uint64_t len = 0; // for watchpoint probes, size of region
std::string mode; // for watchpoint probes, watch mode (rwx)
bool async = false; // for watchpoint probes, if it's an async watchpoint
Expand All @@ -557,7 +556,6 @@ struct Probe
log_size,
index,
freq,
pid,
len,
mode,
async,
Expand Down
20 changes: 20 additions & 0 deletions tests/runtime/scripts/uprobe_pid_check.bt
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
BEGIN {
@count = 0;
}

uprobe:./testprogs/uprobe_fork_loop:uprobeFunction1 {
if (pid == $1) {
// counting 10 instances of the expected pid
// is similar to a delay to ensure we never get
// an unexpected pid
if (@count == 10) {
print("hello");
exit();
} else {
@count++;
}
} else {
// pid should always be the first positional param
exit();
}
}
6 changes: 6 additions & 0 deletions tests/runtime/uprobe
Original file line number Diff line number Diff line change
Expand Up @@ -73,3 +73,9 @@ NAME uprobes - probe function in non-executable library
PROG uprobe:./testlibs/libsimple.so:fun {}
EXPECT Attaching 1 probe...
TIMEOUT 5

NAME uprobes - attach to single process with pid arg
RUN {{BPFTRACE}} runtime/scripts/uprobe_pid_check.bt -p {{BEFORE_PID}} {{BEFORE_PID}}
EXPECT hello
TIMEOUT 5
BEFORE ./testprogs/uprobe_fork_loop
32 changes: 32 additions & 0 deletions tests/testprogs/uprobe_fork_loop.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,32 @@
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int uprobeFunction1(int *n, char c __attribute__((unused)))
{
return *n;
}

void spin()
{
while (1)
{
int n = 13;
char c = 'x';
uprobeFunction1(&n, c);
usleep(500);
}
}

int main(int argc __attribute__((unused)), char **argv __attribute__((unused)))
{
pid_t p = fork();
if (p < 0)
{
perror("fork fail");
exit(1);
}
spin();

return 0;
}

0 comments on commit c83afea

Please sign in to comment.