我正在使用模拟器运行旧的DOS程序,并且已经达到了想要跟踪程序堆栈的程度。但是,我遇到了一个问题,具体来说是如何检测近调用和远调用。一些背景信息:
- 近调用仅将IP推送到堆栈上,并且预计与仅弹出IP以返回的ret成对出现。 - 远调用将CS和IP都推送到堆栈上,并且预计与弹出CS和IP以返回的retf成对出现。 - 除了知道调用它的指令类型或使用哪种返回之外,没有办法知道调用是近调用还是远调用。
幸运的是,在开发该程序的时期,基于BP的堆栈帧非常普遍,因此似乎走过堆栈并不是问题:只需按照BP链即可。不幸的是,获取CS和/或IP很困难,因为似乎没有任何方法可以仅通过查看堆栈就确定调用是近调用还是远调用。
我有有关函数的元数据可用,因此如果我已经知道实际的CS和IP,我可以告诉函数是近调用还是远调用,但是除非我已经知道它是远调用还是近调用,否则我无法弄清楚IP和CS。
我通过猜测并查看我的猜测是否导致有效的函数查找来取得了一些成功,但是我认为这种方法会产生很多误报。
因此,我的问题是:DOS时代的调试器如何解决这个问题并生成堆栈跟踪?我是否错过了某种算法,还是他们只是在堆栈中编码调试信息?(如果是这种情况,那么我将不得不想出其他办法。)
- 近调用仅将IP推送到堆栈上,并且预计与仅弹出IP以返回的ret成对出现。 - 远调用将CS和IP都推送到堆栈上,并且预计与弹出CS和IP以返回的retf成对出现。 - 除了知道调用它的指令类型或使用哪种返回之外,没有办法知道调用是近调用还是远调用。
幸运的是,在开发该程序的时期,基于BP的堆栈帧非常普遍,因此似乎走过堆栈并不是问题:只需按照BP链即可。不幸的是,获取CS和/或IP很困难,因为似乎没有任何方法可以仅通过查看堆栈就确定调用是近调用还是远调用。
我有有关函数的元数据可用,因此如果我已经知道实际的CS和IP,我可以告诉函数是近调用还是远调用,但是除非我已经知道它是远调用还是近调用,否则我无法弄清楚IP和CS。
我通过猜测并查看我的猜测是否导致有效的函数查找来取得了一些成功,但是我认为这种方法会产生很多误报。
因此,我的问题是:DOS时代的调试器如何解决这个问题并生成堆栈跟踪?我是否错过了某种算法,还是他们只是在堆栈中编码调试信息?(如果是这种情况,那么我将不得不想出其他办法。)