/usr/sbin
NameSizeModeActions
aa-load396800755editdlrm
aa-remove-unknown32250755editdlrm
aa-status400000755editdlrm
aa-teardown1370755editdlrm
accessdb149040755editdlrm
acpid539200755editdlrm
add-shell10530755editdlrm
addgnupghome30750755editdlrm
addgroup551910755editdlrm
adduser551910755editdlrm
agetty609920755editdlrm
apparmor_parser16298480755editdlrm
apparmor_status400000755editdlrm
applygnupgdefaults22170755editdlrm
argdist-bpfcc368620755editdlrm
arpd269600755editdlrm
arptables2244240755editdlrm
arptables-nft2244240755editdlrm
arptables-nft-restore2244240755editdlrm
arptables-nft-save2244240755editdlrm
arptables-restore2244240755editdlrm
arptables-save2244240755editdlrm
badblocks351440755editdlrm
bashreadline-bpfcc23800755editdlrm
bashreadline.bt6980755editdlrm
bcache-super-show146480755editdlrm
bindsnoop-bpfcc163460755editdlrm
biolatency-bpfcc113650755editdlrm
biolatency-kp.bt6640755editdlrm
biolatency.bt6810755editdlrm
biolatpcts-bpfcc102480755editdlrm
biopattern-bpfcc39570755editdlrm
biosdecode278560755editdlrm
biosnoop-bpfcc108330755editdlrm
biosnoop.bt11480755editdlrm
biostacks.bt9150755editdlrm
biotop-bpfcc95670755editdlrm
bitesize-bpfcc11660755editdlrm
bitesize.bt5670755editdlrm
blkdeactivate163510755editdlrm
blkdiscard229120755editdlrm
blkid557200755editdlrm
blkzone352000755editdlrm
blockdev352000755editdlrm
bpflist-bpfcc26010755editdlrm
bpftool16220755editdlrm
bridge1110960755editdlrm
btrfsdist-bpfcc66270755editdlrm
btrfsslower-bpfcc99850755editdlrm
cachestat-bpfcc65310755editdlrm
cachetop-bpfcc93670755editdlrm
cache_check14305680755editdlrm
cache_dump14305680755editdlrm
cache_metadata_size14305680755editdlrm
cache_repair14305680755editdlrm
cache_restore14305680755editdlrm
cache_writeback14305680755editdlrm
capable-bpfcc84770755editdlrm
capable.bt19260755editdlrm
capsh584560755editdlrm
cfdisk970080755editdlrm
cgdisk1704800755editdlrm
chcpu311040755editdlrm
chgpasswd597200755editdlrm
chmem352000755editdlrm
chpasswd557360755editdlrm
chronyd3062320755editdlrm
chroot394320755editdlrm
cobjnew-bpfcc530755editdlrm
compactsnoop-bpfcc113690755editdlrm
cpgr496080755editdlrm
cppw496080755editdlrm
cpudist-bpfcc70130755editdlrm
cpuunclaimed-bpfcc149380755editdlrm
cpuwalk.bt4970755editdlrm
criticalstat-bpfcc86070755editdlrm
cron600800755editdlrm
cryptdisks_start15440755editdlrm
cryptdisks_stop8440755editdlrm
cryptsetup2313200755editdlrm
ctrlaltdel147200755editdlrm
dbslower-bpfcc73910755editdlrm
dbstat-bpfcc37900755editdlrm
dcb824480755editdlrm
dcsnoop-bpfcc41260755editdlrm
dcsnoop.bt12610755editdlrm
dcstat-bpfcc38590755editdlrm
deadlock-bpfcc209430755editdlrm
debugfs2312880755editdlrm
delgroup189770755editdlrm
deluser189770755editdlrm
depmod1743280755editdlrm
devlink1544800755editdlrm
dhcpcd4048880755editdlrm
dirtop-bpfcc85680755editdlrm
dmeventd515920755editdlrm
dmidecode1384960755editdlrm
dmsetup1751600755editdlrm
dmstats1751600755editdlrm
dosfsck802640755editdlrm
dosfslabel393040755editdlrm
dpkg-preconfigure43560755editdlrm
dpkg-reconfigure45360755editdlrm
drsnoop-bpfcc68890755editdlrm
dumpe2fs351360755editdlrm
e2freefrag187440755editdlrm
e2fsck3730800755editdlrm
e2image433280755editdlrm
e2label1132160755editdlrm
e2mmpstatus351360755editdlrm
e2scrub72940755editdlrm
e2scrub_all53940755editdlrm
e2undo228400755editdlrm
e4crypt311040755editdlrm
e4defrag351280755editdlrm
ebtables2244240755editdlrm
ebtables-nft2244240755editdlrm
ebtables-nft-restore2244240755editdlrm
ebtables-nft-save2244240755editdlrm
ebtables-restore2244240755editdlrm
ebtables-save2244240755editdlrm
ebtables-translate2244240755editdlrm
era_check14305680755editdlrm
era_dump14305680755editdlrm
era_invalidate14305680755editdlrm
era_restore14305680755editdlrm
ethtool6673200755editdlrm
execsnoop-bpfcc100590755editdlrm
execsnoop.bt9280755editdlrm
exitsnoop-bpfcc96460755editdlrm
ext4dist-bpfcc66830755editdlrm
ext4slower-bpfcc99480755editdlrm
faillock228480755editdlrm
fatlabel393040755editdlrm
fdisk1171680755editdlrm
filefrag187600755editdlrm
filegone-bpfcc57760755editdlrm
filelife-bpfcc65280755editdlrm
fileslower-bpfcc73720755editdlrm
filetop-bpfcc64990755editdlrm
findfs147200755editdlrm
fixparts598800755editdlrm
fsadm245800755editdlrm
fsck434400755editdlrm
fsck.btrfs11850755editdlrm
fsck.cramfs311680755editdlrm
fsck.ext23730800755editdlrm
fsck.ext33730800755editdlrm
fsck.ext43730800755editdlrm
fsck.fat802640755editdlrm
fsck.minix557120755editdlrm
fsck.msdos802640755editdlrm
fsck.vfat802640755editdlrm
fsck.xfs25660755editdlrm
fsfreeze147200755editdlrm
fstab-decode146480755editdlrm
fstrim433920755editdlrm
funccount-bpfcc129810755editdlrm
funcinterval-bpfcc55900755editdlrm
funclatency-bpfcc115490755editdlrm
funcslower-bpfcc106300755editdlrm
gdisk2032480755editdlrm
genl1234720755editdlrm
getcap146480755editdlrm
gethostlatency-bpfcc39140755editdlrm
gethostlatency.bt12220755editdlrm
getpcaps146480755editdlrm
getty609920755editdlrm
groupadd728400755editdlrm
groupdel644240755editdlrm
groupmems597440755editdlrm
groupmod727440755editdlrm
grpck597200755editdlrm
grpconv513680755editdlrm
grpunconv513680755editdlrm
grub-bios-setup9815520755editdlrm
grub-install12258240755editdlrm
grub-macbless9691280755editdlrm
grub-mkconfig88400755editdlrm
grub-mkdevicemap723840755editdlrm
grub-probe9775760755editdlrm
grub-reboot48410755editdlrm
grub-set-default35560755editdlrm
halt15013040755editdlrm
hardirqs-bpfcc70190755editdlrm
hdparm1427760755editdlrm
iconvconfig352960755editdlrm
init1008160755editdlrm
inject-bpfcc164450755editdlrm
insmod1743280755editdlrm
install-sgmlcatalog45510755editdlrm
installkernel26590755editdlrm
integritysetup686720755editdlrm
invoke-rc.d165170755editdlrm
ip7729200755editdlrm
ip6tables2244240755editdlrm
ip6tables-apply70520755editdlrm
ip6tables-legacy951760755editdlrm
ip6tables-legacy-restore951760755editdlrm
ip6tables-legacy-save951760755editdlrm
ip6tables-nft2244240755editdlrm
ip6tables-nft-restore2244240755editdlrm
ip6tables-nft-save2244240755editdlrm
ip6tables-restore2244240755editdlrm
ip6tables-restore-translate2244240755editdlrm
ip6tables-save2244240755editdlrm
ip6tables-translate2244240755editdlrm
iptables2244240755editdlrm
iptables-apply70520755editdlrm
iptables-legacy951760755editdlrm
iptables-legacy-restore951760755editdlrm
iptables-legacy-save951760755editdlrm
iptables-nft2244240755editdlrm
iptables-nft-restore2244240755editdlrm
iptables-nft-save2244240755editdlrm
iptables-restore2244240755editdlrm
iptables-restore-translate2244240755editdlrm
iptables-save2244240755editdlrm
iptables-translate2244240755editdlrm
irqbalance602720755editdlrm
irqbalance-ui393040755editdlrm
iscsi-iname187440755editdlrm
iscsiadm3793200755editdlrm
iscsid2934320755editdlrm
iscsistart2810800755editdlrm
iscsi_discovery52930755editdlrm
isosize147200755editdlrm
iucode-tool556400755editdlrm
iucode_tool556400755editdlrm
javacalls-bpfcc550755editdlrm
javaflow-bpfcc540755editdlrm
javagc-bpfcc520755editdlrm
javaobjnew-bpfcc560755editdlrm
javastat-bpfcc540755editdlrm
javathreads-bpfcc570755editdlrm
kbdrate187520755editdlrm
killall5268560755editdlrm
killsnoop-bpfcc45540755editdlrm
killsnoop.bt8730755editdlrm
klockstat-bpfcc133560755editdlrm
kpartx431760755editdlrm
kvmexit-bpfcc114610755editdlrm
ldattach270080755editdlrm
ldconfig3870755editdlrm
ldconfig.real10512800755editdlrm
llcstat-bpfcc45840755editdlrm
loads.bt11270755editdlrm
locale-gen43160755editdlrm
logrotate965040755editdlrm
logsave144960755editdlrm
losetup763040755editdlrm
lsmod1743280755editdlrm
luksformat34010755editdlrm
lvchange31567120755editdlrm
lvconvert31567120755editdlrm
lvcreate31567120755editdlrm
lvdisplay31567120755editdlrm
lvextend31567120755editdlrm
lvm31567120755editdlrm
lvmconfig31567120755editdlrm
lvmdiskscan31567120755editdlrm
lvmdump103640755editdlrm
lvmpolld2416320755editdlrm
lvmsadc31567120755editdlrm
lvmsar31567120755editdlrm
lvreduce31567120755editdlrm
lvremove31567120755editdlrm
lvrename31567120755editdlrm
lvresize31567120755editdlrm
lvs31567120755editdlrm
lvscan31567120755editdlrm
lxc5890755editdlrm
lxd5890755editdlrm
make-bcache229120755editdlrm
mdadm6371440755editdlrm
mdflush-bpfcc22950755editdlrm
mdflush.bt7750755editdlrm
mdmon2650160755editdlrm
memleak-bpfcc212980755editdlrm
mkdosfs520480755editdlrm
mke2fs1337520755editdlrm
mkfs147200755editdlrm
mkfs.bfs229120755editdlrm
mkfs.btrfs5737520755editdlrm
mkfs.cramfs351440755editdlrm
mkfs.ext21337520755editdlrm
mkfs.ext31337520755editdlrm
mkfs.ext41337520755editdlrm
mkfs.fat520480755editdlrm
mkfs.minix434080755editdlrm
mkfs.msdos520480755editdlrm
mkfs.ntfs679760755editdlrm
mkfs.vfat520480755editdlrm
mkfs.xfs4495280755editdlrm
mkhomedir_helper228720755editdlrm
mkinitramfs157620755editdlrm
mklost+found146480755editdlrm
mkntfs679760755editdlrm
mkswap515920755editdlrm
ModemManager21655760755editdlrm
modinfo1743280755editdlrm
modprobe1743280755editdlrm
mount.fuse187360755editdlrm
mount.fuse3187360755editdlrm
mount.lowntfs-3g1218320755editdlrm
mount.ntfs1628240755editdlrm
mount.ntfs-3g1628240755editdlrm
mountsnoop-bpfcc149680755editdlrm
mpathpersist319600755editdlrm
multipath351280755editdlrm
multipathc187440755editdlrm
multipathd1458800755editdlrm
mysqld554679440755editdlrm
mysqld_qslower-bpfcc31250755editdlrm
naptime.bt10350755editdlrm
needrestart410920755editdlrm
netplan8020755editdlrm
netqtop-bpfcc57250755editdlrm
newusers890480755editdlrm
nfnl_osf187360755editdlrm
nfsdist-bpfcc50680755editdlrm
nfsslower-bpfcc139390755editdlrm
nft268560755editdlrm
nginx13141680755editdlrm
nodegc-bpfcc520755editdlrm
nodestat-bpfcc540755editdlrm
nologin146400755editdlrm
ntfsclone515920755editdlrm
ntfscp311040755editdlrm
ntfslabel229120755editdlrm
ntfsresize638880755editdlrm
ntfsundelete515920755editdlrm
offcputime-bpfcc137790755editdlrm
offwaketime-bpfcc156760755editdlrm
on_ac_power37880755editdlrm
oomkill-bpfcc20840755editdlrm
oomkill.bt11980755editdlrm
opensnoop-bpfcc145810755editdlrm
opensnoop.bt9530755editdlrm
overlayroot-chroot25100755editdlrm
ownership147920755editdlrm
pam-auth-update214650755editdlrm
pam_extrausers_chkpwd269442755editdlrm
pam_extrausers_update351360755editdlrm
pam_getenv28900755editdlrm
pam_namespace_helper4670755editdlrm
pam_timestamp_check146560755editdlrm
parted966640755editdlrm
partprobe147200755editdlrm
pdata_tools14305680755editdlrm
perlcalls-bpfcc550755editdlrm
perlflow-bpfcc540755editdlrm
perlstat-bpfcc540755editdlrm
php-fpm7.448033760755editdlrm
phpcalls-bpfcc540755editdlrm
phpdismod72780755editdlrm
phpenmod72780755editdlrm
phpflow-bpfcc530755editdlrm
phpquery63890755editdlrm
phpstat-bpfcc530755editdlrm
pidpersec-bpfcc11110755editdlrm
pidpersec.bt6280755editdlrm
pivot_root147200755editdlrm
plymouthd1500880755editdlrm
poweroff15013040755editdlrm
ppchcalls-bpfcc142240755editdlrm
profile-bpfcc147560755editdlrm
pvchange31567120755editdlrm
pvck31567120755editdlrm
pvcreate31567120755editdlrm
pvdisplay31567120755editdlrm
pvmove31567120755editdlrm
pvremove31567120755editdlrm
pvresize31567120755editdlrm
pvs31567120755editdlrm
pvscan31567120755editdlrm
pwck555920755editdlrm
pwconv472720755editdlrm
pwhistory_helper228480755editdlrm
pwunconv472720755editdlrm
pythoncalls-bpfcc570755editdlrm
pythonflow-bpfcc560755editdlrm
pythongc-bpfcc540755editdlrm
pythonstat-bpfcc560755editdlrm
rdmaucma-bpfcc50730755editdlrm
readahead-bpfcc66940755editdlrm
readprofile229440755editdlrm
reboot15013040755editdlrm
remove-shell11110755editdlrm
reset-trace-bpfcc34980755editdlrm
resize2fs719920755editdlrm
resolvconf1624800755editdlrm
rmmod1743280755editdlrm
rmt560240755editdlrm
rmt-tar560240755editdlrm
rsyslogd7901920755editdlrm
rtacct289920755editdlrm
rtcwake352000755editdlrm
rtmon1193120755editdlrm
rubycalls-bpfcc550755editdlrm
rubyflow-bpfcc540755editdlrm
rubygc-bpfcc520755editdlrm
rubyobjnew-bpfcc560755editdlrm
rubystat-bpfcc540755editdlrm
runlevel15013040755editdlrm
runqlat-bpfcc95260755editdlrm
runqlat.bt7880755editdlrm
runqlen-bpfcc82480755editdlrm
runqlen.bt10370755editdlrm
runqslower-bpfcc92250755editdlrm
runuser556800755editdlrm
service91040755editdlrm
setcap146480755editdlrm
setuids.bt17990755editdlrm
setvesablank147120755editdlrm
setvtrgb147760755editdlrm
sfdisk1089280755editdlrm
sgdisk1827680755editdlrm
shadowconfig22730755editdlrm
shmsnoop-bpfcc79850755editdlrm
shutdown15013040755editdlrm
slabratetop-bpfcc65370755editdlrm
sofdsnoop-bpfcc82550755editdlrm
softirqs-bpfcc57230755editdlrm
solisten-bpfcc61030755editdlrm
sshd9214160755editdlrm
ssllatency.bt21330755editdlrm
sslsniff-bpfcc140130755editdlrm
sslsnoop.bt20410755editdlrm
stackcount-bpfcc166550755editdlrm
start-stop-daemon486320755editdlrm
statsnoop-bpfcc50410755editdlrm
statsnoop.bt12940755editdlrm
sudo_logsrvd2544640755editdlrm
sudo_sendlog1348320755editdlrm
sulogin433920755editdlrm
swapin.bt6000755editdlrm
swaplabel188160755editdlrm
swapoff229120755editdlrm
swapon433920755editdlrm
switch_root229120755editdlrm
syncsnoop-bpfcc13000755editdlrm
syncsnoop.bt8390755editdlrm
syscount-bpfcc87710755editdlrm
syscount.bt8720755editdlrm
sysctl311120755editdlrm
tarcat9360755editdlrm
tc6452000755editdlrm
tclcalls-bpfcc540755editdlrm
tclflow-bpfcc530755editdlrm
tclobjnew-bpfcc550755editdlrm
tclstat-bpfcc530755editdlrm
tcpaccept-bpfcc92200755editdlrm
tcpaccept.bt17560755editdlrm
tcpcong-bpfcc205910755editdlrm
tcpconnect-bpfcc189020755editdlrm
tcpconnect.bt16150755editdlrm
tcpconnlat-bpfcc92850755editdlrm
tcpdrop-bpfcc76160755editdlrm
tcpdrop.bt24690755editdlrm
tcplife-bpfcc169490755editdlrm
tcplife.bt27850755editdlrm
tcpretrans-bpfcc140980755editdlrm
tcpretrans.bt21200755editdlrm
tcprtt-bpfcc89130755editdlrm
tcpstates-bpfcc140640755editdlrm
tcpsubnet-bpfcc78140755editdlrm
tcpsynbl-bpfcc21750755editdlrm
tcpsynbl.bt9620755editdlrm
tcptop-bpfcc129430755editdlrm
tcptracer-bpfcc181300755editdlrm
telinit15013040755editdlrm
thin_check14305680755editdlrm
thin_delta14305680755editdlrm
thin_dump14305680755editdlrm
thin_ls14305680755editdlrm
thin_metadata_size14305680755editdlrm
thin_repair14305680755editdlrm
thin_restore14305680755editdlrm
thin_rmap14305680755editdlrm
thin_trim14305680755editdlrm
threadsnoop-bpfcc18580755editdlrm
threadsnoop.bt7120755editdlrm
tipc926880755editdlrm
tplist-bpfcc41570755editdlrm
trace-bpfcc438920755editdlrm
ttysnoop-bpfcc76940755editdlrm
tune2fs1132160755editdlrm
ucalls119700755editdlrm
uflow81150755editdlrm
ufw49590755editdlrm
ugc78230755editdlrm
umount.udisks2146400755editdlrm
undump.bt7890755editdlrm
unix_chkpwd310402755editdlrm
unix_update351360755editdlrm
uobjnew61810755editdlrm
update-ca-certificates54460755editdlrm
update-catalog93930755editdlrm
update-grub640755editdlrm
update-grub-gfxpayload3010755editdlrm
update-grub2640755editdlrm
update-ieee-data34920755editdlrm
update-info-dir17000755editdlrm
update-initramfs69080755editdlrm
update-locale30570755editdlrm
update-passwd353920755editdlrm
update-pciids17780755editdlrm
update-rc.d181470755editdlrm
update-secureboot-policy76050755editdlrm
update-shells39840755editdlrm
update-xmlcatalog172840755editdlrm
upgrade-from-grub-legacy15960755editdlrm
usb_modeswitch610960755editdlrm
usb_modeswitch_dispatcher274180755editdlrm
useradd1432320755editdlrm
userdel931920755editdlrm
usermod1307120755editdlrm
ustat124120755editdlrm
uthreads41000755editdlrm
uuidd316240755editdlrm
validlocale17730755editdlrm
vcstime146400755editdlrm
vdpa353920755editdlrm
veritysetup449920755editdlrm
vfscount-bpfcc13900755editdlrm
vfscount.bt5150755editdlrm
vfsstat-bpfcc41590755editdlrm
vfsstat.bt7210755editdlrm
vgcfgbackup31567120755editdlrm
vgcfgrestore31567120755editdlrm
vgchange31567120755editdlrm
vgck31567120755editdlrm
vgconvert31567120755editdlrm
vgcreate31567120755editdlrm
vgdisplay31567120755editdlrm
vgexport31567120755editdlrm
vgextend31567120755editdlrm
vgimport31567120755editdlrm
vgimportclone31567120755editdlrm
vgmerge31567120755editdlrm
vgmknodes31567120755editdlrm
vgreduce31567120755editdlrm
vgremove31567120755editdlrm
vgrename31567120755editdlrm
vgs31567120755editdlrm
vgscan31567120755editdlrm
vgsplit31567120755editdlrm
vigr621440755editdlrm
vipw621440755editdlrm
virtiostat-bpfcc89000755editdlrm
visudo2587760755editdlrm
vpddecode149280755editdlrm
wakeuptime-bpfcc82910755editdlrm
wipefs392960755editdlrm
writeback.bt16990755editdlrm
xfsdist-bpfcc47230755editdlrm
xfsdist.bt9720755editdlrm
xfsslower-bpfcc79640755editdlrm
xfs_admin21740755editdlrm
xfs_bmap6950755editdlrm
xfs_copy926080755editdlrm
xfs_db7050880755editdlrm
xfs_estimate145040755editdlrm
xfs_freeze8000755editdlrm
xfs_fsr431920755editdlrm
xfs_growfs391520755editdlrm
xfs_info12940755editdlrm
xfs_io2085360755editdlrm
xfs_logprint801440755editdlrm
xfs_mdrestore350480755editdlrm
xfs_metadump8160755editdlrm
xfs_mkfile10400755editdlrm
xfs_ncheck6850755editdlrm
xfs_quota923280755editdlrm
xfs_repair6587600755editdlrm
xfs_rtcp185840755editdlrm
xfs_scrub1088160755editdlrm
xfs_scrub_all78410755editdlrm
xfs_spaceman433200755editdlrm
xtables-legacy-multi951760755editdlrm
xtables-monitor2244240755editdlrm
xtables-nft-multi2244240755editdlrm
zerofree144880755editdlrm
zfsdist-bpfcc54270755editdlrm
zfsslower-bpfcc86570755editdlrm
zic679840755editdlrm
zramctl558240755editdlrm
Edit: /usr/sbin/memleak-bpfcc (21298B)
#! /usr/bin/python3 # # memleak Trace and display outstanding allocations to detect # memory leaks in user-mode processes and the kernel. # # USAGE: memleak [-h] [-p PID] [-t] [-a] [-o OLDER] [-c COMMAND] # [--combined-only] [--wa-missing-free] [-s SAMPLE_RATE] # [-T TOP] [-z MIN_SIZE] [-Z MAX_SIZE] [-O OBJ] # [interval] [count] # # Licensed under the Apache License, Version 2.0 (the "License") # Copyright (C) 2016 Sasha Goldshtein. from bcc import BPF from time import sleep from datetime import datetime import resource import argparse import subprocess import os import sys class Allocation(object): def __init__(self, stack, size): self.stack = stack self.count = 1 self.size = size def update(self, size): self.count += 1 self.size += size def run_command_get_output(command): p = subprocess.Popen(command.split(), stdout=subprocess.PIPE, stderr=subprocess.STDOUT) return iter(p.stdout.readline, b'') def run_command_get_pid(command): p = subprocess.Popen(command.split()) return p.pid sort_keys = ["size", "count"] alloc_sort_map = {sort_keys[0]: lambda a: a.size, sort_keys[1]: lambda a: a.count}; combined_sort_map = {sort_keys[0]: lambda a: -a[1].total_size, sort_keys[1]: lambda a: -a[1].number_of_allocs}; examples = """ EXAMPLES: ./memleak -p $(pidof allocs) Trace allocations and display a summary of "leaked" (outstanding) allocations every 5 seconds ./memleak -p $(pidof allocs) -t Trace allocations and display each individual allocator function call ./memleak -ap $(pidof allocs) 10 Trace allocations and display allocated addresses, sizes, and stacks every 10 seconds for outstanding allocations ./memleak -c "./allocs" Run the specified command and trace its allocations ./memleak Trace allocations in kernel mode and display a summary of outstanding allocations every 5 seconds ./memleak -o 60000 Trace allocations in kernel mode and display a summary of outstanding allocations that are at least one minute (60 seconds) old ./memleak -s 5 Trace roughly every 5th allocation, to reduce overhead ./memleak --sort count Trace allocations in kernel mode and display a summary of outstanding allocations that are sorted in count order """ description = """ Trace outstanding memory allocations that weren't freed. Supports both user-mode allocations made with libc functions and kernel-mode allocations made with kmalloc/kmem_cache_alloc/get_free_pages and corresponding memory release functions. """ parser = argparse.ArgumentParser(description=description, formatter_class=argparse.RawDescriptionHelpFormatter, epilog=examples) parser.add_argument("-p", "--pid", type=int, default=-1, help="the PID to trace; if not specified, trace kernel allocs") parser.add_argument("-t", "--trace", action="store_true", help="print trace messages for each alloc/free call") parser.add_argument("interval", nargs="?", default=5, type=int, help="interval in seconds to print outstanding allocations") parser.add_argument("count", nargs="?", type=int, help="number of times to print the report before exiting") parser.add_argument("-a", "--show-allocs", default=False, action="store_true", help="show allocation addresses and sizes as well as call stacks") parser.add_argument("-o", "--older", default=500, type=int, help="prune allocations younger than this age in milliseconds") parser.add_argument("-c", "--command", help="execute and trace the specified command") parser.add_argument("--combined-only", default=False, action="store_true", help="show combined allocation statistics only") parser.add_argument("--wa-missing-free", default=False, action="store_true", help="Workaround to alleviate misjudgments when free is missing") parser.add_argument("-s", "--sample-rate", default=1, type=int, help="sample every N-th allocation to decrease the overhead") parser.add_argument("-T", "--top", type=int, default=10, help="display only this many top allocating stacks (by size)") parser.add_argument("-z", "--min-size", type=int, help="capture only allocations larger than this size") parser.add_argument("-Z", "--max-size", type=int, help="capture only allocations smaller than this size") parser.add_argument("-O", "--obj", type=str, default="c", help="attach to allocator functions in the specified object") parser.add_argument("--ebpf", action="store_true", help=argparse.SUPPRESS) parser.add_argument("--percpu", default=False, action="store_true", help="trace percpu allocations") parser.add_argument("--sort", type=str, default="size", help="report sorted in given key; available key list: size, count") parser.add_argument("--symbols-prefix", type=str, help="memory alloctor symbols prefix") args = parser.parse_args() pid = args.pid command = args.command kernel_trace = (pid == -1 and command is None) trace_all = args.trace interval = args.interval min_age_ns = 1e6 * args.older sample_every_n = args.sample_rate num_prints = args.count top_stacks = args.top min_size = args.min_size max_size = args.max_size obj = args.obj sort_key = args.sort if sort_key not in sort_keys: print("Given sort_key:", sort_key) print("Supporting sort key list:", sort_keys) exit(1) if min_size is not None and max_size is not None and min_size > max_size: print("min_size (-z) can't be greater than max_size (-Z)") exit(1) if command is not None: print("Executing '%s' and tracing the resulting process." % command) pid = run_command_get_pid(command) bpf_source = """ #include struct alloc_info_t { u64 size; u64 timestamp_ns; int stack_id; }; struct combined_alloc_info_t { u64 total_size; u64 number_of_allocs; }; BPF_HASH(sizes, u64); BPF_HASH(allocs, u64, struct alloc_info_t, 1000000); BPF_HASH(memptrs, u64, u64); BPF_STACK_TRACE(stack_traces, 10240); BPF_HASH(combined_allocs, u64, struct combined_alloc_info_t, 10240); static inline void update_statistics_add(u64 stack_id, u64 sz) { struct combined_alloc_info_t *existing_cinfo; struct combined_alloc_info_t cinfo = {0}; existing_cinfo = combined_allocs.lookup(&stack_id); if (existing_cinfo != 0) cinfo = *existing_cinfo; cinfo.total_size += sz; cinfo.number_of_allocs += 1; combined_allocs.update(&stack_id, &cinfo); } static inline void update_statistics_del(u64 stack_id, u64 sz) { struct combined_alloc_info_t *existing_cinfo; struct combined_alloc_info_t cinfo = {0}; existing_cinfo = combined_allocs.lookup(&stack_id); if (existing_cinfo != 0) cinfo = *existing_cinfo; if (sz >= cinfo.total_size) cinfo.total_size = 0; else cinfo.total_size -= sz; if (cinfo.number_of_allocs > 0) cinfo.number_of_allocs -= 1; combined_allocs.update(&stack_id, &cinfo); } static inline int gen_alloc_enter(struct pt_regs *ctx, size_t size) { SIZE_FILTER if (SAMPLE_EVERY_N > 1) { u64 ts = bpf_ktime_get_ns(); if (ts % SAMPLE_EVERY_N != 0) return 0; } u64 pid = bpf_get_current_pid_tgid(); u64 size64 = size; sizes.update(&pid, &size64); if (SHOULD_PRINT) bpf_trace_printk("alloc entered, size = %u\\n", size); return 0; } static inline int gen_alloc_exit2(struct pt_regs *ctx, u64 address) { u64 pid = bpf_get_current_pid_tgid(); u64* size64 = sizes.lookup(&pid); struct alloc_info_t info = {0}; if (size64 == 0) return 0; // missed alloc entry info.size = *size64; sizes.delete(&pid); if (address != 0) { info.timestamp_ns = bpf_ktime_get_ns(); info.stack_id = stack_traces.get_stackid(ctx, STACK_FLAGS); allocs.update(&address, &info); update_statistics_add(info.stack_id, info.size); } if (SHOULD_PRINT) { bpf_trace_printk("alloc exited, size = %lu, result = %lx\\n", info.size, address); } return 0; } static inline int gen_alloc_exit(struct pt_regs *ctx) { return gen_alloc_exit2(ctx, PT_REGS_RC(ctx)); } static inline int gen_free_enter(struct pt_regs *ctx, void *address) { u64 addr = (u64)address; struct alloc_info_t *info = allocs.lookup(&addr); if (info == 0) return 0; allocs.delete(&addr); update_statistics_del(info->stack_id, info->size); if (SHOULD_PRINT) { bpf_trace_printk("free entered, address = %lx, size = %lu\\n", address, info->size); } return 0; } int malloc_enter(struct pt_regs *ctx, size_t size) { return gen_alloc_enter(ctx, size); } int malloc_exit(struct pt_regs *ctx) { return gen_alloc_exit(ctx); } int free_enter(struct pt_regs *ctx, void *address) { return gen_free_enter(ctx, address); } int calloc_enter(struct pt_regs *ctx, size_t nmemb, size_t size) { return gen_alloc_enter(ctx, nmemb * size); } int calloc_exit(struct pt_regs *ctx) { return gen_alloc_exit(ctx); } int realloc_enter(struct pt_regs *ctx, void *ptr, size_t size) { gen_free_enter(ctx, ptr); return gen_alloc_enter(ctx, size); } int realloc_exit(struct pt_regs *ctx) { return gen_alloc_exit(ctx); } int mmap_enter(struct pt_regs *ctx) { size_t size = (size_t)PT_REGS_PARM2(ctx); return gen_alloc_enter(ctx, size); } int mmap_exit(struct pt_regs *ctx) { return gen_alloc_exit(ctx); } int munmap_enter(struct pt_regs *ctx, void *address) { return gen_free_enter(ctx, address); } int posix_memalign_enter(struct pt_regs *ctx, void **memptr, size_t alignment, size_t size) { u64 memptr64 = (u64)(size_t)memptr; u64 pid = bpf_get_current_pid_tgid(); memptrs.update(&pid, &memptr64); return gen_alloc_enter(ctx, size); } int posix_memalign_exit(struct pt_regs *ctx) { u64 pid = bpf_get_current_pid_tgid(); u64 *memptr64 = memptrs.lookup(&pid); void *addr; if (memptr64 == 0) return 0; memptrs.delete(&pid); if (bpf_probe_read_user(&addr, sizeof(void*), (void*)(size_t)*memptr64)) return 0; u64 addr64 = (u64)(size_t)addr; return gen_alloc_exit2(ctx, addr64); } int aligned_alloc_enter(struct pt_regs *ctx, size_t alignment, size_t size) { return gen_alloc_enter(ctx, size); } int aligned_alloc_exit(struct pt_regs *ctx) { return gen_alloc_exit(ctx); } int valloc_enter(struct pt_regs *ctx, size_t size) { return gen_alloc_enter(ctx, size); } int valloc_exit(struct pt_regs *ctx) { return gen_alloc_exit(ctx); } int memalign_enter(struct pt_regs *ctx, size_t alignment, size_t size) { return gen_alloc_enter(ctx, size); } int memalign_exit(struct pt_regs *ctx) { return gen_alloc_exit(ctx); } int pvalloc_enter(struct pt_regs *ctx, size_t size) { return gen_alloc_enter(ctx, size); } int pvalloc_exit(struct pt_regs *ctx) { return gen_alloc_exit(ctx); } """ bpf_source_kernel_node = """ TRACEPOINT_PROBE(kmem, kmalloc_node) { if (WORKAROUND_MISSING_FREE) gen_free_enter((struct pt_regs *)args, (void *)args->ptr); gen_alloc_enter((struct pt_regs *)args, args->bytes_alloc); return gen_alloc_exit2((struct pt_regs *)args, (size_t)args->ptr); } TRACEPOINT_PROBE(kmem, kmem_cache_alloc_node) { if (WORKAROUND_MISSING_FREE) gen_free_enter((struct pt_regs *)args, (void *)args->ptr); gen_alloc_enter((struct pt_regs *)args, args->bytes_alloc); return gen_alloc_exit2((struct pt_regs *)args, (size_t)args->ptr); } """ bpf_source_kernel = """ TRACEPOINT_PROBE(kmem, kmalloc) { if (WORKAROUND_MISSING_FREE) gen_free_enter((struct pt_regs *)args, (void *)args->ptr); gen_alloc_enter((struct pt_regs *)args, args->bytes_alloc); return gen_alloc_exit2((struct pt_regs *)args, (size_t)args->ptr); } TRACEPOINT_PROBE(kmem, kfree) { return gen_free_enter((struct pt_regs *)args, (void *)args->ptr); } TRACEPOINT_PROBE(kmem, kmem_cache_alloc) { if (WORKAROUND_MISSING_FREE) gen_free_enter((struct pt_regs *)args, (void *)args->ptr); gen_alloc_enter((struct pt_regs *)args, args->bytes_alloc); return gen_alloc_exit2((struct pt_regs *)args, (size_t)args->ptr); } TRACEPOINT_PROBE(kmem, kmem_cache_free) { return gen_free_enter((struct pt_regs *)args, (void *)args->ptr); } TRACEPOINT_PROBE(kmem, mm_page_alloc) { gen_alloc_enter((struct pt_regs *)args, PAGE_SIZE << args->order); return gen_alloc_exit2((struct pt_regs *)args, args->pfn); } TRACEPOINT_PROBE(kmem, mm_page_free) { return gen_free_enter((struct pt_regs *)args, (void *)args->pfn); } """ bpf_source_percpu = """ TRACEPOINT_PROBE(percpu, percpu_alloc_percpu) { gen_alloc_enter((struct pt_regs *)args, args->size); return gen_alloc_exit2((struct pt_regs *)args, (size_t)args->ptr); } TRACEPOINT_PROBE(percpu, percpu_free_percpu) { return gen_free_enter((struct pt_regs *)args, (void *)args->ptr); } """ if kernel_trace: if args.percpu: bpf_source += bpf_source_percpu else: bpf_source += bpf_source_kernel if BPF.tracepoint_exists("kmem", "kmalloc_node"): bpf_source += bpf_source_kernel_node if kernel_trace: bpf_source = bpf_source.replace("WORKAROUND_MISSING_FREE", "1" if args.wa_missing_free else "0") bpf_source = bpf_source.replace("SHOULD_PRINT", "1" if trace_all else "0") bpf_source = bpf_source.replace("SAMPLE_EVERY_N", str(sample_every_n)) bpf_source = bpf_source.replace("PAGE_SIZE", str(resource.getpagesize())) size_filter = "" if min_size is not None and max_size is not None: size_filter = "if (size < %d || size > %d) return 0;" % \ (min_size, max_size) elif min_size is not None: size_filter = "if (size < %d) return 0;" % min_size elif max_size is not None: size_filter = "if (size > %d) return 0;" % max_size bpf_source = bpf_source.replace("SIZE_FILTER", size_filter) stack_flags = "0" if not kernel_trace: stack_flags += "|BPF_F_USER_STACK" bpf_source = bpf_source.replace("STACK_FLAGS", stack_flags) if args.ebpf: print(bpf_source) exit() bpf = BPF(text=bpf_source) if not kernel_trace: print("Attaching to pid %d, Ctrl+C to quit." % pid) def attach_probes(sym, fn_prefix=None, can_fail=False, need_uretprobe=True): if fn_prefix is None: fn_prefix = sym if args.symbols_prefix is not None: sym = args.symbols_prefix + sym try: bpf.attach_uprobe(name=obj, sym=sym, fn_name=fn_prefix + "_enter", pid=pid) if need_uretprobe: bpf.attach_uretprobe(name=obj, sym=sym, fn_name=fn_prefix + "_exit", pid=pid) except Exception: if can_fail: return else: raise attach_probes("malloc") attach_probes("calloc") attach_probes("realloc") attach_probes("mmap", can_fail=True) # failed on jemalloc attach_probes("posix_memalign") attach_probes("valloc", can_fail=True) # failed on Android, is deprecated in libc.so from bionic directory attach_probes("memalign") attach_probes("pvalloc", can_fail=True) # failed on Android, is deprecated in libc.so from bionic directory attach_probes("aligned_alloc", can_fail=True) # added in C11 attach_probes("free", need_uretprobe=False) attach_probes("munmap", can_fail=True, need_uretprobe=False) # failed on jemalloc else: print("Attaching to kernel allocators, Ctrl+C to quit.") # No probe attaching here. Allocations are counted by attaching to # tracepoints. # # Memory allocations in Linux kernel are not limited to malloc/free # equivalents. It's also common to allocate a memory page or multiple # pages. Page allocator have two interfaces, one working with page # frame numbers (PFN), while other working with page addresses. It's # possible to allocate pages with one kind of functions, and free them # with another. Code in kernel can easy convert PFNs to addresses and # back, but it's hard to do the same in eBPF kprobe without fragile # hacks. # # Fortunately, Linux exposes tracepoints for memory allocations, which # can be instrumented by eBPF programs. Tracepoint for page allocations # gives access to PFNs for both allocator interfaces. So there is no # need to guess which allocation corresponds to which free. def print_outstanding(): print("[%s] Top %d stacks with outstanding allocations:" % (datetime.now().strftime("%H:%M:%S"), top_stacks)) alloc_info = {} allocs = bpf["allocs"] stack_traces = bpf["stack_traces"] for address, info in sorted(allocs.items(), key=lambda a: a[1].size): if BPF.monotonic_time() - min_age_ns < info.timestamp_ns: continue if info.stack_id < 0: continue if info.stack_id in alloc_info: alloc_info[info.stack_id].update(info.size) else: stack = list(stack_traces.walk(info.stack_id)) combined = [] for addr in stack: combined.append(('0x'+format(addr, '016x')+'\t').encode('utf-8') + bpf.sym(addr, pid, show_module=True, show_offset=True)) alloc_info[info.stack_id] = Allocation(combined, info.size) if args.show_allocs: print("\taddr = %x size = %s" % (address.value, info.size)) to_show = sorted(alloc_info.values(), key=alloc_sort_map[sort_key])[-top_stacks:] for alloc in to_show: print("\t%d bytes in %d allocations from stack\n\t\t%s" % (alloc.size, alloc.count, b"\n\t\t".join(alloc.stack).decode("ascii"))) def print_outstanding_combined(): stack_traces = bpf["stack_traces"] stacks = sorted(bpf["combined_allocs"].items(), key=combined_sort_map[sort_key]) cnt = 1 entries = [] for stack_id, info in stacks: try: trace = [] for addr in stack_traces.walk(stack_id.value): sym = bpf.sym(addr, pid, show_module=True, show_offset=True) trace.append(sym.decode('utf-8')) trace = "\n\t\t".join(trace) except KeyError: trace = "stack information lost" entry = ("\t%d bytes in %d allocations from stack\n\t\t%s" % (info.total_size, info.number_of_allocs, trace)) entries.append(entry) cnt += 1 if cnt > top_stacks: break print("[%s] Top %d stacks with outstanding allocations:" % (datetime.now().strftime("%H:%M:%S"), top_stacks)) print('\n'.join(reversed(entries))) count_so_far = 0 while True: if trace_all: print(bpf.trace_fields()) else: try: sleep(interval) except KeyboardInterrupt: exit() if args.combined_only: print_outstanding_combined() else: print_outstanding() sys.stdout.flush() count_so_far += 1 if num_prints is not None and count_so_far >= num_prints: exit()