软件调试过程中的函数参数确定

  • 问题背景

在项目开发过程中经常需要进行软件调试,而软件调试过程中我们经常需要关注的是所打断点函数的入参是什么,尤其在调试现场问题时在没有调试信息的情况下如何获取函数参数是我们必须要掌握的技能,我在项目开发和现场问题的调试过程中使用下面所述方法来观察函数参数,这种方法经常能够使我解决遇到的问题,因此总结成此经验案例文档供大家参考。

  • 知识点
  1. CPU架构的基本知识
  2. 进程运行时的栈知识
  3. 函数调用时的参数传递

1  32位下参数传递方法

2  64位下参数传递方法

  1. 如何从汇编代码查找相应源代码
  • CPU架构的基本知识

CPU分32位和64位,一般我们说的x86(也有说法i386)指的是32位CPU,这类CPU主要以Intel 的CPU为主;x86_64指的是64位CPU,这类CPU主要以AMD为主,用lscpu命令能获取机器上CPU的详细信息。(关于CPU的32位、64位可以在维基百科上查阅)。

  1. 32位CPU的寄存器

通用寄存器中ESP寄存器用于保存堆栈指针,EBP用于存放基址指针,某些命令使用特定的通用寄存器,比如字符串命令将ECX,ESI,EDI寄存器作为操作数使用。

段寄存器中CS用于保存代码段,DS用于保存数据段,SS用于保存堆栈段。

还有其他类型的寄存器比如控制寄存器(CR0~CR4),调试寄存器(DR0~DR7),MMX寄存器和XMM寄存器等。

  1. 64位CPU的寄存器

64位CPU寄存器与32位CPU寄存器使用大同小异,只需要关注的是32位下能够访问的内存大小为4GB,64位下Intel能够访问的内存大小为240字节,AMD能够访问的内存大小为248字节。

另外还要知道的是32位CPU一般采用分段内存模型,64位一般采用平坦内存模型,具体各种内存模型的概念自行查阅。

  • 进程运行时的栈

程序运行时的栈是后进先出的,栈的用途包括保存程序运行期间的自动变量、函数调用时的参数传递,以及用于保存函数返回地址和返回值,这里给大家画个图,直观的展示下函数调用过程中栈的变化。

 

上面是函数A调用函数B的堆栈变化过程,观察这张图你需要记住的是上层函数A调用下层函数B之前会把调用参数先PUSH进栈,函数调用指令call会自动把返回地址(也就是下一条指令地址)PUSH进栈,然后在下层函数里将基址指针入栈,32位CPU里是EBP寄存器,由此完成函数调用过程。下层函数B返回时会把删除栈帧同时将栈中保存的返回地址POP到程序计数器寄存器中,32位CPU中是EIP寄存器。

Tips:进程栈大小是有限制的,通常默认为8MB,也可以修改栈帧的大小。

  • 函数调用时的参数传递

通过上面对函数调用过程中的栈帧变化,同时根据实际工作中的经验总结得出:

  1. 32位下参数传递方法

32位下,参数默认下是全部存放在栈中的,因此在调试过程中在函数开头1 将函数断住后,用ESP+4即可取得第一个参数,ESP+8取得第二个参数,第三,第四个参数以此类推。

     代码中也可以指定参数传递的方法,比如可以通过在函数定义前面加上 _attribute_((regparm(3)))这种方式声明让函数调用使用eax, edx, ecx三个通用寄存器传递开头三个参数。

  1. 64为下参数传递方法

32位下不同,64位下基本使用寄存器传递参数,除非寄存器不够用时才把参数放到堆栈中。整型和指针型参数会从左至右依次保存到rdirsirdxrcxr8r9中,浮点型参数会保存到xmm0xmm1….中。多于这些寄存器的参数会被保存到栈上。

因此,在函数开头中断后,查看寄存器或栈即可获得参数内容。

注释1:这里说函数开头的意思要注意,在打函数断点时应该在函数名称前加上*号,比如在函数B打断点的话应该是b *B,因为如果不加*号的话会直接跳过一些汇编语句,那么这时候如果用ESP+4的话就不是第一个参数的值了。

注释2: 需要说明的是,C++里代码经过编译后函数名会被变换(mangle),如果编译时没有加上-g调试选项,那么无法直接通过b *B的方法来设置断点,而必须通过b  *_ZN3BfuncEii这种方式来设置断点。

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值