Глава 20 Отладчик (ocamldebug)
В этой главе описывается отладчик OCaml для пошагового выполнения исходного кода с возможностью воспроизведения ocamldebug.
Отладчик доступен в системах, поддерживающих BSD-сокеты, включая Windows. В нативных версиях для Windows функции replay недоступны.
1 Компиляция для отладки
Прежде чем использовать отладчик, программу необходимо скомпилировать и скомпоновать с параметром -g: все файлы .cmo и .cma, входящие в программу, должны быть созданы с помощью ocamlc -g, и их необходимо скомпоновать с помощью ocamlc -g.
Компиляция с параметром -g не влияет на время выполнения программ: объектные файлы и исполняемые файлы байт-кода становятся больше и дольше создаются, но исполняются с той же скоростью, что и при компиляции без -g.
2 Запуск
2.1 Запуск отладчика
Отладчик OCaml запускается командой ocamldebug, которой в качестве первого аргумента передаётся имя исполняемого файла байт-кода:
ocamldebug [options] program [arguments]
Аргументы, следующие за program, необязательны и передаются отлаживаемой программе в качестве аргументов командной строки. (См. также команду set arguments.)
Распознаются следующие параметры командной строки:
- -c count
- Установить максимальное число одновременно существующих контрольных точек равным count.
- -cd dir
- Запустить программу отладчика из рабочего каталога dir, а не из текущего каталога. (См. также команду cd.)
- -emacs
- Сообщить отладчику, что он запущен в Emacs. (Сведения о запуске отладчика в Emacs см. в разделе 20.10.)
- -I directory
- Добавить directory в список каталогов, в которых выполняется поиск исходных и скомпилированных файлов. (См. также команду directory.)
- -s socket
- Использовать socket для связи с отлаживаемой программой. Формат socket описан в разделе о команде set socket (раздел 20.8.8).
- -version
- Вывести строку версии и завершить работу.
- -vnum
- Вывести краткий номер версии и завершить работу.
- -help или --help
- Показать краткую справку по использованию и завершить работу.
2.2 Файл инициализации
При запуске отладчик считывает команды из файла инициализации, прежде чем передать управление пользователю. По умолчанию используется файл .ocamldebug в текущем каталоге, если он существует; в противном случае используется файл .ocamldebug в домашнем каталоге пользователя.
2.3 Завершение работы отладчика
Команда quit завершает работу отладчика. Также можно выйти из отладчика, введя символ конца файла (обычно ctrl-D).
Ввод символа прерывания (обычно ctrl-C) не завершает работу отладчика, а прекращает выполнение текущей команды отладчика и возвращает к приглашению командного уровня.
3 Команды
Команда отладчика представляет собой одну строку ввода. Она начинается с имени команды, за которым следуют аргументы, зависящие от этого имени. Примеры:
run
goto 1000
set arguments arg1 arg2
Имя команды можно сокращать, если при этом не возникает неоднозначности. Например, go 1000 распознаётся как goto 1000, поскольку нет других команд, начинающихся с go. Для наиболее часто используемых команд допускаются неоднозначные сокращения. Например, r обозначает run, хотя есть и другие команды, начинающиеся с r. Проверить допустимость сокращения можно с помощью команды help.
Если предыдущая команда выполнилась успешно, пустая строка (то есть нажатие только клавиши RET) повторит её.
3.1 Получение справки
В отладчике OCaml имеется простая встроенная система справки, содержащая краткое описание каждой команды и переменной.
- help
- Вывести список команд.
- help command
- Вывести справку по команде command.
- help set variable, help show variable
- Вывести справку по переменной variable. Список всех переменных отладчика можно получить с помощью команды help set.
- help info topic
- Вывести справку по теме topic. Чтобы получить список известных тем, используйте команду help info.
3.2 Доступ к состоянию отладчика
- set variable value
- Присвоить переменной отладчика variable значение value.
- show variable
- Вывести значение переменной отладчика variable.
- info subject
- Вывести сведения об указанном объекте. Например, команда info breakpoints выведет список всех точек останова.
4 Выполнение программы
4.1 События
События — это «интересные» места в исходном коде, соответствующие началу или завершению вычисления «интересных» подвыражений. События являются единицами пошагового выполнения (при пошаговом выполнении программа переходит к следующему или предыдущему событию). Кроме того, точки останова можно устанавливать только на событиях. Таким образом, события выполняют ту же роль, что и номера строк в отладчиках для традиционных языков.
Во время выполнения программы при каждом встреченном событии увеличивается счётчик. Значение этого счётчика называется текущим временем. Благодаря обратному выполнению можно перемещаться вперёд и назад к любому моменту выполнения.
Ниже показаны места в исходном коде, где располагаются события отладчика (обозначены ⋈):
- После вызова функции:
(f arg)⋈
- При входе в функцию:
fun x y z -> ⋈ ...
- В каждом случае определения с сопоставлением с образцом (функция, конструкция match…with, конструкция try…with):
function pat1 -> ⋈ expr1 | ... | patN -> ⋈ exprN - Между подвыражениями последовательности:
expr1; ⋈ expr2; ⋈ ...; ⋈ exprN
- В обеих ветвях условного выражения:
if cond then ⋈ expr1 else ⋈ expr2
- В начале каждой итерации цикла:
while cond do ⋈ body done for i = a to b do ⋈ body done
Исключения: вызов функции, за которым следует возврат из функции, компилятор заменяет переходом (оптимизация хвостового вызова). В этом случае после вызова функции событие не добавляется.
4.2 Запуск отлаживаемой программы
Отладчик начинает выполнять отлаживаемую программу только при необходимости. Благодаря этому можно установить точки останова или назначить переменные отладчика до начала выполнения. Есть несколько способов начать выполнение:
- run
- Выполнять программу до достижения точки останова или завершения программы.
- goto 0
- Загрузить программу и остановиться на первом событии.
- goto time
- Загрузить программу и выполнить её до указанного времени. Полезно, если вы уже примерно знаете, когда возникает проблема. Также удобно для установки точек останова на функциональные значения, которые не были вычислены в момент времени 0 (см. раздел 20.5).
На выполнение программы влияют некоторые данные, передаваемые ей при запуске отладчиком, например аргументы командной строки и рабочий каталог. Отладчик предоставляет команды для указания этих данных (set arguments и cd). Эти команды необходимо использовать до начала выполнения программы. Если попытаться изменить аргументы или рабочий каталог после запуска программы, отладчик завершит её (предварительно запросив подтверждение).
4.3 Выполнение программы
Следующие команды выполняют программу вперёд или назад, начиная с текущего времени. Выполнение остановится в указанном командой месте или при достижении точки останова.
- run
- Продолжить выполнение программы вперёд от текущего времени. Остановка произойдёт на следующей точке останова или при завершении программы.
- reverse
- Выполнять программу в обратном направлении от текущего времени. В основном команда используется для перехода к последней точке останова, достигнутой до текущего времени.
- step [count]
- Выполнять программу и остановиться на следующем событии. Если указан аргумент, выполнить это действие count раз. Если count равен 0, выполнять программу до её завершения или достижения точки останова.
- backstep [count]
- Выполнять программу в обратном направлении и остановиться на предыдущем событии. Если указан аргумент, выполнить это действие count раз.
- next [count]
- Выполнять программу и остановиться на следующем событии, пропуская вызовы функций. Если указан аргумент, выполнить это действие count раз.
- previous [count]
- Выполнять программу в обратном направлении и остановиться на предыдущем событии, пропуская вызовы функций. Если указан аргумент, выполнить это действие count раз.
- finish
- Выполнять программу до возврата из текущей функции.
- start
- Выполнять программу в обратном направлении и остановиться на первом событии перед вызовом текущей функции.
4.4 Перемещение во времени
С помощью команды goto можно сразу перейти к указанному времени, не останавливаясь на точках останова.
По мере перемещения по программе отладчик сохраняет историю моментов времени, в которые вы останавливались. Команду last можно использовать для возврата к этим моментам: каждая команда last перемещает на один шаг назад по истории. Это полезно, главным образом, чтобы отменить такие команды, как step и next.
- goto time
- Перейти к указанному времени.
- last [count]
- Вернуться к самому последнему времени, записанному в истории выполнения. Если указан аргумент, выполнить это действие count раз.
- set history size
- Задать размер истории выполнения.
4.5 Завершение программы
- kill
- Завершить выполняемую программу. Эта команда полезна главным образом, если вы хотите перекомпилировать программу, не выходя из отладчика.
5 Точки останова
Точка останова заставляет программу останавливаться при достижении определённого места в программе. Её можно установить несколькими способами с помощью команды break. При установке точкам останова присваиваются номера для дальнейшего использования. Удобнее всего устанавливать точки останова через интерфейс Emacs (см. раздел 20.10).
- break
- Установить точку останова в текущем месте выполнения программы. Текущая позиция должна находиться на событии (то есть не в начале и не в конце программы).
- break function
- Установить точку останова в начале function. Это работает, только если функциональное значение идентификатора function уже вычислено и присвоено этому идентификатору. Поэтому эту команду нельзя использовать в самом начале выполнения программы, когда все идентификаторы ещё не определены; используйте goto time, чтобы продвинуть выполнение до момента, когда функциональное значение станет доступно.
- break @ [module] line
- Установить точку останова в модуле module (или в текущем модуле, если module не указан) на первом событии строки line.
- break @ [module] line column
- Установить точку останова в модуле module (или в текущем модуле, если module не указан) на событии, ближайшем к строке line и столбцу column.
- break @ [module] # character
- Установить точку останова в модуле module на событии, ближайшем к символу с номером character.
- break frag:pc, break pc
- Установить точку останова по адресу кода frag:pc. Целое число frag — это идентификатор фрагмента кода, набора модулей, загруженных одновременно — изначально или с помощью модуля Dynlink. Целое число pc — это счётчик инструкций в данном фрагменте кода. Если frag не указан, по умолчанию используется 0 — фрагмент кода программы, загруженный изначально.
- delete [breakpoint-numbers]
- Удалить указанные точки останова. Если аргумент не задан, удаляются все точки останова (после запроса подтверждения).
- info breakpoints
- Вывести список всех точек останова.
6 Стек вызовов
Каждый раз, когда программа выполняет вызов функции, она сохраняет место вызова (адрес возврата) в блоке данных, называемом кадром стека. Кадр также содержит локальные переменные вызывающей функции. Все кадры размещаются в области памяти, называемой стеком вызовов. Команда backtrace (или bt) отображает часть стека вызовов.
В любой момент времени один из кадров стека «выбран» отладчиком; некоторые команды отладчика неявно обращаются к выбранному кадру. В частности, когда вы запрашиваете значение локальной переменной, оно находится в выбранном кадре. С помощью команд frame, up и down можно выбрать нужный кадр.
Когда программа останавливается, отладчик автоматически выбирает выполняемый в данный момент кадр и кратко описывает его, как это делает команда frame.
- frame
- Описать выбранный в данный момент кадр стека.
- frame frame-number
- Выбрать кадр стека по номеру и описать его. Кадр, выполнявшийся в момент остановки программы, имеет номер 0; кадр его вызывающей функции — номер 1 и так далее вверх по стеку вызовов.
- backtrace [count], bt [count]
- Вывести стек вызовов. Это полезно, чтобы увидеть последовательность вызовов функций, которая привела к текущему кадру. При положительном аргументе выводятся только count самых внутренних кадров. При отрицательном аргументе выводятся только -count самых внешних кадров.
- up [count]
- Выбрать и показать кадр стека, расположенный на один уровень «выше» выбранного, то есть кадр, вызвавший выбранный кадр. Аргумент задаёт, на сколько кадров подняться вверх.
- down [count]
- Выбрать и показать кадр стека, расположенный на один уровень «ниже» выбранного, то есть кадр, вызванный выбранным кадром. Аргумент задаёт, на сколько кадров опуститься вниз.
7 Просмотр значений переменных
Отладчик может выводить текущие значения простых выражений. В выражениях могут использоваться переменные программы: доступны все идентификаторы, находящиеся в области видимости в выбранной точке программы.
Допустимые для вывода выражения представляют собой подмножество выражений OCaml, описываемое следующей грамматикой:
|
Первые два случая относятся к идентификатору значения — неквалифицированному или квалифицированному путём к структуре, в которой он определён. * обозначает только что вычисленный результат (обычно значение применения функции) и допустим только в том случае, если выбрано событие «после» (обычно применение функции). $ integer обозначает ранее выведенное значение. Оставшиеся четыре формы выбирают часть выражения: соответственно, поле записи, элемент массива, элемент строки и текущее содержимое ссылки.
- print переменные
- Вывести значения указанных переменных. print можно сократить до p.
- display переменные
- То же, что и print, но глубина вывода ограничена значением 1. Полезно для просмотра больших структур данных без вывода их целиком. display можно сократить до d.
При выводе сложного выражения его значению автоматически присваивается имя вида $целое число. Такие имена также присваиваются частям значения, которые не удалось вывести из-за превышения максимальной глубины вывода. Именованные значения можно вывести позднее с помощью команд p $целое число или d $целое число. Именованные значения действительны только пока программа остановлена. Они забываются сразу после возобновления выполнения программы.
- set print_depth глубина
- Ограничить глубину вывода значений значением глубина.
- set print_length длина
- Ограничить вывод значений количеством не более длина выведенных узлов.
8 Управление отладчиком
8.1 Задание имени программы и аргументов
- set program файл
- Задать имя программы: файл.
- set arguments аргументы
- Задать аргументы командной строки для программы.
Для передачи аргументов отлаживаемой программе используется оболочка. Поэтому в аргументах можно использовать подстановочные знаки, переменные оболочки и перенаправление файлов. Для отладки программ, читающих данные из стандартного ввода, рекомендуется перенаправлять ввод из файла (с помощью set arguments < input-file); в противном случае ввод программы и ввод отладчика не будут должным образом разделены, а при обратном выполнении программы введённые данные не будут должным образом воспроизводиться.
8.2 Загрузка программ
Переменная loadingmode определяет способ выполнения программы.
- set loadingmode direct
- Программа выполняется непосредственно отладчиком. Это режим по умолчанию.
- set loadingmode runtime
- Отладчик запускает среду выполнения OCaml ocamlrun для выполнения программы. Этот режим редко бывает полезен; кроме того, он препятствует отладке программ, скомпилированных в режиме «пользовательской среды выполнения».
- set loadingmode manual
- Пользователь запускает программу вручную по запросу отладчика. Позволяет выполнять удалённую отладку (см. раздел 20.8.8).
8.3 Пути поиска файлов
Отладчик ищет исходные файлы и скомпилированные файлы интерфейсов в списке каталогов, называемом путём поиска. Изначально путь поиска содержит текущий каталог . и каталог стандартной библиотеки. Команда directory добавляет каталоги в путь.
При каждом изменении пути поиска отладчик очищает все сведения о файлах, которые могли быть сохранены в кэше.
- directory имена каталогов
- Добавить указанные каталоги в путь поиска. Эти каталоги добавляются в начало списка, поэтому поиск в них выполняется первым.
- directory имена каталогов for имя модуля
- То же, что и directory имена каталогов, но поиск в указанных каталогах выполняется только при поиске исходного файла модуля, упакованного в имя модуля.
- directory
- Сбросить путь поиска. Требуется подтверждение.
8.4 Рабочий каталог
При каждом запуске программы в отладчике она наследует свой рабочий каталог от текущего рабочего каталога отладчика. Изначально это каталог, унаследованный от родительского процесса (обычно оболочки), но в отладчике можно задать новый рабочий каталог с помощью команды cd или параметра командной строки -cd.
- cd каталог
- Задать рабочий каталог ocamldebug: каталог.
- pwd
- Вывести рабочий каталог ocamldebug.
8.5 Включение и отключение обратного выполнения
В некоторых случаях может потребоваться отключить обратное выполнение. Это ускоряет выполнение программы и иногда полезно для интерактивных программ.
Обычно отладчик время от времени создаёт контрольные точки состояния программы. То есть он копирует текущее состояние программы (с помощью системного вызова Unix fork). Если переменной checkpoints присвоено значение off, отладчик не будет создавать контрольные точки.
- set checkpoints on/off
- Указать, должен ли отладчик создавать контрольные точки.
8.6 Поведение отладчика при вызове fork
Когда программа вызывает fork, отладчик может следовать за дочерним или родительским процессом. По умолчанию отладчик следит за родительским процессом. Это поведение определяется переменной follow_fork_mode:
- set follow_fork_mode child/parent
- Указать, за каким процессом следить при вызове fork — дочерним или родительским.
8.7 Остановка выполнения при загрузке нового кода
Отладчик совместим с модулем Dynlink. Однако, пока внешний модуль не загружен, установить точку останова в его коде невозможно. Чтобы упростить установку точек останова в динамически загружаемом коде, отладчик останавливает программу при каждой загрузке новых модулей. Это поведение можно отключить с помощью переменной break_on_load:
- set break_on_load on/off
- Указать, следует ли останавливать выполнение после загрузки нового кода.
8.8 Взаимодействие отладчика с программой
Отладчик взаимодействует с отлаживаемой программой через сокет Unix. Может потребоваться изменить имя сокета, например, если отладчик запускается на одной машине, а программа — на другой.
- set socket сокет
- Использовать сокет для взаимодействия с программой. Значением сокет может быть имя файла или спецификация интернет-порта узел:порт, где узел — это имя узла или интернет-адрес в точечной нотации, а порт — номер порта на узле.
На стороне отлаживаемой программы имя сокета передаётся через переменную окружения CAML_DEBUG_SOCKET.
8.9 Тонкая настройка отладчика
Для тонкой настройки отладчика предусмотрено несколько переменных. По умолчанию используются подходящие значения, и обычно менять их не требуется.
- set processcount количество
- Задать максимальное количество контрольных точек: количество. Большее количество контрольных точек позволяет вернуться дальше назад во времени, но требует больше памяти и создаёт больше процессов Unix.
Поскольку создание контрольных точек требует значительных ресурсов, выполнять его слишком часто нельзя. С другой стороны, чем чаще создаются контрольные точки, тем быстрее работает обратное выполнение. В частности, обратное пошаговое выполнение становится отзывчивее, если непосредственно перед текущим моментом создано много контрольных точек. Для тонкой настройки стратегии создания контрольных точек отладчик задаёт разную частоту их создания для длинных (например, run) и коротких (например, step) перемещений. Переменные bigstep и smallstep задают количество событий между контрольными точками в каждом из этих случаев.
- set bigstep количество
- Задать количество событий между контрольными точками для длинных перемещений.
- set smallstep количество
- Задать количество событий между контрольными точками для коротких перемещений.
Следующие команды выводят сведения о контрольных точках и событиях:
- info checkpoints
- Вывести список контрольных точек.
- info events [модуль]
- Вывести список событий в указанном модуле (по умолчанию — в текущем).
8.10 Определяемые пользователем функции вывода
Как и в системе верхнего уровня (раздел 14.2), пользователь может зарегистрировать функции для вывода значений определённых типов. По техническим причинам отладчик не может вызывать функции вывода, находящиеся в отлаживаемой программе. Поэтому код функций вывода необходимо явно загрузить в отладчик.
- load_printer "имя файла"
- Загрузить в отладчик указанный объектный файл .cmo или .cma. Файл загружается в среду, содержащую только стандартную библиотеку OCaml и определения из объектных файлов, ранее загруженных с помощью load_printer. Если этот файл зависит от других ещё не загруженных объектных файлов, отладчик загружает их автоматически, если может найти их в пути поиска. Загруженный файл не имеет прямого доступа к модулям отлаживаемой программы.
- install_printer имя функции вывода
- Зарегистрировать функцию с именем имя функции вывода (путь к значению) как функцию вывода объектов, типы которых соответствуют типу аргумента этой функции. То есть отладчик вызывает имя функции вывода, когда ему нужно вывести такой объект. Функция вывода имя функции вывода должна использовать модуль библиотеки Format для формирования результата, иначе этот результат не будет правильно размещён среди значений, выводимых циклом верхнего уровня.
Путь к значению имя функции вывода должен указывать на одну из функций, определённых в объектных файлах, загруженных с помощью load_printer. Он не может указывать на функции отлаживаемой программы.
- remove_printer имя функции вывода
- Удалить указанную функцию из таблицы функций вывода значений.
9 Прочие команды
- list [модуль] [начало] [конец]
- Вывести исходный код модуля модуль со строки начало по строку конец. По умолчанию выводятся 20 строк текущего модуля, начиная за 10 строк до текущей позиции.
- source имя файла
- Прочитать команды отладчика из скрипта имя файла.
10 Запуск отладчика в Emacs
Самый удобный для пользователя способ работы с отладчиком — запуск в Emacs с режимом OCaml, доступным через MELPA, а также по адресу https://github.com/ocaml/caml-mode.
Отладчик OCaml запускается в Emacs командой M-x camldebug, аргументом которой служит имя исполняемого файла имя программы для отладки. Взаимодействие с отладчиком происходит в буфере Emacs с именем *camldebug-имя программы*. Для взаимодействия с отладчиком доступны средства редактирования и просмотра истории режима Shell.
Кроме того, Emacs показывает исходные файлы, содержащие текущее событие (текущую позицию выполнения программы), и выделяет место, соответствующее этому событию. Отображение обновляется синхронно с действиями отладчика.
В буфере *camldebug-имя программы* доступны следующие сочетания клавиш для наиболее распространённых команд отладчика:
- C-c C-s
- (команда step): выполнить один шаг программы вперёд.
- C-c C-k
- (команда backstep): выполнить один шаг программы назад.
- C-c C-n
- (команда next): выполнить один шаг программы вперёд, пропуская вызовы функций.
- Средняя кнопка мыши
- (команда display): вывести именованное значение $n под указателем мыши (поддерживается последовательный просмотр больших структур данных).
- C-c C-p
- (команда print): вывести значение идентификатора в точке курсора.
- C-c C-d
- (команда display): показать значение идентификатора в точке курсора.
- C-c C-r
- (команда run): выполнять программу вперёд до следующей точки останова.
- C-c C-v
- (команда reverse): выполнять программу назад до последней точки останова.
- C-c C-l
- (команда last): вернуться на шаг назад в истории команд.
- C-c C-t
- (команда backtrace): показать трассировку вызовов функций.
- C-c C-f
- (команда finish): выполнять программу вперёд, пока текущая функция не вернёт управление.
- C-c <
- (команда up): выбрать кадр стека, расположенный ниже текущего.
- C-c >
- (команда down): выбрать кадр стека, расположенный выше текущего.
Во всех буферах режима редактирования OCaml также доступны следующие команды отладчика:
- C-x C-a C-b
- (команда break): установить точку останова на событии, ближайшем к позиции курсора
- C-x C-a C-p
- (команда print): вывести значение идентификатора в точке курсора
- C-x C-a C-d
- (команда display): показать значение идентификатора в точке курсора
© 1995-2026 INRIA.
https://ocaml.org/manual/5.5/debugger.html