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
49df9944
Commit
49df9944
authored
Feb 08, 2017
by
Sasha Goldshtein
Browse files
Options
Browse Files
Download
Email Patches
Plain Diff
memleak: Migrate to new symbols resolution API
Remove usyms.py dependency and replace with new symbols API.
parent
febed330
Changes
3
Show whitespace changes
Inline
Side-by-side
Showing
3 changed files
with
54 additions
and
89 deletions
+54
-89
tools/memleak.py
tools/memleak.py
+7
-24
tools/memleak_example.txt
tools/memleak_example.txt
+37
-37
tools/old/memleak.py
tools/old/memleak.py
+10
-28
No files found.
tools/memleak.py
View file @
49df9944
...
...
@@ -11,31 +11,13 @@
# Licensed under the Apache License, Version 2.0 (the "License")
# Copyright (C) 2016 Sasha Goldshtein.
from
bcc
import
BPF
,
ProcessSymbols
from
bcc
import
BPF
from
time
import
sleep
from
datetime
import
datetime
import
argparse
import
subprocess
import
os
class
KStackDecoder
(
object
):
def
refresh
(
self
):
pass
def
__call__
(
self
,
addr
):
return
"%s [kernel] (%x)"
%
(
BPF
.
ksym
(
addr
),
addr
)
class
UStackDecoder
(
object
):
def
__init__
(
self
,
pid
):
self
.
pid
=
pid
self
.
proc_sym
=
ProcessSymbols
(
pid
)
def
refresh
(
self
):
self
.
proc_sym
.
refresh_code_ranges
()
def
__call__
(
self
,
addr
):
return
"%s (%x)"
%
(
self
.
proc_sym
.
decode_addr
(
addr
),
addr
)
class
Allocation
(
object
):
def
__init__
(
self
,
stack
,
size
):
self
.
stack
=
stack
...
...
@@ -240,8 +222,6 @@ else:
bpf_program
.
attach_kretprobe
(
event
=
"__kmalloc"
,
fn_name
=
"alloc_exit"
)
bpf_program
.
attach_kprobe
(
event
=
"kfree"
,
fn_name
=
"free_enter"
)
decoder
=
KStackDecoder
()
if
kernel_trace
else
UStackDecoder
(
pid
)
def
print_outstanding
():
print
(
"[%s] Top %d stacks with outstanding allocations:"
%
(
datetime
.
now
().
strftime
(
"%H:%M:%S"
),
top_stacks
))
...
...
@@ -256,8 +236,12 @@ def print_outstanding():
if
info
.
stack_id
in
alloc_info
:
alloc_info
[
info
.
stack_id
].
update
(
info
.
size
)
else
:
stack
=
list
(
stack_traces
.
walk
(
info
.
stack_id
,
decoder
))
alloc_info
[
info
.
stack_id
]
=
Allocation
(
stack
,
stack
=
list
(
stack_traces
.
walk
(
info
.
stack_id
))
combined
=
[]
for
addr
in
stack
:
combined
.
append
(
bpf_program
.
sym
(
addr
,
pid
,
show_module
=
True
,
show_address
=
True
))
alloc_info
[
info
.
stack_id
]
=
Allocation
(
combined
,
info
.
size
)
if
args
.
show_allocs
:
print
(
"
\
t
addr = %x size = %s"
%
...
...
@@ -277,7 +261,6 @@ while True:
sleep
(
interval
)
except
KeyboardInterrupt
:
exit
()
decoder
.
refresh
()
print_outstanding
()
count_so_far
+=
1
if
num_prints
is
not
None
and
count_so_far
>=
num_prints
:
...
...
tools/memleak_example.txt
View file @
49df9944
...
...
@@ -10,13 +10,13 @@ For example:
Attaching to malloc and free in pid 5193, Ctrl+C to quit.
[11:16:33] Top 2 stacks with outstanding allocations:
80 bytes in 5 allocations from stack
main+0x6d [
/home/vagrant/allocs] (400862)
__libc_start_main+0xf0 [
/usr/lib64/libc-2.21.so] (7fd460ac2790)
main+0x6d [
allocs]
__libc_start_main+0xf0 [
libc-2.21.so]
[11:16:34] Top 2 stacks with outstanding allocations:
160 bytes in 10 allocations from stack
main+0x6d [
/home/vagrant/allocs] (400862)
__libc_start_main+0xf0 [
/usr/lib64/libc-2.21.so] (7fd460ac2790)
main+0x6d [
allocs]
__libc_start_main+0xf0 [
libc-2.21.so]
Each entry printed is a set of allocations that originate from the same call
...
...
@@ -40,8 +40,8 @@ Attaching to malloc and free in pid 5193, Ctrl+C to quit.
addr = 948d30 size = 16
addr = 948cf0 size = 16
64 bytes in 4 allocations from stack
main+0x6d [
/home/vagrant/allocs] (400862)
__libc_start_main+0xf0 [
/usr/lib64/libc-2.21.so] (7fd460ac2790)
main+0x6d [
allocs]
__libc_start_main+0xf0 [
libc-2.21.so]
[11:16:34] Top 2 stacks with outstanding allocations:
addr = 948d50 size = 16
...
...
@@ -55,8 +55,8 @@ Attaching to malloc and free in pid 5193, Ctrl+C to quit.
addr = 948d70 size = 16
addr = 948df0 size = 16
160 bytes in 10 allocations from stack
main+0x6d [
/home/vagrant/allocs] (400862)
__libc_start_main+0xf0 [
/usr/lib64/libc-2.21.so] (7fd460ac2790)
main+0x6d [
allocs]
__libc_start_main+0xf0 [
libc-2.21.so]
When using the -p switch, memleak traces the allocations of a particular
...
...
@@ -67,35 +67,35 @@ For example:
Attaching to kmalloc and kfree, Ctrl+C to quit.
...
248 bytes in 4 allocations from stack
bpf_prog_load [kernel]
(ffffffff8118c471)
sys_bpf [kernel]
(ffffffff8118c8b5)
bpf_prog_load [kernel]
sys_bpf [kernel]
328 bytes in 1 allocations from stack
perf_mmap [kernel]
(ffffffff811990fd)
mmap_region [kernel]
(ffffffff811df5d4)
do_mmap [kernel]
(ffffffff811dfb83)
vm_mmap_pgoff [kernel]
(ffffffff811c494f)
sys_mmap_pgoff [kernel]
(ffffffff811ddf02)
sys_mmap [kernel]
(ffffffff8101b0ab)
perf_mmap [kernel]
mmap_region [kernel]
do_mmap [kernel]
vm_mmap_pgoff [kernel]
sys_mmap_pgoff [kernel]
sys_mmap [kernel]
464 bytes in 1 allocations from stack
traceprobe_command [kernel]
(ffffffff81187cf2)
traceprobe_probes_write [kernel]
(ffffffff81187d86)
probes_write [kernel]
(ffffffff81181580)
__vfs_write [kernel]
(ffffffff812237b7)
vfs_write [kernel]
(ffffffff81223ec6)
sys_write [kernel]
(ffffffff81224b85)
entry_SYSCALL_64_fastpath [kernel]
(ffffffff8178182e)
traceprobe_command [kernel]
traceprobe_probes_write [kernel]
probes_write [kernel]
__vfs_write [kernel]
vfs_write [kernel]
sys_write [kernel]
entry_SYSCALL_64_fastpath [kernel]
8192 bytes in 1 allocations from stack
alloc_and_copy_ftrace_hash.constprop.59 [kernel]
(ffffffff8115d17e)
ftrace_set_hash [kernel]
(ffffffff8115e767)
ftrace_set_filter_ip [kernel]
(ffffffff8115e9a8)
arm_kprobe [kernel]
(ffffffff81148600)
enable_kprobe [kernel]
(ffffffff811486f6)
kprobe_register [kernel]
(ffffffff81182399)
perf_trace_init [kernel]
(ffffffff8117c4e0)
perf_tp_event_init [kernel]
(ffffffff81192479)
alloc_and_copy_ftrace_hash.constprop.59 [kernel]
ftrace_set_hash [kernel]
ftrace_set_filter_ip [kernel]
arm_kprobe [kernel]
enable_kprobe [kernel]
kprobe_register [kernel]
perf_trace_init [kernel]
perf_tp_event_init [kernel]
Here you can see that arming the kprobe to which our eBPF program is attached
...
...
@@ -129,18 +129,18 @@ seconds, 3 times before quitting:
Attaching to malloc and free in pid 2614, Ctrl+C to quit.
[11:16:33] Top 2 stacks with outstanding allocations:
16 bytes in 1 allocations from stack
main+0x6d [
/home/vagrant/allocs] (400862)
__libc_start_main+0xf0 [
/usr/lib64/libc-2.21.so] (7fdc11ce8790)
main+0x6d [
allocs]
__libc_start_main+0xf0 [
libc-2.21.so]
[11:16:38] Top 2 stacks with outstanding allocations:
16 bytes in 1 allocations from stack
main+0x6d [
/home/vagrant/allocs] (400862)
__libc_start_main+0xf0 [
/usr/lib64/libc-2.21.so] (7fdc11ce8790)
main+0x6d [
allocs]
__libc_start_main+0xf0 [
libc-2.21.so]
[11:16:43] Top 2 stacks with outstanding allocations:
32 bytes in 2 allocations from stack
main+0x6d [
/home/vagrant/allocs] (400862)
__libc_start_main+0xf0 [
/usr/lib64/libc-2.21.so] (7fdc11ce8790)
main+0x6d [
allocs]
__libc_start_main+0xf0 [
libc-2.21.so]
Note that even though the application leaks 16 bytes of memory every second,
the report (printed every 5 seconds) doesn't "see" all the allocations because
...
...
tools/old/memleak.py
View file @
49df9944
...
...
@@ -11,35 +11,20 @@
# Licensed under the Apache License, Version 2.0 (the "License")
# Copyright (C) 2016 Sasha Goldshtein.
from
bcc
import
BPF
,
ProcessSymbols
from
bcc
import
BPF
,
SymbolCache
from
time
import
sleep
from
datetime
import
datetime
import
argparse
import
subprocess
import
os
class
StackDecoder
(
object
):
def
__init__
(
self
,
pid
):
self
.
pid
=
pid
if
pid
!=
-
1
:
self
.
proc_sym
=
ProcessSymbols
(
pid
)
def
refresh
(
self
):
if
self
.
pid
!=
-
1
:
self
.
proc_sym
.
refresh_code_ranges
()
def
decode_stack
(
self
,
info
,
is_kernel_trace
):
def
decode_stack
(
bpf
,
pid
,
info
):
stack
=
""
if
info
.
num_frames
<=
0
:
return
"???"
for
i
in
range
(
0
,
info
.
num_frames
):
addr
=
info
.
callstack
[
i
]
if
is_kernel_trace
:
stack
+=
" %s [kernel] (%x) ;"
%
\
(
BPF
.
ksym
(
addr
),
addr
)
else
:
stack
+=
" %s (%x) ;"
%
\
(
self
.
proc_sym
.
decode_addr
(
addr
),
addr
)
stack
+=
" %s ;"
%
bpf
.
sym
(
addr
,
pid
,
show_address
=
True
)
return
stack
def
run_command_get_output
(
command
):
...
...
@@ -255,8 +240,6 @@ else:
bpf_program
.
attach_kretprobe
(
event
=
"__kmalloc"
,
fn_name
=
"alloc_exit"
)
bpf_program
.
attach_kprobe
(
event
=
"kfree"
,
fn_name
=
"free_enter"
)
decoder
=
StackDecoder
(
pid
)
def
print_outstanding
():
stacks
=
{}
print
(
"[%s] Top %d stacks with outstanding allocations:"
%
...
...
@@ -265,7 +248,7 @@ def print_outstanding():
for
address
,
info
in
sorted
(
allocs
.
items
(),
key
=
lambda
a
:
a
[
1
].
size
):
if
BPF
.
monotonic_time
()
-
min_age_ns
<
info
.
timestamp_ns
:
continue
stack
=
decode
r
.
decode_stack
(
info
,
kernel_trace
)
stack
=
decode
_stack
(
bpf_program
,
pid
,
info
)
if
stack
in
stacks
:
stacks
[
stack
]
=
(
stacks
[
stack
][
0
]
+
1
,
stacks
[
stack
][
1
]
+
info
.
size
)
...
...
@@ -288,7 +271,6 @@ while True:
sleep
(
interval
)
except
KeyboardInterrupt
:
exit
()
decoder
.
refresh
()
print_outstanding
()
count_so_far
+=
1
if
num_prints
is
not
None
and
count_so_far
>=
num_prints
:
...
...
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