开发机用gdb调试远程服务器以及手机客户端,简化加载符号时,共享库的代码段地址映射计算。
1 define conn
2 shell adb forward --list | grep 1234 ; if [ $? == 1 ]; then adb forward tcp:1234 tcp:1234; fi; 2 file $arg0 3 target remote :1234 4 end 5 document conn 6 conn progma-file-path 7 end 8 9 # replace the chinese 10 set sysroot #手机/system目录拉到你机器的本地位置# 11 12 set solib-search-path #$(Project)/app/src/main/jniLibs/armeabi:$(Project)/app/build/intermediates/cmake/debug/obj/armeabi# 13 14 directory #$(Project)/app/src/main/cpp# 15 directory #$(ThirdPartProject)# 16 directory #$(ThirdPartInstallInclude)# 17 18 define showmaps 19 shell pid=`adb -d shell ps | grep #你的程序名# | sed -E 's/^w+//' | sed -E 's/[a-zA-Z].*$//' | sed -E 's/^[ ]+//' | sed -E 's/ .*$//'`; 20 echo pid = $pid; 21 sodir=#共享库目录#; soname=#共享库名称#; 22 echo $soname; baseaddr=`adb -d shell cat /proc/${pid}/maps | grep libnative-lib.so | grep r-xp | sed -E 's/-.*//'`; echo " "baseaddr = $baseaddr; readelf -S $sodir/$soname | grep .text; 23 sodir=#共享库目录#; soname=#共享库名称#; 24 echo $soname; baseaddr=`adb -d shell cat /proc/${pid}/maps | grep libmyjpeg.so | grep r-xp | sed -E 's/-.*//'`; echo " "baseaddr = $baseaddr; readelf -S $sodir/$soname | grep .text; 25 end 26 27 define myaddsyms 28 add-symbol-file $arg0 $arg1+$arg2 29 end 30 document myaddsyms 31 myaddsyms so-local-path baseaddr textoff 32 end
启动调试服务器, gdbs remote:1234 progma arg0 arg1 ...
附加到进程, gdbs --attach remote:1234 pid
确认gdbs是否在监听端口,因为selinux默认不允许对server类型的socket进行读写,也就是不可以accept.
你必须在dlopen共享库后加载它的本地版本,使用上面的脚本方法 showmaps
再用上面的脚本方法 myaddsyms
现在加载好符号了
要注意的是,你手动dlopen的共享库不会被正确地自动回收,如果你未能在主线程退出main函数之前将共享库dlclose,你的共享库将会继续访问已经结束的crt资源,程序退出就会抛出 SIGSEGV。
函数指针要小心,通常都是些回调,发作地点已经远离现场。有一天你的实现代码的定义添加了参数,但是你不清楚是否在其它地方以某一函数指针原型引用了,这样就悲剧了,程序可能会很长一段时间都不出问题,因为一般添加参数都是因为要兼容原来的逻辑基础上增加逻辑,新逻辑一开始会少运行,旧逻辑运行没有问题,一但新添加的参数缺失而引起的逻辑错误,你可能很发现是因为某处使用旧的函数指针原型去继续引用你的代码。