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
Dec 28, 2018
by
Brendan Gregg
Committed by
GitHub
Dec 28, 2018
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
Show 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.
.
.
...
...
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
)
{
{
...
...
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
);
};
};
...
...
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
)
...
...
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