отладчик
отладчик
Есть два подхода к созданию отладчика:
* отладчик на базе инструментирования кода. Сделать его довольно легко, но он будет останавливать только один поток выполнения. Часы будут продолжать идти. А значит, он ограниченно пригоден. Тем не менее, он вполне пригоден для отладки компилятора и других подобных вычислительных задач. В нём легко сделать инспекцию выражений, а может быть, и их вычисление. ЯОС при этом может отлаживать как сама себя, так и другой экземпляр, через консоль (в т.ч. через UART)
* отладчик на базе QEMU/gdb. Такой отладчик позволит отлаживать операционную систему целиком, не меняя код приложения. Всевозможные чудеса с таким отладчиком доступны. Однако сделать его, видимо, гораздо сложнее.
Вот и стою в позе Буриданова осла.
* отладчик на базе инструментирования кода. Сделать его довольно легко, но он будет останавливать только один поток выполнения. Часы будут продолжать идти. А значит, он ограниченно пригоден. Тем не менее, он вполне пригоден для отладки компилятора и других подобных вычислительных задач. В нём легко сделать инспекцию выражений, а может быть, и их вычисление. ЯОС при этом может отлаживать как сама себя, так и другой экземпляр, через консоль (в т.ч. через UART)
* отладчик на базе QEMU/gdb. Такой отладчик позволит отлаживать операционную систему целиком, не меняя код приложения. Всевозможные чудеса с таким отладчиком доступны. Однако сделать его, видимо, гораздо сложнее.
Вот и стою в позе Буриданова осла.
Re: отладчик
План пока такой: gdb будет использоваться только как исполнительный механизм. Будет три программы:
* исследуемая ЯОС (в т.ч. в QEMU)
* gdb, подключившийся к исследуемой ЯОС/QEMU
* исследующая ЯОС (интерфейс отладчика)
В gdb есть attach - развязываем потоки вывода отладчика и ЯОС, а также call - позволяет в самой исследуемой программе реализовать часть отладчика (например, использовать пПиши в отлаживаемой программе). Задача большая, надо дробить на части.
* исследуемая ЯОС (в т.ч. в QEMU)
* gdb, подключившийся к исследуемой ЯОС/QEMU
* исследующая ЯОС (интерфейс отладчика)
В gdb есть attach - развязываем потоки вывода отладчика и ЯОС, а также call - позволяет в самой исследуемой программе реализовать часть отладчика (например, использовать пПиши в отлаживаемой программе). Задача большая, надо дробить на части.
- "Портаменто" - запустить существующий отладчик Богдана на Linux64 хотя бы частично (пропустить хаки в конце процедуры, наверное)
- "Горн" - управление сторонней программой через трубу (к горну для начала подключить что-нибудь попроще, чем gdb). Либо на основе Змея-Горыныча, либо без. Скорее второе, т.к. там нужна координация процессов, а координация процессов на разнородых языках - это хуже, чем разобраться с трубами как таковыми. Может пригодиться socat
- "Сцепка 1" - один ЯОС даёт команды другому
- "Провода" - текстовый интерфейс отладчика Богдана
- "Сцепка 2" - один ЯОС отлаживает другой через тестовый интерфейс, графика показывается на другом экране (хаха, как всё просто на словах)
- "Раскопки" - ищем куски, которые умеют парсить вывод отладчика и давать ему команды. Если они найдутся, то подпроект "Змей-Горыныч"
- "Змей-Горыныч" - проработать вопрос, ест подключения к ЯОС кода на другом языке, если найдутся уже готовые заготовки кусков, работающие как интерфейс отладчика, например, есть же intrace, ddd. См. Linux.Glue.Mod в начале файла - dlsym, dlopen и т.п.
- "Каменный цветок" - дальше додумаю потом - очевидно, тут пока перечислены только пункты отдельных кусочков, но перед стартом всего проекта нужно увидеть, к чему всё это должно прийти, а то вдруг неправильно.
Re: отладчик
План поменялся:
* под Win32 причесать код, в т.ч. внести изменения Богдана в основные модули вместо клонов, как это есть сейчас,
найти и выкинуть мёртвый код, перевести код (если не станет лень)
* разбить на клиента и сервера с возможностью общения через текстовый интерфейс
* сделать удалённую отладку (один ЯОС - отладчик, другой - отлаживаемое)
* портировать по отдельности клиента и сервер на Win64
* и уже потом портировать на Linux
* под Win32 причесать код, в т.ч. внести изменения Богдана в основные модули вместо клонов, как это есть сейчас,
найти и выкинуть мёртвый код, перевести код (если не станет лень)
* разбить на клиента и сервера с возможностью общения через текстовый интерфейс
* сделать удалённую отладку (один ЯОС - отладчик, другой - отлаживаемое)
* портировать по отдельности клиента и сервер на Win64
* и уже потом портировать на Linux
Re: отладчик
Время подходит к концу, надо переводить в вялотекущий режим. Успел не больше половины даже от перевода графического отладчика в командный режим. Текущие планы.
* сервер отладчика отвечает за установку и снятие точек останова, но не за их хранение. Список точек останова живёт на клиенте. При включении/выключении пошаговой отладки полный список точек в более-менее сжатом виде передаётся на сервер
* делим консольного клиент-сервера на подвал и дом. Подвал будет отвечать за обмен простыми командами (он будет связан по COM-порту или подобному каналу связи), а дом - за команды, вводимые пользователем. Дом будет вызывать подвал как процедуру, а не через обмен сообщениями. В т.ч. команда "беги" будет процедурой, к-рая будет возвращаться при приостановке отлаживаемого, завершении его или при обрыве связи
* оконный отладчик будет потом взаимодействовать уже с домом
Примеры команд подвала:
* включи/выключи Trap flag
* поставь/сними точку останова на адрес
* беги
* дай адрес модуля
* напечатай стек
* напечатай переменную
Примеры команд жилого этажа:
* беги
* шагни
* зайди
* открой модуль
* напечатай стек
* напечатай переменную
* поставь/сними точку останова на смещение
* прерви выполнение (это метакоманда, может быть она будет через другой механизм, например, через отправку сигнала gdb или отлаживаемому экземпляру ЯОС)
* сервер отладчика отвечает за установку и снятие точек останова, но не за их хранение. Список точек останова живёт на клиенте. При включении/выключении пошаговой отладки полный список точек в более-менее сжатом виде передаётся на сервер
* делим консольного клиент-сервера на подвал и дом. Подвал будет отвечать за обмен простыми командами (он будет связан по COM-порту или подобному каналу связи), а дом - за команды, вводимые пользователем. Дом будет вызывать подвал как процедуру, а не через обмен сообщениями. В т.ч. команда "беги" будет процедурой, к-рая будет возвращаться при приостановке отлаживаемого, завершении его или при обрыве связи
* оконный отладчик будет потом взаимодействовать уже с домом
Примеры команд подвала:
* включи/выключи Trap flag
* поставь/сними точку останова на адрес
* беги
* дай адрес модуля
* напечатай стек
* напечатай переменную
Примеры команд жилого этажа:
* беги
* шагни
* зайди
* открой модуль
* напечатай стек
* напечатай переменную
* поставь/сними точку останова на смещение
* прерви выполнение (это метакоманда, может быть она будет через другой механизм, например, через отправку сигнала gdb или отлаживаемому экземпляру ЯОС)
Re: отладчик
Кожисерв (бывшая КоОболочка) очевидно, является сервером.
КоКоКли (выпотрошенный ГрКдстп) - это заготовка для подвала клиента. На пляже - сценарий, который позволяет запустить одну команду (на второй - падает).
КоКоКли (выпотрошенный ГрКдстп) - это заготовка для подвала клиента. На пляже - сценарий, который позволяет запустить одну команду (на второй - падает).
Re: отладчик
Сделать клиента изоморфным серверу, в том смысле, что он тоже будет запускать подоболочки. Тогда мы можем абстрагироваться от того, что сервер и клиент у нас живут в отдельных процессах.
Re: отладчик
Проблема читать из исходников многострочные команды, содержащие тильду. Значит, для тестирования нужно сохранять текст, подлежащий чтению, в файл (пробовал расширить механизм чтения команд, но обломался). Вот с этого и надо начать - в БВыраж2 добавить тест, читающий БВыраж из файла и печатающий его в консоль.
Re: отладчик
Проект разморожен, пытаюсь понять, что к чему. Как минимум, ясно, что нужна Windows и в ней программа com0com, для создания пары связанных COM-портов.
Re: отладчик
Плюс минус нашёл, что последнее запускал. Теперь надо понять, что оно печатает (а печатает оно большую простыню). В принципе, похоже на том, что движок отладчика в рамках одного процесса уже частично разбит на клиент и сервер. На этом на сегодня всё.
Re: отладчик
Вот в этом видео показано состояние (правда, слегка устарело) и рассказано про следующий пункт плана:
https://dzen.ru/video/watch/6447ede586b84662e9f0fe16
На 14.47 показана примерная схема работы отладчика.
https://dzen.ru/video/watch/6447ede586b84662e9f0fe16
На 14.47 показана примерная схема работы отладчика.
Re: отладчик
ГрКодоступ должен использовать подобие КоКоКли, но как? КоКоКли общается через два потока, в один пишет, из другого читает.
Видимо, ТестБезОчистки является примером. экзКлиента.ПримиКомандуДляОтправкиНаСервер - это способ отправить команду. А как же дождаться ответа?
Ага, там есть какие-то заготовки, правда, они пустые. Подразумевается, что у КоКоКли есть какое-то "окно", с которым мы будем взаимодействовать.
Ну, во всяком случае, ясно, что надо выкинуть, как минимум, модуль ОсноваКодоступа и заменить его на КоКоКли, а дальше смотреть, чего не хватает, и доделывать.
Видимо, ТестБезОчистки является примером. экзКлиента.ПримиКомандуДляОтправкиНаСервер - это способ отправить команду. А как же дождаться ответа?
Ага, там есть какие-то заготовки, правда, они пустые. Подразумевается, что у КоКоКли есть какое-то "окно", с которым мы будем взаимодействовать.
Ну, во всяком случае, ясно, что надо выкинуть, как минимум, модуль ОсноваКодоступа и заменить его на КоКоКли, а дальше смотреть, чего не хватает, и доделывать.
Re: отладчик
Кое-что получилось, но это словами описать невозможно. По журналу гита более-менее понятно должно быть (мне).
Нужно доделать команды, а затем, если они сразу не заработают, не пора ли оживить Кожисерв? Он отстал от поезда.
Нужно доделать команды, а затем, если они сразу не заработают, не пора ли оживить Кожисерв? Он отстал от поезда.
Re: отладчик
На данный момент:
* режим "перешагивания" не работает вообще (работает до выхода из текущей процедуры)
* режим "захода" приводит к катастрофе, если программа завершается, никуда не зайдя
Очевидно, нам надо ориентироваться на стеке:
Представим себе рекурсивные вызовы:
Результатом нажатия F8 (перешагнуть) в этом случае должно быть то, что мы идём по нашей процедуре. Если мы вернулись из нашей процедуры, то мы
должны остановиться в другой процедуре. Но если мы не вернулись, то мы не должны остановиться.
Как можно в принципе это осуществить, с учётом того, что точки останова находятся не везде?
видимо, нужно снимать пробы стека, а также быть уверенными, что на любом вызове есть точки останова.
Как действовать? Замерять последовательность адресов возврата в стеке. Если в итоге замера глубина стека уменьшилась по сравнению с прошлой глубиной, то значит, мы вернулись. Если она увеличилась, то мы зашли внутрь. Для проверки - адреса на краю изменения должны совпасть. Но если они не совпадут, например, в результате недостатка точек, где можно поставить точку останова, то мы вряд ли что-то с этим сделаем, разве только сделать побольше лишних остановок в мутных случаях.
* режим "перешагивания" не работает вообще (работает до выхода из текущей процедуры)
* режим "захода" приводит к катастрофе, если программа завершается, никуда не зайдя
Очевидно, нам надо ориентироваться на стеке:
Представим себе рекурсивные вызовы:
Код: Выделить всё
другаяПроцедура
нашаПроцедура (здесь стоим в отладчике и нажимаем "перешагнуть")
другаяПроцедура (стоим именно на вызове другой процедуры)
должны остановиться в другой процедуре. Но если мы не вернулись, то мы не должны остановиться.
Как можно в принципе это осуществить, с учётом того, что точки останова находятся не везде?
видимо, нужно снимать пробы стека, а также быть уверенными, что на любом вызове есть точки останова.
Как действовать? Замерять последовательность адресов возврата в стеке. Если в итоге замера глубина стека уменьшилась по сравнению с прошлой глубиной, то значит, мы вернулись. Если она увеличилась, то мы зашли внутрь. Для проверки - адреса на краю изменения должны совпасть. Но если они не совпадут, например, в результате недостатка точек, где можно поставить точку останова, то мы вряд ли что-то с этим сделаем, разве только сделать побольше лишних остановок в мутных случаях.
Re: отладчик
Итак, нужна процедура, которая возвращает общую глубину стека и массив из N верхних адресов возврата на стеке. Видимо, достаточно N = 2.
Жить она должна в модуле рефлексии, но временно можно её поместить в основу кодоступа.
Жить она должна в модуле рефлексии, но временно можно её поместить в основу кодоступа.
Re: отладчик
Что касается вышагивания за пределы, то опять же можно смотреть по глубине стека и после возврата из процедуры, где мы нажали F7, оно будет деградировать до нефильтрованного F8.
Итого, есть три режима ходьбы:
1. истинно пошаговое исполнение с помощью Trap Flag - заканчивается после возврата из текущей процедуры - это нужно для начального этапа F7
2. хождение по временным точкам останова, но фильтруемое - это нужно для реализации F8, чтобы не попасть в более вложенные процедуры. После возврата из текущей процедуры мы меняем образец стека на новый, чтобы F8 не превратилось в F7
3. без Trap Flag, остановка на любой временной точке останова - режимы 1 деградирует до режима 3, когда мы возвращаемся из текущей процедуры.
Итого, есть три режима ходьбы:
1. истинно пошаговое исполнение с помощью Trap Flag - заканчивается после возврата из текущей процедуры - это нужно для начального этапа F7
2. хождение по временным точкам останова, но фильтруемое - это нужно для реализации F8, чтобы не попасть в более вложенные процедуры. После возврата из текущей процедуры мы меняем образец стека на новый, чтобы F8 не превратилось в F7
3. без Trap Flag, остановка на любой временной точке останова - режимы 1 деградирует до режима 3, когда мы возвращаемся из текущей процедуры.
Re: отладчик
Добавляем процесс. Есть mode = Terminated, и это позволяет отключиться от процесса, когда он завершится. В частности, можно так попытаться избавиться от беды с выкатыванием пошаговой отладки за пределы посадочной полосы. Хотя и стек так может.
В минимальном варианте достаточно просто мерять вершину стека и смотреть её динамику.
Также нужно прилипнуть к одному процессу и пропускать срабатывания точек останова в других процессах. А когда процесс будет завершён,
отключать пошаговую отладку и забывать присоединённый процесс (и выводить сообщение, что отлаживаемый процесс завершён, и возвращаться из оболочки верхнего уровня, или что-то в этом роде).
В минимальном варианте достаточно просто мерять вершину стека и смотреть её динамику.
Также нужно прилипнуть к одному процессу и пропускать срабатывания точек останова в других процессах. А когда процесс будет завершён,
отключать пошаговую отладку и забывать присоединённый процесс (и выводить сообщение, что отлаживаемый процесс завершён, и возвращаться из оболочки верхнего уровня, или что-то в этом роде).
Re: отладчик
Да и вообще надо выкинуть использование Trap Flag, потому что и без него всё получается, а он никак не помогает.
Re: отладчик
Зря выкинул Trap Flag, теперь впиливаю обратно. Зато появилась кнопка "разрешить ходьбу", которая по умолчанию выключена и которая
включает режим пошаговой отладки. В общем, сейчас попробую следующее:
* находить модуль, когда он не нашёлся в наших таблицах
* починить ходьбу по маш. коду
включает режим пошаговой отладки. В общем, сейчас попробую следующее:
* находить модуль, когда он не нашёлся в наших таблицах
* починить ходьбу по маш. коду
Re: отладчик
Как открыть новый модуль?
* КоКодоступ видит, что не попали в новый модуль. Кто дальше примет решение? Это проблема на самом деле.
а) он передаёт событие отладки в ГрКодоступ, ГрКодоступ не видит модуля, открывает его. При открытии подаётся команда КоКодоступу открыть тот же модуль, далее надо заново "встать на это место".
б) КоКодоступ сам открывает модуль. Но в этом случае нужен отдельный костыль при вызове оболочки, чтобы КоКодоступ сказал ГрКодоступу, что открыт новый модуль.
Оба варианта выглядят не особо, но пока мы идём по варианту (а). Чего не хватает?
* в КоКодоступе команды "дооткрой вот этот модуль и он должен попасть во вкладку j (это для проверки синхронности)
* в КоКодоступе нет команды "а теперь заново поищи это место", которая влияет на доступность команд. например, на доступность команды F8.
* потом отрефакторить ПокажиНекоеМесто, чтобы оно тоже открывало модуль
* не только "покажи место, где мы стоим", а просто "покажи место", с отдельным параметром "мы здесь стоим"
* КоКодоступ видит, что не попали в новый модуль. Кто дальше примет решение? Это проблема на самом деле.
а) он передаёт событие отладки в ГрКодоступ, ГрКодоступ не видит модуля, открывает его. При открытии подаётся команда КоКодоступу открыть тот же модуль, далее надо заново "встать на это место".
б) КоКодоступ сам открывает модуль. Но в этом случае нужен отдельный костыль при вызове оболочки, чтобы КоКодоступ сказал ГрКодоступу, что открыт новый модуль.
Оба варианта выглядят не особо, но пока мы идём по варианту (а). Чего не хватает?
* в КоКодоступе команды "дооткрой вот этот модуль и он должен попасть во вкладку j (это для проверки синхронности)
* в КоКодоступе нет команды "а теперь заново поищи это место", которая влияет на доступность команд. например, на доступность команды F8.
* потом отрефакторить ПокажиНекоеМесто, чтобы оно тоже открывало модуль
* не только "покажи место, где мы стоим", а просто "покажи место", с отдельным параметром "мы здесь стоим"
Последний раз редактировалось БудДен 08.03.24 13:51, всего редактировалось 1 раз.
Re: отладчик
Но беда будет в случае, когда вместо ГрКодоступа мы используем другой клиент. Тогда другой клиент должен будет воспроизвести ту же последовательность событий. А именно:
А как в будущем с тонким сервером?
Код: Выделить всё
сервер: мы остановились в точке PC = 123123123, модуля не знаю
клиент: ищет модуль и грузит его
клиент: мы стоим в точке PC = 123123123, модуль ABC, пр-ра DEF, смещение 5
сервер: мы стоим в точке соответствия
клиент: разрешаю шагать от точки
сервер: принято
клиент: F8
Код: Выделить всё
сервер: мы остановились в точке PC = 123123123
клиент: ищет модуль и грузит его
клиент: мы стоим в точке PC = 123123123, модуль ABC, пр-ра DEF, смещение 5, в точке соответствия
клиент: поставь временные брекпойнты по адресам 1,2,3,4,5
клиент: беги
Re: отладчик
Почему падает раскодировщик при попытке дизассемблировать модуль ЛогЯдра? Для статически слинкованных модулей code = 0. А адрес процедуры берётся из refs, потом от них отнимается (или прибавляется, не суть) адрес начала кода. А где же тогда информация о расположении процедуры? Modules.ThisModuleByAdr0 говорит о том, что информация хранится в m.procTable. Значит, нам надо полезть в неё и найти эту же процедуру в procTable, тогда мы сможем починить раскодировщик для статически слинкованных модулей. Заполнять поле code не стоит, поскольку тогда можно будет попытаться выгрузить этот модуль и его код будет испорчен.
Re: отладчик
А вот кстати, он отнимается. Значит, в refs уже адрес процедуры, а нам зачем-то в декодере нужны именно смещения. Значит, надо их найти и изжить (codeOffset).
Re: отладчик
После сборки Win32 oberon.log содержит такое:
Можно ли исходя из этого считать, что нет такого понятия как "байты кода"? Или это так нормально? В общем, попробую всё же изжить все использования Modules.code и везде использовать адреса, хотя это не выглядит простым.
Код: Выделить всё
000447670H: code Kernel.second
000447674H: data Kernel.@ConstSections to 000449753H
0004476A8H: code Kernel.FinalizerNode
Re: отладчик
Не совсем ясно, куда дальше двигаться. Попробую хотя бы отделить гуй от начинки отладчика, а общение между ними - только через оболочку. Тогда сможем отлаживать гуй. Но проблема в том, что на самом деле нам нужно привлечь схему в gdb, т.е. нужно в другом месте разрезать и добиться "тощего сервера", который умеет такой минимум:
* ThisModuleByAdr
* b (поставить и снять точку останова)
* r (запустить программу)
* s (шагнуть)
* bt (напечатать стек)
Ну и ещё немногое. И при этом по минимуму (в идеале - никак) не использует возможности платформы, такие, как "дождись" и "нов".
* ThisModuleByAdr
* b (поставить и снять точку останова)
* r (запустить программу)
* s (шагнуть)
* bt (напечатать стек)
Ну и ещё немногое. И при этом по минимуму (в идеале - никак) не использует возможности платформы, такие, как "дождись" и "нов".
Re: отладчик
ГрКоКодоступ + КоКодоступ привело почти к удвоению объёма кода, при том, что нужного архитектурного разреза не получилось. Ну его нафиг тогда.
Объединяем обратно в:
ГрКодоступН + УКодоступ, где УКодоступ будет просто набором утилит. Ну или оставить там только то, что относится к обработчику прерывания, чтобы этот код был вынесен в отдельное место. Ввиду его хрупкости он должен быть под учётом и это в значительной мере достигнуто.
Объединяем обратно в:
ГрКодоступН + УКодоступ, где УКодоступ будет просто набором утилит. Ну или оставить там только то, что относится к обработчику прерывания, чтобы этот код был вынесен в отдельное место. Ввиду его хрупкости он должен быть под учётом и это в значительной мере достигнуто.