Files
Sprinter-SDCC/docs/vscode-sprinter-debug.md
T

273 lines
17 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# Source-debug Sprinter в VS Code
Статус: MVP для разработки самого отладчика. Поддержаны автоматический launch,
ручной attach, точки по строкам и функциям, logpoints, один C-frame,
регистры, простые global/static, continue/pause, instruction step и шаги
по исходнику F10/F11/Shift+F11.
> [!WARNING]
> **Windows пока не поддерживает полный цикл отладки.** Значение
> `debugger: "windows"` включает только штатное окно debugger MAME.
> Текущие launcher, owner lock и DAP/session transport используют Unix
> shell, `fcntl` и Unix domain sockets. Поэтому native Windows launch/attach
> из VS Code пока не считается рабочим. Поддержка потребует отдельного
> Windows transport и end-to-end проверки.
## Какие расширения нужны
Для build/run/debug используется собственное расширение этого проекта —
`toolchain/vscode-sprinter-debug`. Только оно знает формат source-debug
пакета, загрузку приложения через DSS, банки Sprinter и DAP-сессию MAME.
Microsoft C/C++ или clangd можно поставить дополнительно ради completion,
переходов по исходникам и подсветки. Оба анализируют код как близкий к
обычному C и не являются точной моделью SDCC: параметры `__naked`, ABI и
часть target-заголовков потребуют отдельных defines/configuration. Ошибки
реальной сборки всегда определяет `sprinter-cc`.
## Подготовка программы
Соберите приложение с полной картой:
```sh
pyenv exec make -C tests/hello SRC_DEBUG=1
```
Рядом с EXE появится `.sprinter-cc-hello/manifest.json`. При изменении C,
заголовка или опций `make` пересоберёт пакет по хэшу содержимого.
## Загрузка development-расширения
Из корня репозитория откройте VS Code с распакованным расширением:
```sh
code --extensionDevelopmentPath="$PWD/toolchain/vscode-sprinter-debug" "$PWD"
```
Если команда `code` не добавлена в `PATH`, на macOS этого проекта доступен
полный путь:
```sh
"/Applications/Visual Studio Code.app/Contents/Resources/app/bin/code" \
--new-window \
--extensionDevelopmentPath="$PWD/toolchain/vscode-sprinter-debug" \
"$PWD"
```
Расширение в режиме `auto` использует `~/.pyenv/shims/python` при наличии
local `.python-version`; для внешнего workspace ищет установленный
`~/.pyenv/versions/3.12*/bin/python`, затем `.venv/bin/python` и известные
абсолютные пути Python 3.12. Local-версия передаётся задаче сборки через
`PYENV_VERSION`, даже если приложение лежит вне workspace. Это не зависит от `PATH` процесса VS Code,
который мог быть открыт из Dock. Выбор можно переопределить абсолютным путём
в `sprinterDebugger.pythonCommand`; дополнительные аргументы задаются через
`sprinterDebugger.pythonArguments`.
## Автоматический launch
Добавьте в локальный `.vscode/launch.json`:
```json
{
"version": "0.2.0",
"configurations": [
{
"type": "sprinter-mame",
"request": "launch",
"name": "Sprinter MAME: hello",
"build": "${workspaceFolder}/tests/hello/.sprinter-cc-hello"
}
]
}
```
Launcher создаёт временные floppy/HDD/state-каталоги и видимое окно MAME.
В отдельный `cfg/sprinter.cfg` он записывает только включение обеих клавиатур
Sprinter: `:` и `:kbd:ms_naturl`. MAME по умолчанию активирует лишь первую,
поэтому без этой настройки физические клавиши не доходят до DSS `getchar()`.
Действующая пользовательская конфигурация MAME при этом не копируется.
Он читает символы текстового экрана из VRAM, находит пустой prompt `X:…>` и
требует, чтобы тот оставался готовым 0,25 секунды. Только затем ставится
service-точка `main` и вводится `a:\\HELLO.EXE`. После совпадения PC и
сигнатуры кода запускается session server, DAP принимает редакторские точки,
а VS Code показывает остановку на entry. Завершение debug session останавливает
только созданные ей MAME/server.
`dssTimeout` задаёт предельное время ожидания prompt (30 эмулируемых секунд).
`launchAt` можно задать как необязательную нижнюю границу времени запуска;
наличие prompt всё равно обязательно. Перед вводом сохраняется диагностический
снимок DSS.
Дополнительные файлы на floppy задаются массивом `data`, путь к другому MAME —
полем `mame`.
## Ручная проверка VS Code
В репозитории локально подготовлены два профиля `.vscode/launch.json`:
`Sprinter: hello (VS Code)` и `Sprinter: hello (VS Code + MAME debugger)`.
Файл `.vscode` намеренно игнорируется Git и не содержит личных путей.
1. Соберите `hello` командой из раздела «Подготовка программы» и запустите
Extension Development Host одной из команд выше.
2. Откройте `tests/hello/hello.c` и поставьте breakpoint на строке 31,
вызове `puts`.
3. В Run and Debug выберите `Sprinter: hello (VS Code)` и нажмите F5.
Расширение сначала выполнит `make SRC_DEBUG=1` в `tests/hello` как задачу
Sprinter Build. После успешной сборки должно появиться окно Sprinter;
launcher дождётся prompt DSS, введёт
`A:\\HELLO.EXE` и VS Code остановится в `main`.
4. Проверьте Call Stack, scope Registers и Debug Console. После Continue
должна сработать подтверждённая точка строки 31 по адресу `0x824b`.
5. На остановке проверьте F11 и F10. Курсор должен переходить только после
фактической остановки CPU, а не сразу после отправки команды. На строке 62
(`getchar`) нажмите F10, щёлкните окно Sprinter MAME и нажмите латинскую `x`:
выполнение должно перейти на строку 63. Пока программа ждёт клавишу,
кнопка Pause в VS Code должна останавливать CPU.
6. Завершите сессию кнопкой Stop. Затем повторите профиль с `osx`: вместе с
тем же VS Code-сеансом должно открыться штатное Cocoa-окно debugger MAME.
Команда палитры `Sprinter: Build Active Project` собирает приложение по
Makefile открытого C-файла. Задачи `Sprinter: Build ...` доступны и в
`Tasks: Run Task`. Для launch автоматическая сборка включена по умолчанию,
если из `build` можно найти Makefile с `app.mk`; нестандартный каталог задаётся
полем `project`, а уже собранный пакет запускается с `"autoBuild": false`.
Ошибка SDCC с файлом и строкой видна в Problems; ненулевой код задачи
останавливает F5 до запуска MAME. Явный `preLaunchTask` использует стандартное
поведение VS Code и отключает автоматическую сборку расширения.
Если F5 сообщает, что тип `sprinter-mame` неизвестен, окно запущено без
`--extensionDevelopmentPath`. Сообщение `Couldn't find a debug adapter
descriptor` означает, что extension manifest загружен, но расширение не
активировалось; после изменения `package.json` выполните `Developer: Reload
Window`. Канал Output → `Sprinter MAME Debug` показывает выбранные Python и
DAP. При раннем завершении MAME ответ launch включает последние строки
MAME log. Если сборочный пакет устарел, адаптер должен отказать до запуска
программы и показать причину, а не использовать старую карту.
Логи из исходника без вывода в DSS задаются в C через `<sdbg.h>`;
полный синтаксис и таблица поддержанных типов — в
[руководстве по SDBG_LOG](sdbg-log-macros.md):
```c
#include <sdbg.h>
volatile int total;
/* tag уникален в этом .c; total читает debugger, не приложение. */
SDBG_LOG(after_increment, "total={total}");
```
При F5 debug-сборка привяжет нулевой asm-якорь к адресу и session server
поставит logpoint после загрузки DSS. Попадание напишет `total=...` в
Debug Console VS Code и в debugger console MAME, затем продолжит выполнение.
В обычной сборке макрос пуст. Поддерживаются только global/static переменные
доказанного типа, литералы и `{name}`; локальные, выражения и `%d` пока нет.
`SDBG_LOGIF(tag, flag, "...")` выводит сообщение, если поддержанная
global/static `flag` ненулевая. Аргументы не исполняются на Sprinter, поэтому
выражения с побочными эффектами не имеют здесь смысла. В режиме `sdbg`
журнал MAME существует, но его штатное окно не открывается; для видимого
окна выберите `osx` ниже. Горячий logpoint может заметно замедлить эмуляцию:
CPU останавливается на каждом попадании. Если DAP не успевает забрать
события из ограниченного журнала, Debug Console сообщает число пропусков.
Текст в VS Code сохраняется точно; MAME console заменяет двойные кавычки
апострофами и управляющие символы пробелами из-за синтаксиса `printf`.
## Родной debugger MAME вместе с VS Code
По умолчанию используется project backend `sdbg`: видимо окно Sprinter,
а отдельное Cocoa-окно debugger не создаётся. Для регистров, дизассемблера,
памяти и console штатного MAME добавьте в launch-конфигурацию:
```json
"debugger": "osx"
```
Bridge и DAP продолжают работать параллельно. Ручные `go`, изменение точек и
reset в native console обходят модель состояния VS Code; reset пока нельзя
использовать из-за lifecycle-crash MAME 0.287.
Для MAME без project patch выберите штатный provider:
| Платформа/сборка | `debugger` |
|---|---|
| macOS | `osx` |
| Windows native | `windows` |
| Linux с Qt debugger | `qt` |
| Linux/SDL без Qt | `imgui` |
| Автоматический выбор доступного provider | `auto` |
`imgui` использует основное графическое окно MAME; launcher уже запускает его
с `-video soft -window`. `none` немедленно продолжает остановленный CPU, а
`gdbstub` ждёт протокол GDB, поэтому они не подходят для sdbgbridge.
Текущая host-часть sdbg использует `fcntl` и Unix domain sockets. Она работает
на macOS/Linux. Для native Windows нужны отдельные реализации owner lock,
локального RPC и launcher; выбор `windows` решает только сторону MAME и не
обеспечивает работу VS Code-интеграции.
Backend `sdbg` входит как воспроизводимый patch к MAME 0.287. Для локального
checkout достаточно:
```sh
make mame-sdbg
```
Команда идемпотентно применяет
`toolchain/mame-patches/0001-sdbg-debugger-backend.patch`, инкрементально
собирает MAME и устанавливает `mame/v306/mame.arm`.
## Logpoints
Обычная команда VS Code **Add Logpoint…** работает без пересборки. В сообщении
разрешены литералы и простые подстановки:
```text
frame={frame_counter} state={state}
```
Подстановка принимает только имя поддержанной переменной. Выражения,
format specifier и conversion отклоняются. Если logpoint и обычная точка
разрешились в один адрес, сообщение печатается, а CPU остаётся остановленным.
## Шаги по исходнику
F11 выполняет Z80-инструкции до следующей отличающейся C-позиции. F10 на
каждом машинном шаге использует MAME `over`, поэтому банковский вызов проходит
целиком. Shift+F11 сначала делает MAME `out`, затем проходит служебный bank
trampoline до первой C-позиции вызывающей функции. Instruction granularity
остаётся доступна для точного одиночного шага.
Автомат ограничен 512 машинными операциями. Команда шага отвечает VS Code
сразу; пока `getchar()` или другой вызов ждёт внешнего ввода, MAME продолжает
работать, а пользователь может нажать клавишу в его окне либо выполнить Pause
в VS Code. Время ожидания ввода не ограничивается таймаутом исходного шага.
При достижении предела CPU остаётся остановленным, а Debug Console получает
сообщение.
Пользовательская точка внутри шага имеет приоритет; logpoint печатается и шаг
продолжается с прежней семантикой.
## Ручной attach
Для общего MAME между CLI и VS Code сначала запустите `sdbg_server.py`, затем:
```json
{
"type": "sprinter-mame",
"request": "attach",
"name": "Sprinter MAME: Attach",
"socket": "/tmp/sprinter-sdbg.sock"
}
```
Команды server и диагностического CLI приведены в
[mame-source-debug-status.md](mame-source-debug-status.md).
## Ограничения MVP
- Reset/restart отключён после найденного crash MAME 0.287 на старом Lua
callback. Session завершается штатным terminate.
- Локальные, backtrace, setVariable, watchpoints и чтение неотображённого
bank-data ещё не реализованы.
- Если одна инструкция имеет несколько C-маркеров, frame помечается
`[ambiguous]`; адаптер не выбирает строку молча.