Как отладчики для 16-битных программ реального режима производили трассировки стека? - PullRequest
0 голосов
/ 22 октября 2018

Я возиться с запуском старых программ для DOS в эмуляторе, и я дошел до того, что мне хотелось бы отследить стек программы.Тем не менее, я сталкиваюсь с проблемой, в частности, как обнаружить ближние и дальние вызовы.Некоторые предлоги:

  • Рядом с call помещается только IP-адрес в стек, и ожидается, что он будет связан с ret, который выдвигает только IP-адрес для возврата.
  • Far call помещает CS и IP в стек, и ожидается, что он будет соединен с retf, который выдвигает CS и IP для возврата.
  • Нет способа узнатьявляется ли вызов ближним или дальним, за исключением того, что он знает, какой тип инструкции вызвал его или какой ответ он использует.

К счастью, за период, в который была разработана эта программа, BP-основанные на стеке фреймы были очень обычными, так что обход стека не кажется проблемой: я просто следую цепочке BP.К сожалению, получить CS и / или IP сложно, потому что, кажется, у меня нет никакого способа определить, является ли вызов ближним или дальним, глядя только на стек.

У меня есть метаданные о доступных функциях, поэтому я могу сказать, является ли функция ближним или дальним вызовом, если я уже знаю фактические CS и IP, но я не могу определить IP и CS, если я уже не знаю, является ли это дальним вызовомили около вызова.

Я добился небольшого успеха, просто угадав и проверил, приводит ли мое предположение к действительному поиску функции, но я думаю, что этот метод даст много ложных срабатываний,

Итак, мой вопрос таков: как отладчики эпохи DOS справились с этой проблемой и создали трассировки стеков?Есть какой-то алгоритм для этого я пропускаю, или они просто кодируют отладочную информацию в стеке?(Если это так, то мне придется придумать что-то еще.)

1 Ответ

0 голосов
/ 23 октября 2018

Можно предположить, что я никогда не использовал 16-битные инструменты разработки для x86 (современные или прошлые):

Вы знаете значение CS: IP текущей функции (или той, которая сработала)ошибка или что-то еще из фрейма исключения).

Возможно, у вас есть метаданные, которые сообщают вам, является ли это «далекой» функцией, которая вызывается с дальним вызовом или нет.Или вы можете попытаться декодировать, пока не доберетесь до retn или retf, и использовать его, чтобы определить, является ли адрес возврата близким IP или дальним CS:IP.

(Предполагая, что этонормальная функция, которая возвращает с каким-то ret. Или, если она заканчивается jmp хвостовым вызовом другой функции, то адрес возврата, вероятно, соответствует этому, но это другой уровень предположений. И выяснение, что около jmp это конец функции, а не просто переход в большую функцию - это неоднозначная проблема без метаданных символа.)

Но в любом случае примените то же самое к родительской функции: после одного уровня успешного возврататеперь у вас есть CS: IP инструкции после call в родительской функции и значение SS: BP в связанном списке BP.


И кстати, да, это очень хорошопричина широкого использования устаревших стековых фреймов BP: [SP] не является допустимым 16-битным режимом адресации, и только [BP] в качестве основы подразумевает SS как сегмент, так что да, используяBP для доступа к стеку был единственным хорошим вариантом для произвольного доступа (не только push / pop для временных).Нет причин не сохранять / восстанавливать его вначале (перед любыми другими регистрами или резервированием стекового пространства) для создания обычного стекового кадра.

...