Skip to content
Projects
Groups
Snippets
Help
Loading...
Help
Support
Keyboard shortcuts
?
Submit feedback
Contribute to GitLab
Sign in / Register
Toggle navigation
B
bcc
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
bcc
Commits
1fe85d07
Commit
1fe85d07
authored
Feb 28, 2018
by
yonghong-song
Committed by
GitHub
Feb 28, 2018
Browse files
Options
Browse Files
Download
Plain Diff
Merge pull request #1607 from palmtenor/no_reader
Remove PERF_SAMPLE_CALLCHAIN logic from TRACEPOINT events
parents
abef8350
d0e48edb
Changes
14
Show whitespace changes
Inline
Side-by-side
Showing
14 changed files
with
245 additions
and
412 deletions
+245
-412
src/cc/api/BPF.cc
src/cc/api/BPF.cc
+18
-31
src/cc/api/BPF.h
src/cc/api/BPF.h
+4
-9
src/cc/libbpf.c
src/cc/libbpf.c
+56
-70
src/cc/libbpf.h
src/cc/libbpf.h
+7
-14
src/cc/perf_reader.c
src/cc/perf_reader.c
+8
-83
src/cc/perf_reader.h
src/cc/perf_reader.h
+2
-3
src/lua/bcc/bpf.lua
src/lua/bcc/bpf.lua
+32
-20
src/lua/bcc/libbcc.lua
src/lua/bcc/libbcc.lua
+7
-8
src/lua/bcc/table.lua
src/lua/bcc/table.lua
+1
-1
src/python/bcc/__init__.py
src/python/bcc/__init__.py
+100
-125
src/python/bcc/libbcc.py
src/python/bcc/libbcc.py
+6
-10
src/python/bcc/table.py
src/python/bcc/table.py
+4
-4
tests/python/CMakeLists.txt
tests/python/CMakeLists.txt
+0
-2
tests/python/test_callchain.py
tests/python/test_callchain.py
+0
-32
No files found.
src/cc/api/BPF.cc
View file @
1fe85d07
...
...
@@ -159,8 +159,7 @@ StatusTuple BPF::detach_all() {
StatusTuple
BPF
::
attach_kprobe
(
const
std
::
string
&
kernel_func
,
const
std
::
string
&
probe_func
,
bpf_probe_attach_type
attach_type
,
perf_reader_cb
cb
,
void
*
cb_cookie
)
{
bpf_probe_attach_type
attach_type
)
{
std
::
string
probe_event
=
get_kprobe_event
(
kernel_func
,
attach_type
);
if
(
kprobes_
.
find
(
probe_event
)
!=
kprobes_
.
end
())
return
StatusTuple
(
-
1
,
"kprobe %s already attached"
,
probe_event
.
c_str
());
...
...
@@ -168,10 +167,10 @@ StatusTuple BPF::attach_kprobe(const std::string& kernel_func,
int
probe_fd
;
TRY2
(
load_func
(
probe_func
,
BPF_PROG_TYPE_KPROBE
,
probe_fd
));
void
*
res
=
bpf_attach_kprobe
(
probe_fd
,
attach_type
,
probe_event
.
c_str
(),
kernel_func
.
c_str
(),
cb
,
cb_cookie
);
int
res_fd
=
bpf_attach_kprobe
(
probe_fd
,
attach_type
,
probe_event
.
c_str
(),
kernel_func
.
c_str
()
);
if
(
!
res
)
{
if
(
res_fd
<
0
)
{
TRY2
(
unload_func
(
probe_func
));
return
StatusTuple
(
-
1
,
"Unable to attach %skprobe for %s using %s"
,
attach_type_debug
(
attach_type
).
c_str
(),
...
...
@@ -179,7 +178,7 @@ StatusTuple BPF::attach_kprobe(const std::string& kernel_func,
}
open_probe_t
p
=
{};
p
.
reader_ptr
=
res
;
p
.
perf_event_fd
=
res_fd
;
p
.
func
=
probe_func
;
kprobes_
[
probe_event
]
=
std
::
move
(
p
);
return
StatusTuple
(
0
);
...
...
@@ -189,8 +188,7 @@ StatusTuple BPF::attach_uprobe(const std::string& binary_path,
const
std
::
string
&
symbol
,
const
std
::
string
&
probe_func
,
uint64_t
symbol_addr
,
bpf_probe_attach_type
attach_type
,
pid_t
pid
,
perf_reader_cb
cb
,
void
*
cb_cookie
)
{
bpf_probe_attach_type
attach_type
,
pid_t
pid
)
{
std
::
string
module
;
uint64_t
offset
;
TRY2
(
check_binary_symbol
(
binary_path
,
symbol
,
symbol_addr
,
module
,
offset
));
...
...
@@ -202,11 +200,10 @@ StatusTuple BPF::attach_uprobe(const std::string& binary_path,
int
probe_fd
;
TRY2
(
load_func
(
probe_func
,
BPF_PROG_TYPE_KPROBE
,
probe_fd
));
void
*
res
=
bpf_attach_uprobe
(
probe_fd
,
attach_type
,
probe_event
.
c_str
(),
binary_path
.
c_str
(),
offset
,
pid
,
cb
,
cb_cookie
);
int
res_fd
=
bpf_attach_uprobe
(
probe_fd
,
attach_type
,
probe_event
.
c_str
(),
binary_path
.
c_str
(),
offset
,
pid
);
if
(
!
res
)
{
if
(
res_fd
<
0
)
{
TRY2
(
unload_func
(
probe_func
));
return
StatusTuple
(
-
1
,
...
...
@@ -216,7 +213,7 @@ StatusTuple BPF::attach_uprobe(const std::string& binary_path,
}
open_probe_t
p
=
{};
p
.
reader_ptr
=
res
;
p
.
perf_event_fd
=
res_fd
;
p
.
func
=
probe_func
;
uprobes_
[
probe_event
]
=
std
::
move
(
p
);
return
StatusTuple
(
0
);
...
...
@@ -253,8 +250,7 @@ StatusTuple BPF::attach_usdt(const USDT& usdt, pid_t pid) {
}
StatusTuple
BPF
::
attach_tracepoint
(
const
std
::
string
&
tracepoint
,
const
std
::
string
&
probe_func
,
perf_reader_cb
cb
,
void
*
cb_cookie
)
{
const
std
::
string
&
probe_func
)
{
if
(
tracepoints_
.
find
(
tracepoint
)
!=
tracepoints_
.
end
())
return
StatusTuple
(
-
1
,
"Tracepoint %s already attached"
,
tracepoint
.
c_str
());
...
...
@@ -268,17 +264,17 @@ StatusTuple BPF::attach_tracepoint(const std::string& tracepoint,
int
probe_fd
;
TRY2
(
load_func
(
probe_func
,
BPF_PROG_TYPE_TRACEPOINT
,
probe_fd
));
void
*
res
=
bpf_attach_tracepoint
(
probe_fd
,
tp_category
.
c_str
(),
tp_name
.
c_str
()
,
cb
,
cb_cookie
);
int
res_fd
=
bpf_attach_tracepoint
(
probe_fd
,
tp_category
.
c_str
(),
tp_name
.
c_str
());
if
(
!
res
)
{
if
(
res_fd
<
0
)
{
TRY2
(
unload_func
(
probe_func
));
return
StatusTuple
(
-
1
,
"Unable to attach Tracepoint %s using %s"
,
tracepoint
.
c_str
(),
probe_func
.
c_str
());
}
open_probe_t
p
=
{};
p
.
reader_ptr
=
res
;
p
.
perf_event_fd
=
res_fd
;
p
.
func
=
probe_func
;
tracepoints_
[
tracepoint
]
=
std
::
move
(
p
);
return
StatusTuple
(
0
);
...
...
@@ -558,10 +554,7 @@ std::string BPF::get_uprobe_event(const std::string& binary_path,
StatusTuple
BPF
::
detach_kprobe_event
(
const
std
::
string
&
event
,
open_probe_t
&
attr
)
{
if
(
attr
.
reader_ptr
)
{
perf_reader_free
(
attr
.
reader_ptr
);
attr
.
reader_ptr
=
nullptr
;
}
bpf_close_perf_event_fd
(
attr
.
perf_event_fd
);
TRY2
(
unload_func
(
attr
.
func
));
if
(
bpf_detach_kprobe
(
event
.
c_str
())
<
0
)
return
StatusTuple
(
-
1
,
"Unable to detach kprobe %s"
,
event
.
c_str
());
...
...
@@ -570,10 +563,7 @@ StatusTuple BPF::detach_kprobe_event(const std::string& event,
StatusTuple
BPF
::
detach_uprobe_event
(
const
std
::
string
&
event
,
open_probe_t
&
attr
)
{
if
(
attr
.
reader_ptr
)
{
perf_reader_free
(
attr
.
reader_ptr
);
attr
.
reader_ptr
=
nullptr
;
}
bpf_close_perf_event_fd
(
attr
.
perf_event_fd
);
TRY2
(
unload_func
(
attr
.
func
));
if
(
bpf_detach_uprobe
(
event
.
c_str
())
<
0
)
return
StatusTuple
(
-
1
,
"Unable to detach uprobe %s"
,
event
.
c_str
());
...
...
@@ -582,10 +572,7 @@ StatusTuple BPF::detach_uprobe_event(const std::string& event,
StatusTuple
BPF
::
detach_tracepoint_event
(
const
std
::
string
&
tracepoint
,
open_probe_t
&
attr
)
{
if
(
attr
.
reader_ptr
)
{
perf_reader_free
(
attr
.
reader_ptr
);
attr
.
reader_ptr
=
nullptr
;
}
bpf_close_perf_event_fd
(
attr
.
perf_event_fd
);
TRY2
(
unload_func
(
attr
.
func
));
// TODO: bpf_detach_tracepoint currently does nothing.
...
...
src/cc/api/BPF.h
View file @
1fe85d07
...
...
@@ -34,7 +34,7 @@ static const int DEFAULT_PERF_BUFFER_PAGE_CNT = 8;
namespace
ebpf
{
struct
open_probe_t
{
void
*
reader_ptr
;
int
perf_event_fd
;
std
::
string
func
;
std
::
map
<
int
,
int
>*
per_cpu_fd
;
};
...
...
@@ -57,9 +57,7 @@ class BPF {
StatusTuple
attach_kprobe
(
const
std
::
string
&
kernel_func
,
const
std
::
string
&
probe_func
,
bpf_probe_attach_type
=
BPF_PROBE_ENTRY
,
perf_reader_cb
cb
=
nullptr
,
void
*
cb_cookie
=
nullptr
);
bpf_probe_attach_type
=
BPF_PROBE_ENTRY
);
StatusTuple
detach_kprobe
(
const
std
::
string
&
kernel_func
,
bpf_probe_attach_type
attach_type
=
BPF_PROBE_ENTRY
);
...
...
@@ -69,8 +67,7 @@ class BPF {
const
std
::
string
&
probe_func
,
uint64_t
symbol_addr
=
0
,
bpf_probe_attach_type
attach_type
=
BPF_PROBE_ENTRY
,
pid_t
pid
=
-
1
,
perf_reader_cb
cb
=
nullptr
,
void
*
cb_cookie
=
nullptr
);
pid_t
pid
=
-
1
);
StatusTuple
detach_uprobe
(
const
std
::
string
&
binary_path
,
const
std
::
string
&
symbol
,
uint64_t
symbol_addr
=
0
,
bpf_probe_attach_type
attach_type
=
BPF_PROBE_ENTRY
,
...
...
@@ -79,9 +76,7 @@ class BPF {
StatusTuple
detach_usdt
(
const
USDT
&
usdt
);
StatusTuple
attach_tracepoint
(
const
std
::
string
&
tracepoint
,
const
std
::
string
&
probe_func
,
perf_reader_cb
cb
=
nullptr
,
void
*
cb_cookie
=
nullptr
);
const
std
::
string
&
probe_func
);
StatusTuple
detach_tracepoint
(
const
std
::
string
&
tracepoint
);
StatusTuple
attach_perf_event
(
uint32_t
ev_type
,
uint32_t
ev_config
,
...
...
src/cc/libbpf.c
View file @
1fe85d07
...
...
@@ -151,8 +151,6 @@ static struct bpf_helper helpers[] = {
{
"sock_ops_cb_flags_set"
,
"4.16"
},
};
static
int
probe_perf_reader_page_cnt
=
8
;
static
uint64_t
ptr_to_u64
(
void
*
ptr
)
{
return
(
uint64_t
)
(
unsigned
long
)
ptr
;
...
...
@@ -682,7 +680,6 @@ static int bpf_try_perf_event_open_with_probe(const char *name, uint64_t offs,
if
(
type
<
0
||
is_return_bit
<
0
)
return
-
1
;
attr
.
sample_type
=
PERF_SAMPLE_RAW
|
PERF_SAMPLE_CALLCHAIN
;
attr
.
sample_period
=
1
;
attr
.
wakeup_events
=
1
;
if
(
is_return
)
...
...
@@ -724,16 +721,23 @@ static int bpf_try_perf_event_open_with_probe(const char *name, uint64_t offs,
PERF_FLAG_FD_CLOEXEC
);
}
static
int
bpf_attach_tracing_event
(
int
progfd
,
const
char
*
event_path
,
struct
perf_reader
*
reader
,
int
pid
,
int
pfd
)
// When a valid Perf Event FD provided through pfd, it will be used to enable
// and attach BPF program to the event, and event_path will be ignored.
// Otherwise, event_path is expected to contain the path to the event in debugfs
// and it will be used to open the Perf Event FD.
// In either case, if the attach partially failed (such as issue with the
// ioctl operations), the **caller** need to clean up the Perf Event FD, either
// provided by the caller or opened here.
static
int
bpf_attach_tracing_event
(
int
progfd
,
const
char
*
event_path
,
int
pid
,
int
*
pfd
)
{
int
efd
,
cpu
=
0
;
ssize_t
bytes
;
char
buf
[
PATH_MAX
];
struct
perf_event_attr
attr
=
{};
if
(
pfd
<
0
)
{
// Caller did not provided a valid Perf Event FD. Create one with the debugfs
// event path provided.
if
(
*
pfd
<
0
)
{
snprintf
(
buf
,
sizeof
(
buf
),
"%s/id"
,
event_path
);
efd
=
open
(
buf
,
O_RDONLY
,
0
);
if
(
efd
<
0
)
{
...
...
@@ -751,7 +755,6 @@ static int bpf_attach_tracing_event(int progfd, const char *event_path,
buf
[
bytes
]
=
'\0'
;
attr
.
config
=
strtol
(
buf
,
NULL
,
0
);
attr
.
type
=
PERF_TYPE_TRACEPOINT
;
attr
.
sample_type
=
PERF_SAMPLE_RAW
|
PERF_SAMPLE_CALLCHAIN
;
attr
.
sample_period
=
1
;
attr
.
wakeup_events
=
1
;
// PID filter is only possible for uprobe events.
...
...
@@ -762,22 +765,18 @@ static int bpf_attach_tracing_event(int progfd, const char *event_path,
// Tracing events do not do CPU filtering in any cases.
if
(
pid
!=
-
1
)
cpu
=
-
1
;
pfd
=
syscall
(
__NR_perf_event_open
,
&
attr
,
pid
,
cpu
,
-
1
/* group_fd */
,
PERF_FLAG_FD_CLOEXEC
);
if
(
pfd
<
0
)
{
*
pfd
=
syscall
(
__NR_perf_event_open
,
&
attr
,
pid
,
cpu
,
-
1
/* group_fd */
,
PERF_FLAG_FD_CLOEXEC
);
if
(
*
pfd
<
0
)
{
fprintf
(
stderr
,
"perf_event_open(%s/id): %s
\n
"
,
event_path
,
strerror
(
errno
));
return
-
1
;
}
}
perf_reader_set_fd
(
reader
,
pfd
);
if
(
perf_reader_mmap
(
reader
,
attr
.
type
,
attr
.
sample_type
)
<
0
)
return
-
1
;
if
(
ioctl
(
pfd
,
PERF_EVENT_IOC_SET_BPF
,
progfd
)
<
0
)
{
if
(
ioctl
(
*
pfd
,
PERF_EVENT_IOC_SET_BPF
,
progfd
)
<
0
)
{
perror
(
"ioctl(PERF_EVENT_IOC_SET_BPF)"
);
return
-
1
;
}
if
(
ioctl
(
pfd
,
PERF_EVENT_IOC_ENABLE
,
0
)
<
0
)
{
if
(
ioctl
(
*
pfd
,
PERF_EVENT_IOC_ENABLE
,
0
)
<
0
)
{
perror
(
"ioctl(PERF_EVENT_IOC_ENABLE)"
);
return
-
1
;
}
...
...
@@ -785,24 +784,19 @@ static int bpf_attach_tracing_event(int progfd, const char *event_path,
return
0
;
}
void
*
bpf_attach_kprobe
(
int
progfd
,
enum
bpf_probe_attach_type
attach_type
,
const
char
*
ev_name
,
const
char
*
fn_name
,
perf_reader_cb
cb
,
void
*
cb_cookie
)
int
bpf_attach_kprobe
(
int
progfd
,
enum
bpf_probe_attach_type
attach_type
,
const
char
*
ev_name
,
const
char
*
fn_name
)
{
int
kfd
;
int
pfd
;
int
kfd
,
pfd
=
-
1
;
char
buf
[
256
];
char
event_alias
[
128
];
struct
perf_reader
*
reader
=
NULL
;
static
char
*
event_type
=
"kprobe"
;
reader
=
perf_reader_new
(
cb
,
NULL
,
NULL
,
cb_cookie
,
probe_perf_reader_page_cnt
);
if
(
!
reader
)
goto
error
;
// Try create the kprobe Perf Event with perf_event_open API.
pfd
=
bpf_try_perf_event_open_with_probe
(
fn_name
,
0
,
-
1
,
event_type
,
attach_type
!=
BPF_PROBE_ENTRY
);
// If failed, most likely Kernel doesn't support the new perf_event_open API
// yet. Try create the event using debugfs.
if
(
pfd
<
0
)
{
snprintf
(
buf
,
sizeof
(
buf
),
"/sys/kernel/debug/tracing/%s_events"
,
event_type
);
kfd
=
open
(
buf
,
O_WRONLY
|
O_APPEND
,
0
);
...
...
@@ -823,15 +817,16 @@ void *bpf_attach_kprobe(int progfd, enum bpf_probe_attach_type attach_type,
close
(
kfd
);
snprintf
(
buf
,
sizeof
(
buf
),
"/sys/kernel/debug/tracing/events/%ss/%s"
,
event_type
,
event_alias
);
}
if
(
bpf_attach_tracing_event
(
progfd
,
buf
,
reader
,
-
1
/* PID */
,
pfd
)
<
0
)
goto
error
;
return
reader
;
// If perf_event_open succeeded, bpf_attach_tracing_event will use the created
// Perf Event FD directly and buf would be empty and unused.
// Otherwise it will read the event ID from the path in buf, create the
// Perf Event event using that ID, and updated value of pfd.
if
(
bpf_attach_tracing_event
(
progfd
,
buf
,
-
1
/* PID */
,
&
pfd
)
==
0
)
return
pfd
;
error:
perf_reader_free
(
reader
);
return
NULL
;
bpf_close_perf_event_fd
(
pfd
);
return
-
1
;
}
static
int
enter_mount_ns
(
int
pid
)
{
...
...
@@ -895,24 +890,19 @@ static void exit_mount_ns(int fd) {
perror
(
"setns"
);
}
void
*
bpf_attach_uprobe
(
int
progfd
,
enum
bpf_probe_attach_type
attach_type
,
int
bpf_attach_uprobe
(
int
progfd
,
enum
bpf_probe_attach_type
attach_type
,
const
char
*
ev_name
,
const
char
*
binary_path
,
uint64_t
offset
,
pid_t
pid
,
perf_reader_cb
cb
,
void
*
cb_cookie
)
uint64_t
offset
,
pid_t
pid
)
{
char
buf
[
PATH_MAX
];
char
event_alias
[
PATH_MAX
];
struct
perf_reader
*
reader
=
NULL
;
static
char
*
event_type
=
"uprobe"
;
int
res
,
kfd
=
-
1
,
ns_fd
=
-
1
;
int
pfd
;
reader
=
perf_reader_new
(
cb
,
NULL
,
NULL
,
cb_cookie
,
probe_perf_reader_page_cnt
);
if
(
!
reader
)
goto
error
;
int
res
,
kfd
=
-
1
,
pfd
=
-
1
,
ns_fd
=
-
1
;
// Try create the uprobe Perf Event with perf_event_open API.
pfd
=
bpf_try_perf_event_open_with_probe
(
binary_path
,
offset
,
pid
,
event_type
,
attach_type
!=
BPF_PROBE_ENTRY
);
// If failed, most likely Kernel doesn't support the new perf_event_open API
// yet. Try create the event using debugfs.
if
(
pfd
<
0
)
{
snprintf
(
buf
,
sizeof
(
buf
),
"/sys/kernel/debug/tracing/%s_events"
,
event_type
);
kfd
=
open
(
buf
,
O_WRONLY
|
O_APPEND
,
0
);
...
...
@@ -940,22 +930,25 @@ void *bpf_attach_uprobe(int progfd, enum bpf_probe_attach_type attach_type,
goto
error
;
}
close
(
kfd
);
kfd
=
-
1
;
exit_mount_ns
(
ns_fd
);
ns_fd
=
-
1
;
snprintf
(
buf
,
sizeof
(
buf
),
"/sys/kernel/debug/tracing/events/%ss/%s"
,
event_type
,
event_alias
);
}
if
(
bpf_attach_tracing_event
(
progfd
,
buf
,
reader
,
pid
,
pfd
)
<
0
)
goto
error
;
return
reader
;
// If perf_event_open succeeded, bpf_attach_tracing_event will use the created
// Perf Event FD directly and buf would be empty and unused.
// Otherwise it will read the event ID from the path in buf, create the
// Perf Event event using that ID, and updated value of pfd.
if
(
bpf_attach_tracing_event
(
progfd
,
buf
,
pid
,
&
pfd
)
==
0
)
return
pfd
;
error:
if
(
kfd
>=
0
)
close
(
kfd
);
exit_mount_ns
(
ns_fd
);
perf_reader_free
(
reader
);
return
NULL
;
bpf_close_perf_event_fd
(
pfd
);
return
-
1
;
}
static
int
bpf_detach_probe
(
const
char
*
ev_name
,
const
char
*
event_type
)
...
...
@@ -1036,26 +1029,19 @@ int bpf_detach_uprobe(const char *ev_name)
}
void
*
bpf_attach_tracepoint
(
int
progfd
,
const
char
*
tp_category
,
const
char
*
tp_name
,
perf_reader_cb
cb
,
void
*
cb_cookie
)
{
int
bpf_attach_tracepoint
(
int
progfd
,
const
char
*
tp_category
,
const
char
*
tp_name
)
{
char
buf
[
256
];
struct
perf_reader
*
reader
=
NULL
;
reader
=
perf_reader_new
(
cb
,
NULL
,
NULL
,
cb_cookie
,
probe_perf_reader_page_cnt
);
if
(
!
reader
)
goto
error
;
int
pfd
=
-
1
;
snprintf
(
buf
,
sizeof
(
buf
),
"/sys/kernel/debug/tracing/events/%s/%s"
,
tp_category
,
tp_name
);
if
(
bpf_attach_tracing_event
(
progfd
,
buf
,
reader
,
-
1
/* PID */
,
-
1
/* pfd */
)
<
0
)
goto
error
;
if
(
bpf_attach_tracing_event
(
progfd
,
buf
,
-
1
/* PID */
,
&
pfd
)
==
0
)
return
pfd
;
return
reader
;
error:
perf_reader_free
(
reader
);
return
NULL
;
bpf_close_perf_event_fd
(
pfd
);
return
-
1
;
}
int
bpf_detach_tracepoint
(
const
char
*
tp_category
,
const
char
*
tp_name
)
{
...
...
@@ -1071,7 +1057,7 @@ void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb,
struct
perf_event_attr
attr
=
{};
struct
perf_reader
*
reader
=
NULL
;
reader
=
perf_reader_new
(
NULL
,
raw_cb
,
lost_cb
,
cb_cookie
,
page_cnt
);
reader
=
perf_reader_new
(
raw_cb
,
lost_cb
,
cb_cookie
,
page_cnt
);
if
(
!
reader
)
goto
error
;
...
...
@@ -1088,7 +1074,7 @@ void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb,
}
perf_reader_set_fd
(
reader
,
pfd
);
if
(
perf_reader_mmap
(
reader
,
attr
.
type
,
attr
.
sample_type
)
<
0
)
if
(
perf_reader_mmap
(
reader
)
<
0
)
goto
error
;
if
(
ioctl
(
pfd
,
PERF_EVENT_IOC_ENABLE
,
0
)
<
0
)
{
...
...
src/cc/libbpf.h
View file @
1fe85d07
...
...
@@ -65,27 +65,20 @@ int bpf_attach_socket(int sockfd, int progfd);
* bind the raw socket to the interface 'name' */
int
bpf_open_raw_sock
(
const
char
*
name
);
typedef
void
(
*
perf_reader_cb
)(
void
*
cb_cookie
,
int
pid
,
uint64_t
callchain_num
,
void
*
callchain
);
typedef
void
(
*
perf_reader_raw_cb
)(
void
*
cb_cookie
,
void
*
raw
,
int
raw_size
);
typedef
void
(
*
perf_reader_lost_cb
)(
void
*
cb_cookie
,
uint64_t
lost
);
void
*
bpf_attach_kprobe
(
int
progfd
,
enum
bpf_probe_attach_type
attach_type
,
const
char
*
ev_name
,
const
char
*
fn_name
,
perf_reader_cb
cb
,
void
*
cb_cookie
);
int
bpf_attach_kprobe
(
int
progfd
,
enum
bpf_probe_attach_type
attach_type
,
const
char
*
ev_name
,
const
char
*
fn_name
);
int
bpf_detach_kprobe
(
const
char
*
ev_name
);
void
*
bpf_attach_uprobe
(
int
progfd
,
enum
bpf_probe_attach_type
attach_type
,
int
bpf_attach_uprobe
(
int
progfd
,
enum
bpf_probe_attach_type
attach_type
,
const
char
*
ev_name
,
const
char
*
binary_path
,
uint64_t
offset
,
pid_t
pid
,
perf_reader_cb
cb
,
void
*
cb_cookie
);
uint64_t
offset
,
pid_t
pid
);
int
bpf_detach_uprobe
(
const
char
*
ev_name
);
void
*
bpf_attach_tracepoint
(
int
progfd
,
const
char
*
tp_category
,
const
char
*
tp_name
,
perf_reader_cb
cb
,
void
*
cb_cookie
);
int
bpf_attach_tracepoint
(
int
progfd
,
const
char
*
tp_category
,
const
char
*
tp_name
);
int
bpf_detach_tracepoint
(
const
char
*
tp_category
,
const
char
*
tp_name
);
void
*
bpf_open_perf_buffer
(
perf_reader_raw_cb
raw_cb
,
...
...
src/cc/perf_reader.c
View file @
1fe85d07
...
...
@@ -37,7 +37,6 @@ enum {
};
struct
perf_reader
{
perf_reader_cb
cb
;
perf_reader_raw_cb
raw_cb
;
perf_reader_lost_cb
lost_cb
;
void
*
cb_cookie
;
// to be returned in the cb
...
...
@@ -49,18 +48,14 @@ struct perf_reader {
int
page_size
;
int
page_cnt
;
int
fd
;
uint32_t
type
;
uint64_t
sample_type
;
};
struct
perf_reader
*
perf_reader_new
(
perf_reader_cb
cb
,
perf_reader_raw_cb
raw_cb
,
struct
perf_reader
*
perf_reader_new
(
perf_reader_raw_cb
raw_cb
,
perf_reader_lost_cb
lost_cb
,
void
*
cb_cookie
,
int
page_cnt
)
{
struct
perf_reader
*
reader
=
calloc
(
1
,
sizeof
(
struct
perf_reader
));
if
(
!
reader
)
return
NULL
;
reader
->
cb
=
cb
;
reader
->
raw_cb
=
raw_cb
;
reader
->
lost_cb
=
lost_cb
;
reader
->
cb_cookie
=
cb_cookie
;
...
...
@@ -89,7 +84,7 @@ void perf_reader_free(void *ptr) {
}
}
int
perf_reader_mmap
(
struct
perf_reader
*
reader
,
unsigned
type
,
unsigned
long
sample_type
)
{
int
perf_reader_mmap
(
struct
perf_reader
*
reader
)
{
int
mmap_size
=
reader
->
page_size
*
(
reader
->
page_cnt
+
1
);
if
(
reader
->
fd
<
0
)
{
...
...
@@ -102,8 +97,6 @@ int perf_reader_mmap(struct perf_reader *reader, unsigned type, unsigned long sa
perror
(
"mmap"
);
return
-
1
;
}
reader
->
type
=
type
;
reader
->
sample_type
=
sample_type
;
return
0
;
}
...
...
@@ -120,69 +113,6 @@ struct perf_sample_trace_kprobe {
uint64_t
ip
;
};
static
void
parse_tracepoint
(
struct
perf_reader
*
reader
,
void
*
data
,
int
size
)
{
uint8_t
*
ptr
=
data
;
struct
perf_event_header
*
header
=
(
void
*
)
data
;
struct
perf_sample_trace_kprobe
*
tk
=
NULL
;
uint64_t
*
callchain
=
NULL
;
uint64_t
num_callchain
=
0
;
ptr
+=
sizeof
(
*
header
);
if
(
ptr
>
(
uint8_t
*
)
data
+
size
)
{
fprintf
(
stderr
,
"%s: corrupt sample header
\n
"
,
__FUNCTION__
);
return
;
}
if
(
reader
->
sample_type
&
PERF_SAMPLE_CALLCHAIN
)
{
struct
{
uint64_t
nr
;
uint64_t
ips
[
0
];
}
*
cc
=
(
void
*
)
ptr
;
ptr
+=
sizeof
(
cc
->
nr
)
+
sizeof
(
*
cc
->
ips
)
*
cc
->
nr
;
// size sanity check
if
(
ptr
>
(
uint8_t
*
)
data
+
size
)
{
fprintf
(
stderr
,
"%s: corrupt callchain sample
\n
"
,
__FUNCTION__
);
return
;
}
int
i
;
// don't include magic numbers in the call chain
for
(
i
=
0
;
i
<
cc
->
nr
;
++
i
)
{
if
(
cc
->
ips
[
i
]
==
PERF_CONTEXT_USER
)
break
;
if
(
cc
->
ips
[
i
]
>=
PERF_CONTEXT_MAX
)
continue
;
if
(
!
callchain
)
callchain
=
&
cc
->
ips
[
i
];
++
num_callchain
;
}
}
// for kprobes, raw samples just include the common data structure and the
// instruction pointer
if
(
reader
->
sample_type
&
PERF_SAMPLE_RAW
)
{
struct
{
uint32_t
size
;
char
data
[
0
];
}
*
raw
=
(
void
*
)
ptr
;
ptr
+=
sizeof
(
raw
->
size
)
+
raw
->
size
;
if
(
ptr
>
(
uint8_t
*
)
data
+
size
)
{
fprintf
(
stderr
,
"%s: corrupt raw sample
\n
"
,
__FUNCTION__
);
return
;
}
tk
=
(
void
*
)
raw
->
data
;
}
// sanity check
if
(
ptr
!=
(
uint8_t
*
)
data
+
size
)
{
fprintf
(
stderr
,
"%s: extra data at end of sample
\n
"
,
__FUNCTION__
);
return
;
}
// call out to the user with the parsed data
if
(
reader
->
cb
)
reader
->
cb
(
reader
->
cb_cookie
,
tk
?
tk
->
common
.
pid
:
-
1
,
num_callchain
,
callchain
);
}
static
void
parse_sw
(
struct
perf_reader
*
reader
,
void
*
data
,
int
size
)
{
uint8_t
*
ptr
=
data
;
struct
perf_event_header
*
header
=
(
void
*
)
data
;
...
...
@@ -198,14 +128,12 @@ static void parse_sw(struct perf_reader *reader, void *data, int size) {
return
;
}
if
(
reader
->
sample_type
&
PERF_SAMPLE_RAW
)
{
raw
=
(
void
*
)
ptr
;
ptr
+=
sizeof
(
raw
->
size
)
+
raw
->
size
;
if
(
ptr
>
(
uint8_t
*
)
data
+
size
)
{
fprintf
(
stderr
,
"%s: corrupt raw sample
\n
"
,
__FUNCTION__
);
return
;
}
}
// sanity check
if
(
ptr
!=
(
uint8_t
*
)
data
+
size
)
{
...
...
@@ -278,9 +206,6 @@ void perf_reader_event_read(struct perf_reader *reader) {
fprintf
(
stderr
,
"Possibly lost %"
PRIu64
" samples
\n
"
,
lost
);
}
}
else
if
(
e
->
type
==
PERF_RECORD_SAMPLE
)
{
if
(
reader
->
type
==
PERF_TYPE_TRACEPOINT
)
parse_tracepoint
(
reader
,
ptr
,
e
->
size
);
else
if
(
reader
->
type
==
PERF_TYPE_SOFTWARE
)
parse_sw
(
reader
,
ptr
,
e
->
size
);
}
else
{
fprintf
(
stderr
,
"%s: unknown sample type %d
\n
"
,
__FUNCTION__
,
e
->
type
);
...
...
src/cc/perf_reader.h
View file @
1fe85d07
...
...
@@ -25,12 +25,11 @@ extern "C" {
struct
perf_reader
;
struct
perf_reader
*
perf_reader_new
(
perf_reader_cb
cb
,
perf_reader_raw_cb
raw_cb
,
struct
perf_reader
*
perf_reader_new
(
perf_reader_raw_cb
raw_cb
,
perf_reader_lost_cb
lost_cb
,
void
*
cb_cookie
,
int
page_cnt
);
void
perf_reader_free
(
void
*
ptr
);
int
perf_reader_mmap
(
struct
perf_reader
*
reader
,
unsigned
type
,
unsigned
long
sample_type
);
int
perf_reader_mmap
(
struct
perf_reader
*
reader
);
void
perf_reader_event_read
(
struct
perf_reader
*
reader
);
int
perf_reader_poll
(
int
num_readers
,
struct
perf_reader
**
readers
,
int
timeout
);
int
perf_reader_fd
(
struct
perf_reader
*
reader
);
...
...
src/lua/bcc/bpf.lua
View file @
1fe85d07
...
...
@@ -24,6 +24,7 @@ local Bpf = class("BPF")
Bpf
.
static
.
open_kprobes
=
{}
Bpf
.
static
.
open_uprobes
=
{}
Bpf
.
static
.
perf_buffers
=
{}
Bpf
.
static
.
KPROBE_LIMIT
=
1000
Bpf
.
static
.
tracer_pipe
=
nil
Bpf
.
static
.
DEFAULT_CFLAGS
=
{
...
...
@@ -39,8 +40,8 @@ end
function
Bpf
.
static
.
cleanup
()
local
function
detach_all
(
probe_type
,
all_probes
)
for
key
,
probe
in
pairs
(
all_probes
)
do
libbcc
.
perf_reader_free
(
probe
)
for
key
,
fd
in
pairs
(
all_probes
)
do
libbcc
.
bpf_close_perf_event_fd
(
fd
)
-- skip bcc-specific kprobes
if
not
key
:
starts
(
"bcc:"
)
then
if
probe_type
==
"kprobes"
then
...
...
@@ -55,6 +56,12 @@ function Bpf.static.cleanup()
detach_all
(
"kprobes"
,
Bpf
.
static
.
open_kprobes
)
detach_all
(
"uprobes"
,
Bpf
.
static
.
open_uprobes
)
for
key
,
perf_buffer
in
pairs
(
Bpf
.
static
.
perf_buffers
)
do
libbcc
.
perf_reader_free
(
perf_buffer
)
Bpf
.
static
.
perf_buffers
[
key
]
=
nil
end
if
Bpf
.
static
.
tracer_pipe
~=
nil
then
Bpf
.
static
.
tracer_pipe
:
close
()
end
...
...
@@ -189,9 +196,9 @@ function Bpf:attach_uprobe(args)
local
retprobe
=
args
.
retprobe
and
1
or
0
local
res
=
libbcc
.
bpf_attach_uprobe
(
fn
.
fd
,
retprobe
,
ev_name
,
path
,
addr
,
args
.
pid
or
-
1
,
nil
,
nil
)
-- TODO; reader callback
args
.
pid
or
-
1
)
assert
(
res
~=
nil
,
"failed to attach BPF to uprobe"
)
assert
(
res
>=
0
,
"failed to attach BPF to uprobe"
)
self
:
probe_store
(
"uprobe"
,
ev_name
,
res
)
return
self
end
...
...
@@ -206,10 +213,9 @@ function Bpf:attach_kprobe(args)
local
ev_name
=
string.format
(
"%s_%s"
,
ptype
,
event
:
gsub
(
"
[
%+%.
]
"
,
"_"
))
local
retprobe
=
args
.
retprobe
and
1
or
0
local
res
=
libbcc
.
bpf_attach_kprobe
(
fn
.
fd
,
retprobe
,
ev_name
,
event
,
nil
,
nil
)
-- TODO; reader callback
local
res
=
libbcc
.
bpf_attach_kprobe
(
fn
.
fd
,
retprobe
,
ev_name
,
event
)
assert
(
res
~=
nil
,
"failed to attach BPF to kprobe"
)
assert
(
res
>=
0
,
"failed to attach BPF to kprobe"
)
self
:
probe_store
(
"kprobe"
,
ev_name
,
res
)
return
self
end
...
...
@@ -228,16 +234,22 @@ function Bpf:get_table(name, key_type, leaf_type)
return
self
.
tables
[
name
]
end
function
Bpf
:
probe_store
(
t
,
id
,
reader
)
function
Bpf
:
probe_store
(
t
,
id
,
fd
)
if
t
==
"kprobe"
then
Bpf
.
open_kprobes
[
id
]
=
reader
Bpf
.
open_kprobes
[
id
]
=
fd
elseif
t
==
"uprobe"
then
Bpf
.
open_uprobes
[
id
]
=
reader
Bpf
.
open_uprobes
[
id
]
=
fd
else
error
(
"unknown probe type '%s'"
%
t
)
end
log
.
info
(
"%s -> %s"
,
id
,
reader
)
log
.
info
(
"%s -> %s"
,
id
,
fd
)
end
function
Bpf
:
perf_buffer_store
(
t
,
id
,
reader
)
Bpf
.
perf_buffers
[
id
]
=
reader
log
.
info
(
"%s -> %s"
,
id
,
fd
)
end
function
Bpf
:
probe_lookup
(
t
,
id
)
...
...
@@ -250,32 +262,32 @@ function Bpf:probe_lookup(t, id)
end
end
function
Bpf
:
_
kprobe
_array
()
local
kprobe_count
=
table
.
count
(
Bpf
.
open_kprobe
s
)
local
readers
=
ffi
.
new
(
"struct perf_reader*[?]"
,
kprobe
_count
)
function
Bpf
:
_
perf_buffer
_array
()
local
perf_buffer_count
=
table
.
count
(
Bpf
.
perf_buffer
s
)
local
readers
=
ffi
.
new
(
"struct perf_reader*[?]"
,
perf_buffer
_count
)
local
n
=
0
for
_
,
r
in
pairs
(
Bpf
.
open_kprobe
s
)
do
for
_
,
r
in
pairs
(
Bpf
.
perf_buffer
s
)
do
readers
[
n
]
=
r
n
=
n
+
1
end
assert
(
n
==
kprobe
_count
)
assert
(
n
==
perf_buffer
_count
)
return
readers
,
n
end
function
Bpf
:
kprobe_poll_loop
()
local
p
robes
,
probe_count
=
self
:
_kprobe
_array
()
local
p
erf_buffer
,
perf_buffer_count
=
self
:
_perf_buffer
_array
()
return
pcall
(
function
()
while
true
do
libbcc
.
perf_reader_poll
(
p
robe_count
,
probe
s
,
-
1
)
libbcc
.
perf_reader_poll
(
p
erf_buffer_count
,
perf_buffer
s
,
-
1
)
end
end
)
end
function
Bpf
:
kprobe_poll
(
timeout
)
local
p
robes
,
probe_count
=
self
:
_kprobe
_array
()
libbcc
.
perf_reader_poll
(
p
robe_count
,
probe
s
,
timeout
or
-
1
)
local
p
erf_buffer
,
perf_buffer_count
=
self
:
_perf_buffer
_array
()
libbcc
.
perf_reader_poll
(
p
erf_buffer_count
,
perf_buffer
s
,
timeout
or
-
1
)
end
return
Bpf
src/lua/bcc/libbcc.lua
View file @
1fe85d07
...
...
@@ -39,23 +39,22 @@ int bpf_attach_socket(int sockfd, int progfd);
/* create RAW socket and bind to interface 'name' */
int bpf_open_raw_sock(const char *name);
typedef void (*perf_reader_cb)(void *cb_cookie, int pid, uint64_t callchain_num, void *callchain);
typedef void (*perf_reader_raw_cb)(void *cb_cookie, void *raw, int raw_size);
typedef void (*perf_reader_lost_cb)(void *cb_cookie, uint64_t lost);
void *bpf_attach_kprobe(int progfd, int attach_type, const char *ev_name,
const char *fn_name, perf_reader_cb cb,
void *cb_cookie);
int bpf_attach_kprobe(int progfd, int attach_type, const char *ev_name,
const char *fn_name);
int bpf_detach_kprobe(const char *ev_name);
void *bpf_attach_uprobe(int progfd, int attach_type, const char *ev_name,
const char *binary_path, uint64_t offset, int pid,
perf_reader_cb cb, void *cb_cookie);
int bpf_attach_uprobe(int progfd, int attach_type, const char *ev_name,
const char *binary_path, uint64_t offset, int pid);
int bpf_detach_uprobe(const char *ev_name);
void * bpf_open_perf_buffer(perf_reader_raw_cb raw_cb, perf_reader_lost_cb lost_cb, void *cb_cookie, int pid, int cpu, int page_cnt);
int bpf_close_perf_event_fd(int fd);
]]
ffi
.
cdef
[[
...
...
@@ -100,7 +99,7 @@ ffi.cdef[[
struct perf_reader;
void perf_reader_free(void *ptr);
int perf_reader_mmap(struct perf_reader *reader
, unsigned type, unsigned long sample_type
);
int perf_reader_mmap(struct perf_reader *reader);
int perf_reader_poll(int num_readers, struct perf_reader **readers, int timeout);
int perf_reader_fd(struct perf_reader *reader);
void perf_reader_set_fd(struct perf_reader *reader, int fd);
...
...
src/lua/bcc/table.lua
View file @
1fe85d07
...
...
@@ -263,7 +263,7 @@ function PerfEventArray:_open_perf_buffer(cpu, callback, ctype, page_cnt, lost_c
local
fd
=
libbcc
.
perf_reader_fd
(
reader
)
self
:
set
(
cpu
,
fd
)
self
.
bpf
:
p
robe_store
(
"kprobe"
,
_perf_id
(
self
.
map_id
,
cpu
),
reader
)
self
.
bpf
:
p
erf_buffer_store
(
_perf_id
(
self
.
map_id
,
cpu
),
reader
)
self
.
_callbacks
[
cpu
]
=
_cb
end
...
...
src/python/bcc/__init__.py
View file @
1fe85d07
...
...
@@ -24,12 +24,12 @@ import errno
import
sys
basestring
=
(
unicode
if
sys
.
version_info
[
0
]
<
3
else
str
)
from
.libbcc
import
lib
,
_CB_TYPE
,
bcc_symbol
,
bcc_symbol_option
,
_SYM_CB_TYPE
from
.libbcc
import
lib
,
bcc_symbol
,
bcc_symbol_option
,
_SYM_CB_TYPE
from
.table
import
Table
,
PerfEventArray
from
.perf
import
Perf
from
.utils
import
get_online_cpus
,
printb
,
_assert_is_bytes
,
ArgString
_
k
probe_limit
=
1000
_probe_limit
=
1000
_num_open_probes
=
0
# for tests
...
...
@@ -244,7 +244,7 @@ class BPF(object):
return
exe_file
return
None
def
__init__
(
self
,
src_file
=
b""
,
hdr_file
=
b""
,
text
=
None
,
cb
=
None
,
debug
=
0
,
def
__init__
(
self
,
src_file
=
b""
,
hdr_file
=
b""
,
text
=
None
,
debug
=
0
,
cflags
=
[],
usdt_contexts
=
[]):
"""Create a new BPF module with the given source code.
...
...
@@ -264,15 +264,14 @@ class BPF(object):
hdr_file
=
_assert_is_bytes
(
hdr_file
)
text
=
_assert_is_bytes
(
text
)
self
.
open_kprobes
=
{}
self
.
open_uprobes
=
{}
self
.
open_tracepoints
=
{}
self
.
kprobe_fds
=
{}
self
.
uprobe_fds
=
{}
self
.
tracepoint_fds
=
{}
self
.
perf_buffers
=
{}
self
.
open_perf_events
=
{}
self
.
tracefile
=
None
atexit
.
register
(
self
.
cleanup
)
self
.
_reader_cb_impl
=
_CB_TYPE
(
BPF
.
_reader_cb
)
self
.
_user_cb
=
cb
self
.
debug
=
debug
self
.
funcs
=
{}
self
.
tables
=
{}
...
...
@@ -461,11 +460,6 @@ class BPF(object):
def
__iter__
(
self
):
return
self
.
tables
.
__iter__
()
def
_reader_cb
(
self
,
pid
,
callchain_num
,
callchain
):
if
self
.
_user_cb
:
cc
=
tuple
(
callchain
[
i
]
for
i
in
range
(
0
,
callchain_num
))
self
.
_user_cb
(
pid
,
cc
)
@
staticmethod
def
attach_raw_socket
(
fn
,
dev
):
dev
=
_assert_is_bytes
(
dev
)
...
...
@@ -497,17 +491,27 @@ class BPF(object):
def
_check_probe_quota
(
self
,
num_new_probes
):
global
_num_open_probes
if
_num_open_probes
+
num_new_probes
>
_
k
probe_limit
:
if
_num_open_probes
+
num_new_probes
>
_probe_limit
:
raise
Exception
(
"Number of open probes would exceed global quota"
)
def
_add_kprobe
(
self
,
name
,
probe
):
def
_add_kprobe
_fd
(
self
,
name
,
fd
):
global
_num_open_probes
self
.
open_kprobes
[
name
]
=
probe
self
.
kprobe_fds
[
name
]
=
fd
_num_open_probes
+=
1
def
_del_kprobe
(
self
,
name
):
def
_del_kprobe
_fd
(
self
,
name
):
global
_num_open_probes
del
self
.
open_kprobes
[
name
]
del
self
.
kprobe_fds
[
name
]
_num_open_probes
-=
1
def
_add_uprobe_fd
(
self
,
name
,
fd
):
global
_num_open_probes
self
.
uprobe_fds
[
name
]
=
fd
_num_open_probes
+=
1
def
_del_uprobe_fd
(
self
,
name
):
global
_num_open_probes
del
self
.
uprobe_fds
[
name
]
_num_open_probes
-=
1
def
attach_kprobe
(
self
,
event
=
b""
,
fn_name
=
b""
,
event_re
=
b""
):
...
...
@@ -529,25 +533,12 @@ class BPF(object):
self
.
_check_probe_quota
(
1
)
fn
=
self
.
load_func
(
fn_name
,
BPF
.
KPROBE
)
ev_name
=
b"p_"
+
event
.
replace
(
b"+"
,
b"_"
).
replace
(
b"."
,
b"_"
)
res
=
lib
.
bpf_attach_kprobe
(
fn
.
fd
,
0
,
ev_name
,
event
,
self
.
_reader_cb_impl
,
ct
.
cast
(
id
(
self
),
ct
.
py_object
))
res
=
ct
.
cast
(
res
,
ct
.
c_void_p
)
if
not
res
:
fd
=
lib
.
bpf_attach_kprobe
(
fn
.
fd
,
0
,
ev_name
,
event
)
if
fd
<
0
:
raise
Exception
(
"Failed to attach BPF to kprobe"
)
self
.
_add_kprobe
(
ev_name
,
res
)
self
.
_add_kprobe
_fd
(
ev_name
,
fd
)
return
self
def
detach_kprobe
(
self
,
event
):
event
=
_assert_is_bytes
(
event
)
ev_name
=
b"p_"
+
event
.
replace
(
b"+"
,
b"_"
).
replace
(
b"."
,
b"_"
)
if
ev_name
not
in
self
.
open_kprobes
:
raise
Exception
(
"Kprobe %s is not attached"
%
event
)
lib
.
perf_reader_free
(
self
.
open_kprobes
[
ev_name
])
res
=
lib
.
bpf_detach_kprobe
(
ev_name
)
if
res
<
0
:
raise
Exception
(
"Failed to detach BPF from kprobe"
)
self
.
_del_kprobe
(
ev_name
)
def
attach_kretprobe
(
self
,
event
=
b""
,
fn_name
=
b""
,
event_re
=
b""
):
event
=
_assert_is_bytes
(
event
)
fn_name
=
_assert_is_bytes
(
fn_name
)
...
...
@@ -565,25 +556,32 @@ class BPF(object):
self
.
_check_probe_quota
(
1
)
fn
=
self
.
load_func
(
fn_name
,
BPF
.
KPROBE
)
ev_name
=
b"r_"
+
event
.
replace
(
b"+"
,
b"_"
).
replace
(
b"."
,
b"_"
)
res
=
lib
.
bpf_attach_kprobe
(
fn
.
fd
,
1
,
ev_name
,
event
,
self
.
_reader_cb_impl
,
ct
.
cast
(
id
(
self
),
ct
.
py_object
))
res
=
ct
.
cast
(
res
,
ct
.
c_void_p
)
if
not
res
:
fd
=
lib
.
bpf_attach_kprobe
(
fn
.
fd
,
1
,
ev_name
,
event
)
if
fd
<
0
:
raise
Exception
(
"Failed to attach BPF to kprobe"
)
self
.
_add_kprobe
(
ev_name
,
res
)
self
.
_add_kprobe
_fd
(
ev_name
,
fd
)
return
self
def
detach_k
retprobe
(
self
,
event
):
event
=
_assert_is_bytes
(
event
)
ev_name
=
b"r_"
+
event
.
replace
(
b"+"
,
b"_"
).
replace
(
b"."
,
b"_"
)
if
ev_name
not
in
self
.
open_kprobes
:
raise
Exception
(
"Kretprobe %s is not attached"
%
event
)
lib
.
perf_reader_free
(
self
.
open_kprobes
[
ev_name
]
)
def
detach_k
probe_event
(
self
,
ev_name
):
if
ev_name
not
in
self
.
kprobe_fds
:
raise
Exception
(
"Kprobe %s is not attached"
%
event
)
res
=
lib
.
bpf_close_perf_event_fd
(
self
.
kprobe_fds
[
ev_name
])
if
res
<
0
:
raise
Exception
(
"Failed to close kprobe FD"
)
res
=
lib
.
bpf_detach_kprobe
(
ev_name
)
if
res
<
0
:
raise
Exception
(
"Failed to detach BPF from kprobe"
)
self
.
_del_kprobe
(
ev_name
)
self
.
_del_kprobe_fd
(
ev_name
)
def
detach_kprobe
(
self
,
event
):
event
=
_assert_is_bytes
(
event
)
ev_name
=
b"p_"
+
event
.
replace
(
b"+"
,
b"_"
).
replace
(
b"."
,
b"_"
)
self
.
detach_kprobe_event
(
ev_name
)
def
detach_kretprobe
(
self
,
event
):
event
=
_assert_is_bytes
(
event
)
ev_name
=
b"r_"
+
event
.
replace
(
b"+"
,
b"_"
).
replace
(
b"."
,
b"_"
)
self
.
detach_kprobe_event
(
ev_name
)
@
staticmethod
def
attach_xdp
(
dev
,
fn
,
flags
=
0
):
...
...
@@ -699,12 +697,10 @@ class BPF(object):
fn
=
self
.
load_func
(
fn_name
,
BPF
.
TRACEPOINT
)
(
tp_category
,
tp_name
)
=
tp
.
split
(
b':'
)
res
=
lib
.
bpf_attach_tracepoint
(
fn
.
fd
,
tp_category
,
tp_name
,
self
.
_reader_cb_impl
,
ct
.
cast
(
id
(
self
),
ct
.
py_object
))
res
=
ct
.
cast
(
res
,
ct
.
c_void_p
)
if
not
res
:
fd
=
lib
.
bpf_attach_tracepoint
(
fn
.
fd
,
tp_category
,
tp_name
)
if
fd
<
0
:
raise
Exception
(
"Failed to attach BPF to tracepoint"
)
self
.
open_tracepoints
[
tp
]
=
res
self
.
tracepoint_fds
[
tp
]
=
fd
return
self
def
detach_tracepoint
(
self
,
tp
=
b""
):
...
...
@@ -717,14 +713,16 @@ class BPF(object):
"""
tp
=
_assert_is_bytes
(
tp
)
if
tp
not
in
self
.
open_tracepoint
s
:
if
tp
not
in
self
.
tracepoint_fd
s
:
raise
Exception
(
"Tracepoint %s is not attached"
%
tp
)
lib
.
perf_reader_free
(
self
.
open_tracepoints
[
tp
])
res
=
lib
.
bpf_close_perf_event_fd
(
self
.
tracepoint_fds
[
tp
])
if
res
<
0
:
raise
Exception
(
"Failed to detach BPF from tracepoint"
)
(
tp_category
,
tp_name
)
=
tp
.
split
(
b':'
)
res
=
lib
.
bpf_detach_tracepoint
(
tp_category
,
tp_name
)
if
res
<
0
:
raise
Exception
(
"Failed to detach BPF from tracepoint"
)
del
self
.
open_tracepoint
s
[
tp
]
del
self
.
tracepoint_fd
s
[
tp
]
def
_attach_perf_event
(
self
,
progfd
,
ev_type
,
ev_config
,
sample_period
,
sample_freq
,
pid
,
cpu
,
group_fd
):
...
...
@@ -762,16 +760,6 @@ class BPF(object):
raise
Exception
(
"Failed to detach BPF from perf event"
)
del
self
.
open_perf_events
[(
ev_type
,
ev_config
)]
def
_add_uprobe
(
self
,
name
,
probe
):
global
_num_open_probes
self
.
open_uprobes
[
name
]
=
probe
_num_open_probes
+=
1
def
_del_uprobe
(
self
,
name
):
global
_num_open_probes
del
self
.
open_uprobes
[
name
]
_num_open_probes
-=
1
@
staticmethod
def
get_user_functions
(
name
,
sym_re
):
return
set
([
name
for
(
name
,
_
)
in
...
...
@@ -855,33 +843,12 @@ class BPF(object):
self
.
_check_probe_quota
(
1
)
fn
=
self
.
load_func
(
fn_name
,
BPF
.
KPROBE
)
ev_name
=
self
.
_get_uprobe_evname
(
b"p"
,
path
,
addr
,
pid
)
res
=
lib
.
bpf_attach_uprobe
(
fn
.
fd
,
0
,
ev_name
,
path
,
addr
,
pid
,
self
.
_reader_cb_impl
,
ct
.
cast
(
id
(
self
),
ct
.
py_object
))
res
=
ct
.
cast
(
res
,
ct
.
c_void_p
)
if
not
res
:
fd
=
lib
.
bpf_attach_uprobe
(
fn
.
fd
,
0
,
ev_name
,
path
,
addr
,
pid
)
if
fd
<
0
:
raise
Exception
(
"Failed to attach BPF to uprobe"
)
self
.
_add_uprobe
(
ev_name
,
res
)
self
.
_add_uprobe
_fd
(
ev_name
,
fd
)
return
self
def
detach_uprobe
(
self
,
name
=
b""
,
sym
=
b""
,
addr
=
None
,
pid
=-
1
):
"""detach_uprobe(name="", sym="", addr=None, pid=-1)
Stop running a bpf function that is attached to symbol 'sym' in library
or binary 'name'.
"""
name
=
_assert_is_bytes
(
name
)
sym
=
_assert_is_bytes
(
sym
)
(
path
,
addr
)
=
BPF
.
_check_path_symbol
(
name
,
sym
,
addr
,
pid
)
ev_name
=
self
.
_get_uprobe_evname
(
b"p"
,
path
,
addr
,
pid
)
if
ev_name
not
in
self
.
open_uprobes
:
raise
Exception
(
"Uprobe %s is not attached"
%
ev_name
)
lib
.
perf_reader_free
(
self
.
open_uprobes
[
ev_name
])
res
=
lib
.
bpf_detach_uprobe
(
ev_name
)
if
res
<
0
:
raise
Exception
(
"Failed to detach BPF from uprobe"
)
self
.
_del_uprobe
(
ev_name
)
def
attach_uretprobe
(
self
,
name
=
b""
,
sym
=
b""
,
sym_re
=
b""
,
addr
=
None
,
fn_name
=
b""
,
pid
=-
1
):
"""attach_uretprobe(name="", sym="", sym_re="", addr=None, fn_name=""
...
...
@@ -908,14 +875,36 @@ class BPF(object):
self
.
_check_probe_quota
(
1
)
fn
=
self
.
load_func
(
fn_name
,
BPF
.
KPROBE
)
ev_name
=
self
.
_get_uprobe_evname
(
b"r"
,
path
,
addr
,
pid
)
res
=
lib
.
bpf_attach_uprobe
(
fn
.
fd
,
1
,
ev_name
,
path
,
addr
,
pid
,
self
.
_reader_cb_impl
,
ct
.
cast
(
id
(
self
),
ct
.
py_object
))
res
=
ct
.
cast
(
res
,
ct
.
c_void_p
)
if
not
res
:
fd
=
lib
.
bpf_attach_uprobe
(
fn
.
fd
,
1
,
ev_name
,
path
,
addr
,
pid
)
if
fd
<
0
:
raise
Exception
(
"Failed to attach BPF to uprobe"
)
self
.
_add_uprobe
(
ev_name
,
res
)
self
.
_add_uprobe
_fd
(
ev_name
,
fd
)
return
self
def
detach_uprobe_event
(
self
,
ev_name
):
if
ev_name
not
in
self
.
uprobe_fds
:
raise
Exception
(
"Uprobe %s is not attached"
%
ev_name
)
res
=
lib
.
bpf_close_perf_event_fd
(
self
.
uprobe_fds
[
ev_name
])
if
res
<
0
:
raise
Exception
(
"Failed to detach BPF from uprobe"
)
res
=
lib
.
bpf_detach_uprobe
(
ev_name
)
if
res
<
0
:
raise
Exception
(
"Failed to detach BPF from uprobe"
)
self
.
_del_uprobe_fd
(
ev_name
)
def
detach_uprobe
(
self
,
name
=
b""
,
sym
=
b""
,
addr
=
None
,
pid
=-
1
):
"""detach_uprobe(name="", sym="", addr=None, pid=-1)
Stop running a bpf function that is attached to symbol 'sym' in library
or binary 'name'.
"""
name
=
_assert_is_bytes
(
name
)
sym
=
_assert_is_bytes
(
sym
)
(
path
,
addr
)
=
BPF
.
_check_path_symbol
(
name
,
sym
,
addr
,
pid
)
ev_name
=
self
.
_get_uprobe_evname
(
b"p"
,
path
,
addr
,
pid
)
self
.
detach_uprobe_event
(
ev_name
)
def
detach_uretprobe
(
self
,
name
=
b""
,
sym
=
b""
,
addr
=
None
,
pid
=-
1
):
"""detach_uretprobe(name="", sym="", addr=None, pid=-1)
...
...
@@ -928,13 +917,7 @@ class BPF(object):
(
path
,
addr
)
=
BPF
.
_check_path_symbol
(
name
,
sym
,
addr
,
pid
)
ev_name
=
self
.
_get_uprobe_evname
(
b"r"
,
path
,
addr
,
pid
)
if
ev_name
not
in
self
.
open_uprobes
:
raise
Exception
(
"Uretprobe %s is not attached"
%
ev_name
)
lib
.
perf_reader_free
(
self
.
open_uprobes
[
ev_name
])
res
=
lib
.
bpf_detach_uprobe
(
ev_name
)
if
res
<
0
:
raise
Exception
(
"Failed to detach BPF from uprobe"
)
self
.
_del_uprobe
(
ev_name
)
self
.
detach_uprobe_event
(
ev_name
)
def
_trace_autoload
(
self
):
for
i
in
range
(
0
,
lib
.
bpf_num_functions
(
self
.
module
)):
...
...
@@ -1099,24 +1082,23 @@ class BPF(object):
"""num_open_kprobes()
Get the number of open K[ret]probes. Can be useful for scenarios where
event_re is used while attaching and detaching probes. Excludes
perf_events readers.
event_re is used while attaching and detaching probes.
"""
return
len
(
[
k
for
k
in
self
.
open_kprobes
.
keys
()
if
type
(
k
)
is
bytes
]
)
return
len
(
self
.
kprobe_fds
)
def
num_open_uprobes
(
self
):
"""num_open_uprobes()
Get the number of open U[ret]probes.
"""
return
len
(
self
.
open_uprobe
s
)
return
len
(
self
.
uprobe_fd
s
)
def
num_open_tracepoints
(
self
):
"""num_open_tracepoints()
Get the number of open tracepoints.
"""
return
len
(
self
.
open_tracepoint
s
)
return
len
(
self
.
tracepoint_fd
s
)
def
kprobe_poll
(
self
,
timeout
=
-
1
):
"""kprobe_poll(self)
...
...
@@ -1125,10 +1107,10 @@ class BPF(object):
cb() that was given in the BPF constructor for each entry.
"""
try
:
readers
=
(
ct
.
c_void_p
*
len
(
self
.
open_kprobe
s
))()
for
i
,
v
in
enumerate
(
self
.
open_kprobe
s
.
values
()):
readers
=
(
ct
.
c_void_p
*
len
(
self
.
perf_buffer
s
))()
for
i
,
v
in
enumerate
(
self
.
perf_buffer
s
.
values
()):
readers
[
i
]
=
v
lib
.
perf_reader_poll
(
len
(
self
.
open_kprobe
s
),
readers
,
timeout
)
lib
.
perf_reader_poll
(
len
(
reader
s
),
readers
,
timeout
)
except
KeyboardInterrupt
:
exit
()
...
...
@@ -1136,26 +1118,19 @@ class BPF(object):
"""the do nothing exit handler"""
def
cleanup
(
self
):
for
k
,
v
in
list
(
self
.
open_kprobes
.
items
()):
# non-string keys here include the perf_events reader
if
isinstance
(
k
,
bytes
):
lib
.
perf_reader_free
(
v
)
lib
.
bpf_detach_kprobe
(
bytes
(
k
))
self
.
_del_kprobe
(
k
)
# clean up opened perf ring buffer and perf events
# Clean up opened probes
for
k
,
v
in
list
(
self
.
kprobe_fds
.
items
()):
self
.
detach_kprobe_event
(
k
)
for
k
,
v
in
list
(
self
.
uprobe_fds
.
items
()):
self
.
detach_uprobe_event
(
k
)
for
k
,
v
in
list
(
self
.
tracepoint_fds
.
items
()):
self
.
detach_tracepoint
(
k
)
# Clean up opened perf ring buffer and perf events
table_keys
=
list
(
self
.
tables
.
keys
())
for
key
in
table_keys
:
if
isinstance
(
self
.
tables
[
key
],
PerfEventArray
):
del
self
.
tables
[
key
]
for
k
,
v
in
list
(
self
.
open_uprobes
.
items
()):
lib
.
perf_reader_free
(
v
)
lib
.
bpf_detach_uprobe
(
bytes
(
k
))
self
.
_del_uprobe
(
k
)
for
k
,
v
in
self
.
open_tracepoints
.
items
():
lib
.
perf_reader_free
(
v
)
(
tp_category
,
tp_name
)
=
k
.
split
(
b':'
)
lib
.
bpf_detach_tracepoint
(
tp_category
,
tp_name
)
self
.
open_tracepoints
.
clear
()
for
(
ev_type
,
ev_config
)
in
list
(
self
.
open_perf_events
.
keys
()):
self
.
detach_perf_event
(
ev_type
,
ev_config
)
if
self
.
tracefile
:
...
...
src/python/bcc/libbcc.py
View file @
1fe85d07
...
...
@@ -85,23 +85,19 @@ lib.bpf_attach_socket.argtypes = [ct.c_int, ct.c_int]
lib
.
bpf_prog_load
.
restype
=
ct
.
c_int
lib
.
bpf_prog_load
.
argtypes
=
[
ct
.
c_int
,
ct
.
c_char_p
,
ct
.
c_void_p
,
ct
.
c_size_t
,
ct
.
c_char_p
,
ct
.
c_uint
,
ct
.
c_int
,
ct
.
c_char_p
,
ct
.
c_uint
]
lib
.
bpf_attach_kprobe
.
restype
=
ct
.
c_void_p
_CB_TYPE
=
ct
.
CFUNCTYPE
(
None
,
ct
.
py_object
,
ct
.
c_int
,
ct
.
c_ulonglong
,
ct
.
POINTER
(
ct
.
c_ulonglong
))
_RAW_CB_TYPE
=
ct
.
CFUNCTYPE
(
None
,
ct
.
py_object
,
ct
.
c_void_p
,
ct
.
c_int
)
_LOST_CB_TYPE
=
ct
.
CFUNCTYPE
(
None
,
ct
.
py_object
,
ct
.
c_ulonglong
)
lib
.
bpf_attach_kprobe
.
argtypes
=
[
ct
.
c_int
,
ct
.
c_int
,
ct
.
c_char_p
,
ct
.
c_char_p
,
_CB_TYPE
,
ct
.
py_object
]
lib
.
bpf_attach_kprobe
.
restype
=
ct
.
c_int
lib
.
bpf_attach_kprobe
.
argtypes
=
[
ct
.
c_int
,
ct
.
c_int
,
ct
.
c_char_p
,
ct
.
c_char_p
]
lib
.
bpf_detach_kprobe
.
restype
=
ct
.
c_int
lib
.
bpf_detach_kprobe
.
argtypes
=
[
ct
.
c_char_p
]
lib
.
bpf_attach_uprobe
.
restype
=
ct
.
c_
void_p
lib
.
bpf_attach_uprobe
.
restype
=
ct
.
c_
int
lib
.
bpf_attach_uprobe
.
argtypes
=
[
ct
.
c_int
,
ct
.
c_int
,
ct
.
c_char_p
,
ct
.
c_char_p
,
ct
.
c_ulonglong
,
ct
.
c_int
,
_CB_TYPE
,
ct
.
py_object
]
ct
.
c_ulonglong
,
ct
.
c_int
]
lib
.
bpf_detach_uprobe
.
restype
=
ct
.
c_int
lib
.
bpf_detach_uprobe
.
argtypes
=
[
ct
.
c_char_p
]
lib
.
bpf_attach_tracepoint
.
restype
=
ct
.
c_void_p
lib
.
bpf_attach_tracepoint
.
argtypes
=
[
ct
.
c_int
,
ct
.
c_char_p
,
ct
.
c_char_p
,
_CB_TYPE
,
ct
.
py_object
]
lib
.
bpf_attach_tracepoint
.
restype
=
ct
.
c_int
lib
.
bpf_attach_tracepoint
.
argtypes
=
[
ct
.
c_int
,
ct
.
c_char_p
,
ct
.
c_char_p
]
lib
.
bpf_detach_tracepoint
.
restype
=
ct
.
c_int
lib
.
bpf_detach_tracepoint
.
argtypes
=
[
ct
.
c_char_p
,
ct
.
c_char_p
]
lib
.
bpf_open_perf_buffer
.
restype
=
ct
.
c_void_p
...
...
src/python/bcc/table.py
View file @
1fe85d07
...
...
@@ -494,10 +494,10 @@ class PerfEventArray(ArrayBase):
# Delete entry from the array
super
(
PerfEventArray
,
self
).
__delitem__
(
key
)
key_id
=
(
id
(
self
),
key
)
if
key_id
in
self
.
bpf
.
open_kprobe
s
:
if
key_id
in
self
.
bpf
.
perf_buffer
s
:
# The key is opened for perf ring buffer
lib
.
perf_reader_free
(
self
.
bpf
.
open_kprobe
s
[
key_id
])
self
.
bpf
.
_del_kprobe
(
key_id
)
lib
.
perf_reader_free
(
self
.
bpf
.
perf_buffer
s
[
key_id
])
del
self
.
bpf
.
perf_buffers
[
key_id
]
del
self
.
_cbs
[
key
]
else
:
# The key is opened for perf event read
...
...
@@ -544,7 +544,7 @@ class PerfEventArray(ArrayBase):
raise
Exception
(
"Could not open perf buffer"
)
fd
=
lib
.
perf_reader_fd
(
reader
)
self
[
self
.
Key
(
cpu
)]
=
self
.
Leaf
(
fd
)
self
.
bpf
.
_add_kprobe
((
id
(
self
),
cpu
),
reader
)
self
.
bpf
.
perf_buffers
[(
id
(
self
),
cpu
)]
=
reader
# keep a refcnt
self
.
_cbs
[
cpu
]
=
(
fn
,
lost_fn
)
# The actual fd is held by the perf reader, add to track opened keys
...
...
tests/python/CMakeLists.txt
View file @
1fe85d07
...
...
@@ -46,8 +46,6 @@ add_test(NAME py_test_clang WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
COMMAND
${
TEST_WRAPPER
}
py_clang sudo
${
CMAKE_CURRENT_SOURCE_DIR
}
/test_clang.py
)
add_test
(
NAME py_test_histogram WORKING_DIRECTORY
${
CMAKE_CURRENT_SOURCE_DIR
}
COMMAND
${
TEST_WRAPPER
}
py_histogram sudo
${
CMAKE_CURRENT_SOURCE_DIR
}
/test_histogram.py
)
add_test
(
NAME py_test_callchain WORKING_DIRECTORY
${
CMAKE_CURRENT_SOURCE_DIR
}
COMMAND
${
TEST_WRAPPER
}
py_callchain sudo
${
CMAKE_CURRENT_SOURCE_DIR
}
/test_callchain.py
)
add_test
(
NAME py_array WORKING_DIRECTORY
${
CMAKE_CURRENT_SOURCE_DIR
}
COMMAND
${
TEST_WRAPPER
}
py_array sudo
${
CMAKE_CURRENT_SOURCE_DIR
}
/test_array.py
)
add_test
(
NAME py_uprobes WORKING_DIRECTORY
${
CMAKE_CURRENT_SOURCE_DIR
}
...
...
tests/python/test_callchain.py
deleted
100755 → 0
View file @
abef8350
#!/usr/bin/env python
# Copyright (c) PLUMgrid, Inc.
# Licensed under the Apache License, Version 2.0 (the "License")
from
bcc
import
BPF
import
time
from
unittest
import
main
,
TestCase
class
TestCallchain
(
TestCase
):
def
test_callchain1
(
self
):
hist
=
{}
def
cb
(
pid
,
callchain
):
counter
=
hist
.
get
(
callchain
,
0
)
counter
+=
1
hist
[
callchain
]
=
counter
b
=
BPF
(
text
=
"""
#include <linux/ptrace.h>
int kprobe__finish_task_switch(struct pt_regs *ctx) {
return 1;
}
"""
,
cb
=
cb
)
start
=
time
.
time
()
while
time
.
time
()
<
start
+
1
:
b
.
kprobe_poll
()
for
k
,
v
in
hist
.
items
():
syms
=
[
b
.
ksym
(
addr
)
for
addr
in
k
]
print
(
"%-08d:"
%
v
,
syms
)
if
__name__
==
"__main__"
:
main
()
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