gpt4 book ai didi

debugging - 16 位实模式程序的调试器如何生成堆栈跟踪?

转载 作者:行者123 更新时间:2023-12-03 08:13:57 24 4
gpt4 key购买 nike

我正在模拟器中运行旧的 DOS 程序,我已经到了想要跟踪程序堆栈的地步。但是,我遇到了一个问题,特别是如何检测近距调用和远距调用。一些借口:

  • near call 仅将 IP 压入堆栈,并预期与仅弹出要返回的 IP 的 ret 配对。
  • 调用 将CS 和IP 都压入堆栈,并预期与弹出CS 和IP 以返回的retf 配对。
  • 没有办法知道调用是近调用还是远调用,除非知道调用它的是哪种指令,或者它使用了哪种返回值。

幸运的是,在这个程序开发的时期,基于 BP 的堆栈框架非常很常见,所以遍历堆栈似乎不是问题:我只是遵循 BP 链.不幸的是,获取 CS 和/或 IP 很困难,因为我似乎没有任何方法可以仅通过查看堆栈来确定调用是近调用还是远调用。

我有关于可用函数的元数据,所以如果我已经知道实际的 CS 和 IP,我可以判断一个函数是近调用还是远调用,但我无法弄清楚 IP 和 CS,除非我已经知道它是不是远电话或近电话。

我通过猜测 并查看我的猜测是否导致有效的函数查找取得了一些成功,但我认为这种方法会产生很多误报。

所以我的问题是:DOS 时代的调试器是如何处理这个问题并产生堆栈跟踪的?是否有一些我缺少的算法,或者他们只是在堆栈中编码调试信息? (如果是这样的话,那我就得想出别的办法了。)

最佳答案

只是猜测,我从未真正使用过 16 位 x86 开发工具(现代的或过去的):

您知道当前函数的 CS:IP 值(或触发故障的函数或来自异常帧的任何内容)。

您可能有元数据告诉您这是否是通过远调用调用的“远”函数。或者您可以尝试解码直到到达 retnretf,并使用它来确定返回地址是接近 IP 还是远 CS:IP.

(假设这是一个返回某种ret的普通函数。或者如果它以对另一个函数的jmp尾调用结束,那么返回地址可能匹配那,但那是另一个层次的假设。在没有任何符号元数据的情况下,弄清楚附近的 jmp 是函数的结尾,而不仅仅是大型函数内的跳转是一个模棱两可的问题。)

但是无论如何,将同样的事情应用于父函数:在成功回溯一级之后,您现在在父函数中的 call 之后拥有指令的 CS:IP,以及 SS :BP链表的BP值。


顺便说一句,是的,遗留 BP 堆栈帧被广泛使用是有充分理由的:[SP] 不是有效的 16 位寻址模式,只有 [BP] 作为基础意味着 SS 作为一个段,所以是的,使用 BP 访问堆栈是随机访问的唯一好的选择(不仅仅是临时的 push/pop)。没有理由不先保存/恢复它(在任何其他寄存器或保留堆栈空间之前)来制作传统的堆栈框架。

关于debugging - 16 位实模式程序的调试器如何生成堆栈跟踪?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/52936900/

24 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com