Linux:GDB 调试一些函数栈被毁坏的问题

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6

一、背景

        GDB调试代码时偶尔会遇到一些奇怪的现象函数的参数地址在函数内部被传递给另外的函数然后发现地址发生了改变这样的情况称之为函数的栈被毁坏导致无法重入。

然后被调用的函数里面访问了非法的地址导致了segment fault,产生core dump文件。

        这类问题一般都比较棘手。

二、如何解决

        此类问题可以从gdb的栈保护设置开始着手。

编译的时候添加编译选项-fstack-protector -fstack-protector-all 这两个选项指示编译器开启栈保护这样在栈乱序的第一时间可以dump出来现场。可加在Makefile里面。

三、举例

1、问题

  • 以多线程应用程序中由于线程间的冲突导致的栈破坏为例讲解调试方法。由于存在栈破坏可以说backtrace信息并不完整
  • 问题某个进行线程间通信的程序中含有bug生成了coredump文件

2、解决方法

1、假设出现以下现象

gdbbt
#0 0x00000003b4869ac80 in nanossleep () from /lib64/libc.so.6
#1 000ee1c2000ee1c1 in ?? ()
#2 000ee1c2000ee1c3 in ?? ()
#3 000ee1c2000ee1c5 in ?? ()
#4 000ee1c2000ee1c7 in ?? ()

  • gdb的bt信息是依据栈里保存的函数返回地址来显示的。gdb的bt信息来自进程的栈上。
  • 上面的bt不正确的情况基本上可以认为是栈被破坏了

3、查看寄存器和栈

gdbinfo reg
...
rsp    0x4162f0c8    0x4162f0c8 
...
rip    0x3b4869ac80    0x3b4869ac80 <nanosleep+96>    
...

gdbx/i 0x3b4869ac80    
0x3b4869ac80 <nanosleep+96> retq <-这是函数的返回指令
/*
1.在x86中函数返回是从栈指针sp的地址处取出返回地址然后跳转到该地址
*/

(gdb)x/g 0x4162f0c8    
0x4162f0c8:    0x000ee1c2000ee1c1
/*
1.然而返回的地址成了0x000ee1c2000ee1c1也就是说跳转到该地址可怀疑
返回地址被破坏了。可认为是栈被破坏了。
2.因此可以认为跳转地址不正确即栈上的返回地址不正确
3.从bt也可以看出最后的nanpsleep()是从地址0x000ee1c2000ee1c1调用的而0x000ee1c2000ee1c1
不是正确的地址
*/

  • 由于栈空间还被用做局部变量的保存空间因此局部变量的内容也有可能被破坏
  • 调查栈破坏的方法依据被破坏的数据内容判断执行写入的位置看看有没有对栈空间(局部变量)的引用指针传递的处理
  • 栈破坏原因分析示例中在线程间的数据处理上传递了栈的指针导致了其他线程向该地址写入了数据。而这个其他线程向栈内写入数据的操作被推迟了从而导致了栈破坏。

正常时应用程序行为如下

出现问题时应用程序的行为

进阶

《GDB/Debug.Hacks中文版深入调试的技术和工具》

阿里云国内75折 回扣 微信号:monov8
阿里云国际,腾讯云国际,低至75折。AWS 93折 免费开户实名账号 代冲值 优惠多多 微信号:monov8 飞机:@monov6
标签: linux