概述

             在开发中分析问题的时候不管是从log分析系统服务,还是跟踪和内核驱动的交互,能够动态去观测堆栈或者是参数都是很重要的,特别是针对一些闭源库,没有源码导致分析更是难上加难,本文介绍一种使用gdb来进行动态跟踪的方法。

说明

             本文以展锐闭源的gnss_test程序为例来分析其如何与内核驱动进行交互的过程进行分析,主要通过gdb跟跟踪准库的open和ioctl函数来分析其大概的过程。开发者也可以同样根据这个方法来对其他的函数进行动态的跟踪。开发者可以去参照 gdb/gdbserver调试 搭建基础环境,开发者手机还要参照 解决ubuntu 20 开发者手机hdc无法使用 ,参照着两个文章构建调试环境。

操作

建立gdb连接

 

连接到开发板的调试环境,在主函数停下。

设置断点跟踪信息

这里commands名就是设置gdb命令,gdb将会遇到此断点的时候自动执行这些命令,上图我们只是想观测这些断点时程序的行为,让gdb打印信息并自动继续执行。

当然你也可以不设置commands,这样就会回到默认的gdb调试模式。

获取调试信息

 设置完调试命令之后,gdb就会按照你设置断点和命令自动去打印相关的信息,而通过这信息就可以看到他到底打开了哪些设备,已经使用哪些ioctl等详细信息,而且保证无一遗漏,而且对于整个程序的调整顺序,以及每一次调用的堆栈也有详细的数据,这对于分析程序行为都是非常关键的。

可以很轻松就看到 /dev/gnss_pmnotify_ctl、  /dev/gnss_dbg、 /dev/data0_gnss 、 /sys/class/misc/gnss_common_ctl/gnss_subsys、/sys/class/misc/gnss_common_ctl/gnss_clktype、/sys/class/misc/gnss_common_ctl/gnss_status等设备文件在此程序中被打开使用,而且可以观测到其调用的详细时刻,以及此刻的程序输出行为。

ioctl则是集中在fd=16的设备上,ioctl的命令则是有21515 21505 21506等,同样你可以看到调用的详细时刻。

结合/proc文件系统,我们就可以知道ioctl到底是发送给了那个设备的路径信息。

# ps -ef |grep gns
root          2160  2132 0 22:57:48 pts/0 00:00:02 gdbserver 0.0.0.0:1234 /data/gnss_test
root          2162  2160 0 22:57:48 pts/0 00:00:00 gnss_test
root          3050  3046 3 23:43:14 pts/1 00:00:00 grep gns
# ls /proc/2162/fd                                                             
fd/      fdinfo/
# ls /proc/2162/fd                                                             
0  10  12  14  16  2   3  5  7  9  
1  11  13  15  17  24  4  6  8  
# ls /proc/2162/fd -slha                                                       
total 0
0 dr-x------ 2 root root  0 1970-01-10 22:57 .
0 dr-xr-xr-x 9 root root  0 1970-01-10 22:57 ..
0 lrwx------ 1 root root 64 1970-01-10 22:57 0 -> /dev/pts/0
0 lrwx------ 1 root root 64 1970-01-10 22:57 1 -> /dev/pts/0
0 lrwx------ 1 root root 64 1970-01-10 23:43 10 -> anon_inode:[eventpoll]
0 lrwx------ 1 root root 64 1970-01-10 22:57 11 -> /dev/console
0 lrwx------ 1 root root 64 1970-01-10 22:57 12 -> socket:[27232]
0 lrwx------ 1 root root 64 1970-01-10 23:43 13 -> /dev/gnss_pmnotify_ctl
0 lr-x------ 1 root root 64 1970-01-10 23:43 14 -> /sys/devices/platform/backlight/backlight/sprd_backlight/actual_brightness
0 lrwx------ 1 root root 64 1970-01-10 23:43 15 -> /dev/gnss_dbg
0 lrwx------ 1 root root 64 1970-01-10 23:43 16 -> /dev/data0_gnss
0 lrwx------ 1 root root 64 1970-01-10 23:43 17 -> /data/vendor/gnss/sprd/gnss.log
0 lrwx------ 1 root root 64 1970-01-10 22:57 2 -> /dev/pts/0
0 lrwx------ 1 root root 64 1970-01-10 22:57 24 -> socket:[303]
0 lrwx------ 1 root root 64 1970-01-10 22:57 3 -> socket:[38739]
0 lrwx------ 1 root root 64 1970-01-10 22:57 4 -> socket:[41190]
0 lrwx------ 1 root root 64 1970-01-10 22:57 5 -> anon_inode:[eventpoll]
0 lrwx------ 1 root root 64 1970-01-10 23:43 6 -> socket:[41191]
0 lrwx------ 1 root root 64 1970-01-10 23:43 7 -> anon_inode:[eventpoll]
0 lr-x------ 1 root root 64 1970-01-10 23:43 8 -> pipe:[41945]
0 l-wx------ 1 root root 64 1970-01-10 23:43 9 -> pipe:[41945]

通过这个方式基本上可以摸清楚改应用到底是如何与内核进行一些细节,虽然不是全貌,但是这些信息也足够重要了。

总结

         通过这种方式开发者可以非常动态去设置不同的断点,并在每一个断点出执行一些自定义的gdb命令,让开发者可以随时观察程序的细节信息,而且不需要重新编译。甚至在一些没有源码情况下也可以做一定程序详细的分析。这方法可以不对代码做任何修改来动态去观察非常细节的程序行为,哪怕是正在运行中的程序也可以attach上进行分析。

 

 

 

 

 

 

 

Logo

社区规范:仅讨论OpenHarmony相关问题。

更多推荐