Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
B
bpftrace
Project overview
Project overview
Details
Activity
Releases
Repository
Repository
Files
Commits
Branches
Tags
Contributors
Graph
Compare
Issues
0
Issues
0
List
Boards
Labels
Milestones
Merge Requests
0
Merge Requests
0
Analytics
Analytics
Repository
Value Stream
Wiki
Wiki
Snippets
Snippets
Members
Members
Collapse sidebar
Close sidebar
Activity
Graph
Create a new issue
Commits
Issue Boards
Open sidebar
Kirill Smelkov
bpftrace
Commits
e89957ff
Commit
e89957ff
authored
6 years ago
by
Brendan Gregg
Committed by
GitHub
6 years ago
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #297 from danobi/cmd_runner
Add -c CMD option
parents
d33e6f03
a3086a88
Changes
4
Hide whitespace changes
Inline
Side-by-side
Showing
4 changed files
with
120 additions
and
5 deletions
+120
-5
man/man8/bpftrace.8
man/man8/bpftrace.8
+10
-1
src/bpftrace.cpp
src/bpftrace.cpp
+88
-0
src/bpftrace.h
src/bpftrace.h
+4
-1
src/main.cpp
src/main.cpp
+18
-3
No files found.
man/man8/bpftrace.8
View file @
e89957ff
...
@@ -60,7 +60,12 @@ Execute PROGRAM.
...
@@ -60,7 +60,12 @@ Execute PROGRAM.
.
.
.TP
.TP
\fB\-p PID\fR
\fB\-p PID\fR
Process ID for enabling USDT probes.
Enable USDT probes on PID. Will terminate bpftrace on PID termination. Note this is not a global PID filter on probes.
.
.TP
\fB\-c CMD\fR
Helper to run CMD. Equivalent to manually running CMD and then giving passing the PID to -p. This is useful to ensure
you've traced at least the duration CMD's execution. You must provide an absolute path for the executable.
.
.
.TP
.TP
\fB\-v\fR
\fB\-v\fR
...
@@ -85,6 +90,10 @@ List probes containing "sleep".
...
@@ -85,6 +90,10 @@ List probes containing "sleep".
Trace processes calling sleep.
Trace processes calling sleep.
.
.
.TP
.TP
\fBbpftrace \-c \'sleep 5\' \-e \'kprobe:do_nanosleep { printf("PID %d sleeping\en", pid); }\'\fR
run "sleep 5" in a new process and then trace processes calling sleep.
.
.TP
\fBbpftrace \-e \'tracepoint:raw_syscalls:sys_enter { @[comm]=count(); }\'\fR
\fBbpftrace \-e \'tracepoint:raw_syscalls:sys_enter { @[comm]=count(); }\'\fR
Count syscalls by process name.
Count syscalls by process name.
.
.
...
...
This diff is collapsed.
Click to expand it.
src/bpftrace.cpp
View file @
e89957ff
...
@@ -10,7 +10,10 @@
...
@@ -10,7 +10,10 @@
#include <sys/types.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/stat.h>
#include <sys/prctl.h>
#include <sys/wait.h>
#include <fcntl.h>
#include <fcntl.h>
#include <unistd.h>
#include "bcc_syms.h"
#include "bcc_syms.h"
#include "perf_reader.h"
#include "perf_reader.h"
...
@@ -21,11 +24,25 @@
...
@@ -21,11 +24,25 @@
#include "triggers.h"
#include "triggers.h"
#include "resolve_cgroupid.h"
#include "resolve_cgroupid.h"
extern
char
**
environ
;
namespace
bpftrace
{
namespace
bpftrace
{
DebugLevel
bt_debug
=
DebugLevel
::
kNone
;
DebugLevel
bt_debug
=
DebugLevel
::
kNone
;
bool
bt_verbose
=
false
;
bool
bt_verbose
=
false
;
BPFtrace
::~
BPFtrace
()
{
for
(
int
pid
:
child_pids_
)
{
// We don't care if waitpid returns any errors. We're just trying
// to make a best effort here. It's not like we could recover from
// an error.
int
status
;
waitpid
(
pid
,
&
status
,
0
);
}
}
int
BPFtrace
::
add_probe
(
ast
::
Probe
&
p
)
int
BPFtrace
::
add_probe
(
ast
::
Probe
&
p
)
{
{
for
(
auto
attach_point
:
*
p
.
attach_points
)
for
(
auto
attach_point
:
*
p
.
attach_points
)
...
@@ -427,6 +444,21 @@ int BPFtrace::run(std::unique_ptr<BpfOrc> bpforc)
...
@@ -427,6 +444,21 @@ int BPFtrace::run(std::unique_ptr<BpfOrc> bpforc)
if
(
epollfd
<
0
)
if
(
epollfd
<
0
)
return
epollfd
;
return
epollfd
;
// Spawn a child process if we've been passed a command to run
if
(
cmd_
.
size
())
{
auto
args
=
split_string
(
cmd_
,
' '
);
int
pid
=
spawn_child
(
args
);
if
(
pid
<
0
)
{
std
::
cerr
<<
"Failed to spawn child="
<<
cmd_
<<
std
::
endl
;
return
pid
;
}
child_pids_
.
emplace_back
(
pid
);
pid_
=
pid
;
}
BEGIN_trigger
();
BEGIN_trigger
();
// NOTE (mmarchini): Apparently the kernel fires kprobe_events in the reverse
// NOTE (mmarchini): Apparently the kernel fires kprobe_events in the reverse
...
@@ -1079,6 +1111,56 @@ int BPFtrace::print_lhist(const std::vector<uint64_t> &values, int min, int max,
...
@@ -1079,6 +1111,56 @@ int BPFtrace::print_lhist(const std::vector<uint64_t> &values, int min, int max,
return
0
;
return
0
;
}
}
int
BPFtrace
::
spawn_child
(
const
std
::
vector
<
std
::
string
>&
args
)
{
static
const
int
maxargs
=
256
;
char
*
argv
[
maxargs
];
// Convert vector of strings into raw array of C-strings for execve(2)
int
idx
=
0
;
for
(
const
auto
&
arg
:
args
)
{
if
(
idx
==
maxargs
-
1
)
{
std
::
cerr
<<
"Too many args passed into spawn_child ("
<<
args
.
size
()
<<
" > "
<<
maxargs
-
1
<<
")"
<<
std
::
endl
;
return
-
1
;
}
argv
[
idx
]
=
const_cast
<
char
*>
(
arg
.
c_str
());
++
idx
;
}
argv
[
idx
]
=
nullptr
;
// must be null terminated
// Fork and exec
int
ret
=
fork
();
if
(
ret
==
0
)
{
// Receive SIGTERM if parent dies
//
// Useful if user doesn't kill the bpftrace process group
if
(
prctl
(
PR_SET_PDEATHSIG
,
SIGTERM
))
perror
(
"prctl(PR_SET_PDEATHSIG)"
);
if
(
execve
(
argv
[
0
],
argv
,
environ
))
{
perror
(
"execve"
);
return
-
1
;
}
}
else
if
(
ret
>
0
)
{
return
ret
;
}
else
{
perror
(
"fork"
);
return
-
1
;
}
return
-
1
;
// silence end of control compiler warning
}
std
::
string
BPFtrace
::
hist_index_label
(
int
power
)
std
::
string
BPFtrace
::
hist_index_label
(
int
power
)
{
{
char
suffix
=
'\0'
;
char
suffix
=
'\0'
;
...
@@ -1477,6 +1559,12 @@ bool BPFtrace::is_pid_alive(int pid)
...
@@ -1477,6 +1559,12 @@ bool BPFtrace::is_pid_alive(int pid)
throw
std
::
runtime_error
(
"failed to snprintf"
);
throw
std
::
runtime_error
(
"failed to snprintf"
);
}
}
// Do a nonblocking wait on the pid just in case it's our child and it
// has exited. We don't really care about any errors, we're just trying
// to make a best effort.
int
status
;
waitpid
(
pid
,
&
status
,
WNOHANG
);
int
fd
=
open
(
buf
,
0
,
O_RDONLY
);
int
fd
=
open
(
buf
,
0
,
O_RDONLY
);
if
(
fd
<
0
&&
errno
==
ENOENT
)
if
(
fd
<
0
&&
errno
==
ENOENT
)
{
{
...
...
This diff is collapsed.
Click to expand it.
src/bpftrace.h
View file @
e89957ff
...
@@ -50,7 +50,7 @@ class BPFtrace
...
@@ -50,7 +50,7 @@ class BPFtrace
{
{
public:
public:
BPFtrace
()
:
ncpus_
(
ebpf
::
get_possible_cpus
().
size
())
{
}
BPFtrace
()
:
ncpus_
(
ebpf
::
get_possible_cpus
().
size
())
{
}
virtual
~
BPFtrace
()
{
}
virtual
~
BPFtrace
()
;
virtual
int
add_probe
(
ast
::
Probe
&
p
);
virtual
int
add_probe
(
ast
::
Probe
&
p
);
int
num_probes
()
const
;
int
num_probes
()
const
;
int
run
(
std
::
unique_ptr
<
BpfOrc
>
bpforc
);
int
run
(
std
::
unique_ptr
<
BpfOrc
>
bpforc
);
...
@@ -68,6 +68,7 @@ public:
...
@@ -68,6 +68,7 @@ public:
std
::
string
resolve_probe
(
uint64_t
probe_id
);
std
::
string
resolve_probe
(
uint64_t
probe_id
);
uint64_t
resolve_cgroupid
(
const
std
::
string
&
path
);
uint64_t
resolve_cgroupid
(
const
std
::
string
&
path
);
std
::
vector
<
uint64_t
>
get_arg_values
(
std
::
vector
<
Field
>
args
,
uint8_t
*
arg_data
);
std
::
vector
<
uint64_t
>
get_arg_values
(
std
::
vector
<
Field
>
args
,
uint8_t
*
arg_data
);
std
::
string
cmd_
;
int
pid_
{
0
};
int
pid_
{
0
};
std
::
map
<
std
::
string
,
std
::
unique_ptr
<
IMap
>>
maps_
;
std
::
map
<
std
::
string
,
std
::
unique_ptr
<
IMap
>>
maps_
;
...
@@ -97,6 +98,7 @@ private:
...
@@ -97,6 +98,7 @@ private:
std
::
map
<
int
,
void
*>
pid_sym_
;
std
::
map
<
int
,
void
*>
pid_sym_
;
int
ncpus_
;
int
ncpus_
;
int
online_cpus_
;
int
online_cpus_
;
std
::
vector
<
int
>
child_pids_
;
std
::
unique_ptr
<
AttachedProbe
>
attach_probe
(
Probe
&
probe
,
const
BpfOrc
&
bpforc
);
std
::
unique_ptr
<
AttachedProbe
>
attach_probe
(
Probe
&
probe
,
const
BpfOrc
&
bpforc
);
int
setup_perf_events
();
int
setup_perf_events
();
...
@@ -118,6 +120,7 @@ private:
...
@@ -118,6 +120,7 @@ private:
static
std
::
string
lhist_index_label
(
int
number
);
static
std
::
string
lhist_index_label
(
int
number
);
static
std
::
vector
<
std
::
string
>
split_string
(
std
::
string
&
str
,
char
split_by
);
static
std
::
vector
<
std
::
string
>
split_string
(
std
::
string
&
str
,
char
split_by
);
std
::
vector
<
uint8_t
>
find_empty_key
(
IMap
&
map
,
size_t
size
)
const
;
std
::
vector
<
uint8_t
>
find_empty_key
(
IMap
&
map
,
size_t
size
)
const
;
static
int
spawn_child
(
const
std
::
vector
<
std
::
string
>&
args
);
static
bool
is_pid_alive
(
int
pid
);
static
bool
is_pid_alive
(
int
pid
);
};
};
...
...
This diff is collapsed.
Click to expand it.
src/main.cpp
View file @
e89957ff
...
@@ -25,7 +25,8 @@ void usage()
...
@@ -25,7 +25,8 @@ void usage()
std
::
cerr
<<
" -e 'program' execute this program"
<<
std
::
endl
;
std
::
cerr
<<
" -e 'program' execute this program"
<<
std
::
endl
;
std
::
cerr
<<
" -h show this help message"
<<
std
::
endl
;
std
::
cerr
<<
" -h show this help message"
<<
std
::
endl
;
std
::
cerr
<<
" -l [search] list probes"
<<
std
::
endl
;
std
::
cerr
<<
" -l [search] list probes"
<<
std
::
endl
;
std
::
cerr
<<
" -p PID PID for enabling USDT probes"
<<
std
::
endl
;
std
::
cerr
<<
" -p PID enable USDT probes on PID"
<<
std
::
endl
;
std
::
cerr
<<
" -c 'CMD' run CMD and enable USDT probes on resulting process"
<<
std
::
endl
;
std
::
cerr
<<
" -v verbose messages"
<<
std
::
endl
<<
std
::
endl
;
std
::
cerr
<<
" -v verbose messages"
<<
std
::
endl
<<
std
::
endl
;
std
::
cerr
<<
"EXAMPLES:"
<<
std
::
endl
;
std
::
cerr
<<
"EXAMPLES:"
<<
std
::
endl
;
std
::
cerr
<<
"bpftrace -l '*sleep*'"
<<
std
::
endl
;
std
::
cerr
<<
"bpftrace -l '*sleep*'"
<<
std
::
endl
;
...
@@ -56,12 +57,13 @@ int main(int argc, char *argv[])
...
@@ -56,12 +57,13 @@ int main(int argc, char *argv[])
{
{
int
err
;
int
err
;
Driver
driver
;
Driver
driver
;
char
*
pid_str
=
NULL
;
char
*
pid_str
=
nullptr
;
char
*
cmd_str
=
nullptr
;
bool
listing
=
false
;
bool
listing
=
false
;
std
::
string
script
,
search
;
std
::
string
script
,
search
;
int
c
;
int
c
;
while
((
c
=
getopt
(
argc
,
argv
,
"de:hlp:v"
))
!=
-
1
)
while
((
c
=
getopt
(
argc
,
argv
,
"de:hlp:v
c:
"
))
!=
-
1
)
{
{
switch
(
c
)
switch
(
c
)
{
{
...
@@ -84,6 +86,9 @@ int main(int argc, char *argv[])
...
@@ -84,6 +86,9 @@ int main(int argc, char *argv[])
case
'l'
:
case
'l'
:
listing
=
true
;
listing
=
true
;
break
;
break
;
case
'c'
:
cmd_str
=
optarg
;
break
;
default:
default:
usage
();
usage
();
return
1
;
return
1
;
...
@@ -97,6 +102,13 @@ int main(int argc, char *argv[])
...
@@ -97,6 +102,13 @@ int main(int argc, char *argv[])
return
1
;
return
1
;
}
}
if
(
cmd_str
&&
pid_str
)
{
std
::
cerr
<<
"USAGE: Cannot use both -c and -p."
<<
std
::
endl
;
usage
();
return
1
;
}
// Listing probes
// Listing probes
if
(
listing
)
if
(
listing
)
{
{
...
@@ -152,6 +164,9 @@ int main(int argc, char *argv[])
...
@@ -152,6 +164,9 @@ int main(int argc, char *argv[])
if
(
pid_str
)
if
(
pid_str
)
bpftrace
.
pid_
=
atoi
(
pid_str
);
bpftrace
.
pid_
=
atoi
(
pid_str
);
if
(
cmd_str
)
bpftrace
.
cmd_
=
cmd_str
;
TracepointFormatParser
::
parse
(
driver
.
root_
);
TracepointFormatParser
::
parse
(
driver
.
root_
);
if
(
bt_debug
!=
DebugLevel
::
kNone
)
if
(
bt_debug
!=
DebugLevel
::
kNone
)
...
...
This diff is collapsed.
Click to expand it.
Write
Preview
Markdown
is supported
0%
Try again
or
attach a new file
Attach a file
Cancel
You are about to add
0
people
to the discussion. Proceed with caution.
Finish editing this message first!
Cancel
Please
register
or
sign in
to comment