KernelShark调试笔记

KernelShark是Linux系统上的一个优化工具,最初是由红帽公司开发的,主要开发者是Steven Rostedt。

根据内核代码中的签名信息,Steven在2007年接手内核的ftrace模块,他可能是在开发ftrace的过程中,出于测试的需要,开发了建立在ftrace功能上的两个工具程序,一个是命令行形式的trace-cmd,另一个便是图形界面的KernelShark。

Steven在1998年读硕士时便参与Linux内核开发,在2006年加入RedHat,一直工作2016年。正是在RedHat工作时,Steven开发了ftrace和KernelShark。最初版本的KernelShark大约是在2010年时对外发布的。

25ada05e68d9d3c75131fe5bd02d9d61.pngSteven在Linux基金会官网上的照片 (来自LF官网)

我一直很喜欢KernelShark工具,常常使用这个工具,也总在讲Linux内核调试工具时介绍这个工具。

不知道是不是因为这个工具源自RedHat,在Ubuntu上,这个工具总是有些问题。比如在几年前的Ubuntu 16上,从Ubuntu仓库下载安装的的KernelShark菜单缺少重要的Record项。

f535763d6bd9bc19d4fe45ef029c3474.png

近日,在较新的Ubuntu 20.04上安装KernelShark,使用Ubuntu仓库安装,结果又是Record功能不工作。

69c8724516f5026c53bc207ece5834f0.png

于是我只好又用几年前的老办法,自己下载代码,自己build。

和上次一样,我到KernelShark的官网下载了最新的代码。

但是构建时,发现构建方法变了,不如以前简单方便了。但装了一些依赖后,还是构建通过了。 

但运行时,启动Record功能,立刻出了问题。

gebox@gebox-VirtualBox:~/kernel-shark-kernelshark-v2.1.0/bin$ ./kshark-su-record 

QStandardPaths: XDG_RUNTIME_DIR not set, defaulting to '/tmp/runtime-root'

free(): invalid pointer

./kshark-su-record: line 5: 13167 Aborted                 (core dumped) pkexec kshark-record -o ${PWD}/trace.dat

看起来是释放无效指针,glibc发起abort信号,紧急停车。

于是上调试器,追查。

有了调试器,很快定位到发起错误free的代码,即KsCaptureDialog.cpp的230行。

fe0195af1ba228c24171d8f675fbc2df.png

找到出问题的函数,其代码如下:

971c73971365f064715b6ea09d34b6bd.png

看来出问题的free释放的是来自kshark_tracecmd_local_plugins的字符串数组,是由tracefs_tracers返回的。

/** Get an array of available tracer plugins. */

char **kshark_tracecmd_local_plugins()

{

    return tracefs_tracers(tracefs_tracing_dir());

}

tracefs_tracers是libtracefs的接口函数,tracefs是ftrace的文件系统接口,主要开发者也是Steven。

根据librtracefs的文档,必须使用tracefs_list_free函数来释放tracefs_tracers返回的字符串数组。

The tracefs_tracers() function returns array of strings with the names of supported tracer
       plugins, located in the given tracing_dir directory. This could be NULL or the location of
       the tracefs mount point for the trace systems of the local machine, or it may be a path to
       a copy of the tracefs directory from another machine. The last entry in the array as a
       NULL pointer. The array must be freed with tracefs_list_free() API.

如此看来,这里直接使用free来释放,是个大bug,如果glibc不检查到,那么就可能把堆搞乱,导致更难发现的bug。

纠正了free问题后,重新编译,再运行,这下Record功能可以工作了,可以抓到事件和产生trace.dat文件了。但是打开文件分析时,KernelShark的界面挂住了,长时间没有更新,也没有反应。

9b548c68a171b959fb9d58d3faec3dd3.png

我是昨晚做上面的安装和调试工作的,改掉了一个bug后,没想到又出来一个。因为今天还要讲课,所以我想放弃新版本,改用老版本了。但是在要关闭电脑的时候,大脑中又有了继续战斗的念头。

于是,再次上调试器,切换UI线程,查找挂死原因。仔细一看,居然和白天讲课时讲的案例一模一样,UI线程在等待互斥量。

查找互斥量的拥有者线程,再找到等待这个互斥量的函数,查看源代码,发现了一个很明显的bug。

ec9108617f82851735458d5ac401c67b.png

789行获取锁,然后调用tracecmd_read_at函数,判断函数返回值,如果返回值为空,794行直接返回了,忘记释放锁。唉,这也太草率了。

在794行前面增加释放锁的代码,再次编译运行,这下终于可以正常工作了,熟悉的界面再次出现。

f2209f287b880adf3f13d04871800cfb.png

需要说明的是,上面两个比较明显、也比较严重的Showstopper级别的bug并不是出自Steven之手,Steven在2016年时就离开RedHat,加入Vmware,在Vmware工作四年后,目前在Google工作。

在今晚准备写这个文章时,顺着Steven的Linkedin动态找到trace-cmd 3.0的发布说明,又到trace-cmd的git网页。

https://git.kernel.org/pub/scm/utils/trace-cmd/kernel-shark.git/commit/

偶然中看到一个7天前的补丁信息:

Branch Commit message Author Age

kernelshark kernelshark: Release input_mutex on not finding record Steven Rostedt (Google) 7 days

看详细描述:

d220405e57d64899249e29f9f9029526.png

居然就是上面的第二个bug。看来Steven已经发现了这个问题。

查看git.kernel.org上第一个bug对应的源代码,bug还是在的。

756998f19ace1ebf4bf5a268b91b9896.png

如此看来,git.kernel.org上的代码与kernelshark.org上的代码相比,fix掉了第二个bug,更新一些。

第一个bug也许与libtracefs的实现有关,也就是与发行版有关,或许在某些实现中,返回的字符串数组可以直接使用free来释放。但仔细看了Steven本人写的tracefs的实现,在注释里也明确说了要使用专门的函数释放,言外之意是不可以使用free。

https://git.kernel.org/pub/scm/libs/libtrace/libtracefs.git/tree/src/tracefs-events.c

b6881c2110c43945c2c6e476185227e3.png

如此看来,第一个bug确实是bug无疑。

参考资料:

1. Steven的Linkedin页面

https://www.linkedin.com/in/steven-rostedt-0159437a/

2. Steven的个人网站

http://goodmis.org/ 

(写文章很辛苦,恳请各位读者点击“在看”,也欢迎转发)

*************************************************

正心诚意,格物致知,以人文情怀审视软件,以软件技术改变人生

扫描下方二维码或者在微信中搜索“盛格塾”小程序,可以阅读更多文章和有声读物

94174584af7fd97a0771b267ebc07394.png

也欢迎关注格友公众号

5dfed6af4dd7ce7a052f4ec8c6398b58.png

  • 3
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值