在x86调试中,符号如何解决使用FPO走栈的问题?

时间:2017-08-16 13:28:44

标签: windows debugging x86 symbols callstack

在这个答案:https://stackoverflow.com/a/8646611/192359中,解释了在调试x86代码时,即使使用FPO(帧指针省略),符号也允许调试器显示调用栈。

给出的解释是:

  

在x86上,PDB包含FPO信息,允许调试器可靠地展开调用堆栈。

我的问题是这些信息是什么?据我所知,只知道函数是否具有FPO并不能帮助您找到堆栈指针的原始值,因为这取决于运行时信息。

我在这里缺少什么?

1 个答案:

答案 0 :(得分:3)

从根本上说,总是可以使用足够的信息 1 来遍历堆栈,除非堆栈或执行上下文已被不可挽回地损坏。

例如,即使rbp未用作帧指针,返回地址仍然在堆栈的某处,您只需要知道在哪里。对于不在函数体中修改rsp(间接或直接)的函数,它将处于与rsp的简单固定偏移处。对于在函数体中修改rsp的函数(即具有可变堆栈大小的函数),rsp的偏移量可能取决于函数中的确切位置。

PDB文件只包含这个“边带”信息,允许某人确定函数中任何指令的返回地址。 Hans链接了相关的内存中结构above - 您可以看到,因为它知道局部变量的大小等等,它可以计算rsp和帧的基数之间的偏移量,因此到达返回地址。它还知道有多少指令字节是“prolog”的一部分,这很重要,因为如果IP仍在该区域中,则应用不同的规则(即,尚未调整堆栈以反映此函数中的本地)。

在64位Windows中,确切的函数调用ABI已经变得更加具体,而所有函数通常必须提供展开信息:不是.pdb而是直接在.pdb包含在二进制文件中的部分。因此,即使没有exit()文件,您也应该能够展开结构合理的64位Windows程序。它允许任何寄存器用作帧指针,并且仍然允许帧指针省略(有一些限制)。有关详细信息,请start here

1 如果不是这样,问问自己当前运行的函数如何返回?现在,技术上你可以设计一个程序,它以无法返回的方式破坏或忘记堆栈,并且永远不会退出或使用abort()//Main upate public void update(float delta) { updateFriction(); } //Movements and Subclasses of them public void accelerate() { //find current speed in forward direction Vector2 currentForwardNormal = ship.getWorldVector(new Vector2(0,1)); float currentSpeed = getForwardVelocity().dot(currentForwardNormal); //apply necessary force float force = 0; if(maxSpeed > currentSpeed) { force = maxDriveForce; } else { force = -maxDriveForce; } System.out.println("Current Speed: "+currentSpeed); System.out.println("Current Forward Normal: "+currentForwardNormal); ship.applyForceToCenter(currentForwardNormal.scl(force),true); } public void rotate(boolean direction) { //true for Up and false for Down if(direction) { //torques } } private void updateFriction() { Vector2 impulse = getLateralVelocity().scl(-ship.getMass()); ship.applyLinearImpulse(impulse, ship.getWorldCenter(), true); ship.applyAngularImpulse(0.1f * ship.getInertia() * -ship.getAngularVelocity(),true); } private Vector2 getLateralVelocity() { Vector2 currentRightNormal = ship.getWorldVector(new Vector2(1,0)); return currentRightNormal.scl(currentRightNormal.dot(ship.getLinearVelocity())); } private Vector2 getForwardVelocity() { Vector2 currentRightNormal = ship.getWorldVector(new Vector2(0,1)); return currentRightNormal.scl(currentRightNormal.dot(ship.getLinearVelocity())); } 之类的方法来终止。这是非常不寻常的,不可能在组装之外。