Программный останов что это
Большая Энциклопедия Нефти и Газа
Программный останов
Алгоритм и настройка программы: документы массива ВВИ64 сортируются по итоговым реквизитам в порядке их получения. Итоговая строка не выдается, если документ с данным итоговым шифром встречается один раз. При первом программном останове с пульта принимается дата. [21]
Векторы формируются как для обнаруженных, так и для необнаруженных неисправностей. В последнем случае элементы вектора, описывающие номер теста и проверки, отсутствуют. Эти векторы служат для оценки процента обнаруженных неисправностей как для всей ЭВМ, так и для ее блоков, что позволяет дополнять тесты с целью увеличения их обнаруживающей способности. По окончании имитации неисправностей УИ переводится в нейтральное положение и снова выполняется однократный прогон тестов микродиагностики. Если в последнем прогоне ошибок не обнаружено, что свидетельствует о нормальном окончании имитации, массив векторов сбрасывается на магнитную ленту ( МЛ) результатов имитации и ПМ выдает оператору указания об установке на УИ ТЭЗ со следующим конструктивным адресом. Для некоторых ТЭЗ, в частности ТЭЗ синхронизации, УИ вносит задержку, из-за которой тесты микродиагностики в нейтральном состоянии УИ не проходят. Для этих ТЭЗ внесение неисправностей выполняется вручную при той же программе путем установки перемычки от источника логических 0 или 1 на испытуемый контакт. С этой целью в ПМ предусмотрены программный останов перед имитацией и продолжение программы после установки перемычки. В остальном тестирование, накопление и обработка результатов ручного моделирования выполняются аналогично автоматическому моделированию. [26]
Программный останов что это
Основные цели использования отладчика состоят в том, чтобы вы могли остановить свою программу до того, как она завершится, или чтобы в том случае, если в вашей программе возникнут проблемы, вы могли выяснить их причины.
Точки останова можно устанавливать по позиции или по имени.
Точки останова устанавливаются в определенной позиции программы.
А есть еще более быстрый способ: для установки точки останова просто дважды щелкните слева от исходной строки.
(Если вас смущает такое количество разных способов, помните, что пользователи DDD делятся на три категории, и поддерживать нужно их всех. Новички изучают DDD и могут предпочитать использовать одну-единственную кнопку мыши. Продвинутые пользователи знают, как применять клавиатурные эквиваленты, и предпочитают всплывающие меню. Опытные пользователи предпочитают интерфейс командной строки.)
Есть еще более быстрый способ: щелкните на `Break. ‘ из редактора точек останова (который вызывается через `Source => Breakpoints’ ) и введите имя функции.
Есть еще более быстрый вариант: можно выделить точку останова и нажать на `Delete’ в редакторе точек останова (он вызывается через `Source => Breakpoints’ ).
Вместо того чтобы удалять точку останова или наблюдения вы можете предпочесть выключить ее. При этом точка останова не действует, как если бы ее удалили, но информация о ней запоминается, так что позднее вы сможете снова включить ее.(12)
Временная точка останова удаляется сразу, как только достигнута.(13)
Временные точки останова бывают удобны, когда нужно прогнать программу до какой-то позиции: просто установите в этом месте временную точку останова и продолжите выполнение.
`Continue Until Here’ из всплывающего меню устанавливает временную точку останова слева от исходной строки и сразу возобновляет выполнение. Программа останавливается, когда достигнута эта точка.
Условия останова могут обладать побочными эффектами и даже могут вызывать функции вашей программы. Это может быть полезно, к примеру, для запуска функций, которые ведут протокол работы программы, или для применения ваших собственных функций печати, которые форматируют какие-то особые структуры данных. Результаты полностью предсказуемы, если только по тому же адресу нет других включенных точек останова. (В такой ситуации DDD может сначала заметить другую точку останова и остановить программу, не проверяя условие.)
Обратите внимание на то, что для получения побочных эффектов команды точек останова обычно более удобны и гибки. См. раздел 5.1.8 Команды точек останова, для дополнительной информации.
Вы можете задать счетчик пропусков в поле `Ignore Count’ из панели свойств точки останова.(15)
Если у точки останова есть положительный счетчик пропусков и условие, то условие не проверяется. Как только счетчик пропусков достигает нуля, DDD начинает проверять условие.
Вы можете присвоить любой точке останова (или наблюдения) последовательность команд DDD, которые нужно выполнить, когда программа останавливается в этой точке. Например, вы можете захотеть напечатать значения некоторых выражений или включить другие точки останова.(16)
Вы можете отредактировать эти команды с помощью кнопок `Commands’ из панели свойств точки останова.
Чтобы переместить точку останова в другое место, нажмите на знаке «стоп» первую кнопку мыши и перенесите его в желаемую позицию.(17) Это эквивалентно удалению точки останова в старой позиции и установке ее в новой. Новая точка останова наследует все свойства старой, кроме номера.
Точки наблюдения имеют много общего с точками останова: в частности, вы можете включать и выключать их. Также, вы можете устанавливать условия, счетчики пропусков и команды, которые должны выполняться, когда наблюдаемое значение изменяется.
Пожалуйста, обратите внимание: на архитектурах без специальной поддержки точек наблюдения они замедляют программу на два порядка. Это происходит, потому что подчиненный отладчик должен прерывать программу после каждой машинной инструкции, чтобы проверить, не изменилась ли наблюдаемая величина. Однако, эта задержка может оправдать себя при поиске ошибок, если вы даже не представляете какую часть программы подозревать.
`Interrupt’ и ESC также прерывают запущенную команду отладчика, такую как печать данных.
По умолчанию после каждого события DDD проверяет, не захвачен ли указатель мыши. Если он захвачен, DDD продолжает программу, чтобы вы могли использовать X-дисплей.
Это работает так: когда программа останавливается, DDD проверяет, нет ли событий ввода, таких как ввод с клавиатуры или мыши. Если DDD не получает никаких событий в течение следующих пяти секунд, он проверяет, не захвачен ли указатель мыши, пробуя захватить и отдать его. Если эта попытка неудачна, DDD решает, что указатель захвачен.
Проверка захвата контролируется следующими ресурсами:
Ресурс: checkGrabs (класс CheckGrabs) Если это `on’ (по умолчанию), DDD проверят после каждого события, не захвачен ли указатель мыши. Если он захвачен, DDD автоматически продолжит выполнение отлаживаемой программы.
Урок №26. Отладка программ: степпинг и точки останова
Обновл. 21 Июл 2021 |
Как ни странно, программирование может быть сложным и ошибок может быть очень много. Ошибки, как правило, попадают в одну из двух категорий: синтаксические или семантические/смысловые.
Типы ошибок
Синтаксическая ошибка возникает, когда вы пишете код, который не соответствует правилам грамматики языка C++. Например, пропущенные точки с запятой, необъявленные переменные, непарные круглые или фигурные скобки и т.д. В следующей программе есть несколько синтаксических ошибок:
К счастью, компилятор ловит подобные ошибки и сообщает о них в виде предупреждений или ошибок.
Семантическая ошибка возникает, когда код является синтаксически правильным, но делает не то, что задумал программист.
Иногда это может привести к сбою в программе, например, если делить на ноль:
Иногда это может привести к неверным результатам:
Либо делать вообще не то, что нужно:
К сожалению, компилятор не ловит подобные ошибки, так как он проверяет только то, что вы написали, а не то, что вы хотели этим сделать.
В примерах, приведенных выше, ошибки довольно легко обнаружить. Но в большинстве программ (в которых больше 40 строк кода), семантические ошибки увидеть с помощью простого просмотра кода будет не так-то и легко.
И здесь нам на помощь приходит отладчик.
Отладчик
Отладчик (или «дебаггер», от англ. «debugger») — это компьютерная программа, которая позволяет программисту контролировать выполнение кода. Например, программист может использовать отладчик для выполнения программы пошагово, последовательно изучая значения переменных в программе.
Старые дебаггеры, такие как GDB, имели интерфейс командной строки, где программисту приходилось вводить специальные команды для старта работы. Современные дебаггеры имеют графический интерфейс, что значительно упрощает работу с ними. Сейчас почти все современные IDE имеют встроенные отладчики. То есть, вы можете использовать одну среду разработки как для написания кода, так и для его отладки (вместо постоянного переключения между разными программами).
Базовый функционал у всех отладчиков один и тот же. Отличаются они, как правило, тем, как этот функционал и доступ к нему организованы, горячими клавишами и дополнительными возможностями.
Примечание: Перед тем как продолжить, убедитесь, что вы находитесь в режиме конфигурации «Debug». Все скриншоты данного урока выполнены в Visual Studio 2019.
Степпинг
Степпинг (англ. «stepping») — это возможность отладчика выполнять код пошагово (строка за строкой). Есть три команды степпинга:
Команда «Шаг с заходом»
Команда «Шаг с обходом»
Команда «Шаг с выходом»
Мы сейчас рассмотрим каждую из этих команд в индивидуальном порядке.
Команда «Шаг с заходом»
Команда «Шаг с заходом» (англ. «Step into») выполняет следующую строку кода. Если этой строкой является вызов функции, то «Шаг с заходом» открывает функцию и выполнение переносится в начало этой функции.
Давайте рассмотрим очень простую программу:
Как вы уже знаете, при запуске программы выполнение начинается с вызова главной функции main(). Так как мы хотим выполнить отладку внутри функции main(), то давайте начнем с использования команды «Шаг с заходом».
В Visual Studio, перейдите в меню «Отладка» > «Шаг с заходом» (либо нажмите F11 ):
Если вы используете другую IDE, то найдите в меню команду «Step Into/Шаг с заходом» и выберите её.
Когда вы это сделаете, должны произойти две вещи. Во-первых, так как наше приложение является консольной программой, то должно открыться консольное окно. Оно будет пустым, так как мы еще ничего не выводили. Во-вторых, вы должны увидеть специальный маркер слева возле открывающей скобки функции main(). В Visual Studio этим маркером является жёлтая стрелочка (если вы используете другую IDE, то должно появиться что-нибудь похожее):
Стрелка-маркер указывает на следующую строку, которая будет выполняться. В этом случае отладчик говорит нам, что следующей строкой, которая будет выполняться, — будет открывающая фигурная скобка функции main(). Выберите «Шаг с заходом» еще раз — стрелка переместится на следующую строку:
Это значит, что следующей строкой, которая будет выполняться, — будет вызов функции printValue(). Выберите «Шаг с заходом» еще раз. Поскольку printValue() — это вызов функции, то мы переместимся в начало функции printValue():
Теперь выберите «Шаг с обходом» (F10). Вы увидите число 5 в консольном окне.
Выберите «Шаг с заходом» еще раз для выполнения закрывающей фигурной скобки printValue(). Функция printValue() завершит свое выполнение и стрелка переместиться в функцию main(). Обратите внимание, в main() стрелка снова будет указывать на вызов printValue():
Может показаться, будто отладчик намеревается еще раз повторить цикл с функцией printValue(), но в действительности он нам просто сообщает, что он только что вернулся из этой функции.
Выберите «Шаг с заходом» два раза. Готово, все строки кода выполнены. Некоторые дебаггеры автоматически прекращают сеанс отладки в этой точке. Но Visual Studio так не делает, так что если вы используете Visual Studio, то выберите «Отладка» > «Остановить отладку» (или Shift+F5 ):
Таким образом мы полностью остановили сеанс отладки нашей программы.
Команда «Шаг с обходом»
Как и команда «Шаг с заходом», команда «Шаг с обходом» (англ. «Step over») позволяет выполнить следующую строку кода. Только если этой строкой является вызов функции, то «Шаг с обходом» выполнит весь код функции в одно нажатие и возвратит нам контроль после того, как функция будет выполнена.
Примечание для пользователей Code::Blocks: Команда «Step over» называется «Next Line».
Рассмотрим пример, используя следующую программу:
Знакомство с WinDBG – Часть 2
В первой части мы получили базовое представление об отладчике WinDBG. Во второй части мы углубим свои знания, чтобы вы уже смогли начать отладку программ.
Автор: Брэд Антониевич (Brad Antoniewicz)
В первой части мы получили базовое представление об отладчике WinDBG. Во второй части мы углубим свои знания, чтобы вы уже смогли начать отладку программ.
Перечень всех статей, входящих в этот цикл:
Точки останова можно выставить как внутри приложения, так и внутри процессора (аппаратно). Рассмотрим оба этих способа:
Программные точки останова
Перед выполнением программа сначала загружается в память, что позволяет нам временно модифицировать участок памяти, связанный с программой, без влияния на процесс ее выполнения. Именно так и работают программные точки останова. Отладчик запоминает ассемблерную инструкцию, где должна быть вставлена точка останова, затем заменяет ее на ассемблерную инструкцию INT 3 (0xcc), которая заставляет процессор остановить выполнение программы. Как только точка останова достигнута, отладчик считывает текущий адрес памяти, достает ранее записанную инструкцию и показывает ее пользователю. Пользователю кажется, что программа остановился на этой инструкции, однако процессор не имеет ни малейшего представления о ее существовании.
В WinDBG программные точки останова устанавливаются при помощи команд bp, bm, или bu. Команда bp (Break Point), вероятно, наиболее часто используемая команда, при помощи которой устанавливаются точки останова. В самом простейшем случае достаточно указать один адрес, по которому должна быть установлена точка останова:
Адрес, передаваемый команде bp, должен быть участком памяти с исполняемым кодом. Поскольку команда bp работает с памятью, где хранятся данные, то в некоторых случаях могут возникнуть проблемы, так как отладчик перезаписывает информацию, которая находится в участке памяти. Во избежание проблем компания Microsoft рекомендует использовать команду ba (о ней мы поговорим дальше) в случае, если вы работаете с памятью, где хранятся данные.
Давайте рассмотрим, как устанавливать программные точки останова на примере приложения notepad.exe, которое мы будем запускать через WinDBG. По умолчанию, при запуске программы через WinDBG, отладчик устанавливает точку останова в самом начале программы. Для начала найдем адрес памяти, куда загрузился notepad.exe:
Рисунок 1: Нахождение адреса загрузки notepad.exe
Рисунок 2: Нахождение точки входа программы
Теперь устанавливаем точку останова в точку входа (адрес загрузки + 0x3689):
Рисунок 3: Установление точки останова
Наконец, после всех вышеперечисленных манипуляций, мы возобновляем запуск программы, используя команду g (подробнее о ней мы поговорим позже) до тех пор, пока поток выполнения не дойдет до точки останова. Как только это произойдет, на экране появится сообщение:
Рисунок 4: Сообщение, появляющееся по достижении точки останова
В большинстве случаев вы будете использовать программные точки останова, однако иногда вам понадобятся аппаратные точки останова (например, когда у памяти установлен атрибут «только чтение» или когда информация защищена и т. д.).
Аппаратные точки останова
Внутри большинства процессоров существуют специальные отладочные регистры, которые можно использовать для хранения адресов точек останова и специальных условий доступа, по которым срабатывают эти точки останова (например, на чтение, запись или выполнение). Точки останова, хранящиеся в таких регистрах, называются аппаратными (или процессорными) точками останова. Когда процессор доходит до адреса памяти, которые определен внутри отладочного регистра и выполняются условия доступа, программа останавливается.
В WinDBG аппаратные точки останова устанавливаются при помощи команды ba (Break on Access). Обычно в эту команду передается три аргумента:
0:001> ba e 1 00453689
При помощи этой команды, вероятно, можно было добиться того же самого, что и в примере с командой bp, но только не в случае с аппаратными точками останова (вскоре мы узнаем почему). Первый аргумент e – тип доступа к памяти (на выполнение), второй аргумент – размер (всегда 1 для этого типа доступа). Последний аргумент – адрес. Давайте рассмотрим установку аппаратной точки останова, учитывая то, что наши адреса загрузки различаются из-за ASLR.
Из-за способа, при помощи которого Windows сбрасывает контексты потока, и места, где появляется WinDBG после порождения процесса, мы не сможем установить точку останова тем же самым способом, как делали это в предыдущем примере. Ранее мы устанавливали точку останова во входной точке приложения, но если сделать так же и здесь, то возникнет ошибка:
0:000> lmf m notepad
start end module name
00e60000 00e90000 notepad notepad.exe
0:000> ba e 1 00e63689
^ Unable to set breakpoint error
The system resets thread contexts after the process
breakpoint so hardware breakpoints cannot be set.
Go to the executable’s entry point and set it then.
‘ba e 1 00e63689’
Для решения этой проблемы нам нужно использовать команду g, чтобы программа добралась до определенного адреса памяти. Когда мы устанавливали программную точку останова, то делали примерно то же самое, но не совсем. Таким образом, мы заставляем WinDBG дойти до начального контекста потока, что впоследствии позволит нам устанавливать аппаратные точки останова.
0:000> g 00e63689
ModLoad: 76be0000 76bff000 C:\Windows\system32\IMM32.DLL
ModLoad: 76c00000 76ccc000 C:\Windows\system32\MSCTF.dll
eax=77081162 ebx=7ffd7000 ecx=00000000 edx=00e63689 esi=00000000 edi=00000000
eip=00e63689 esp=0022fbb4 ebp=0022fbbc iopl=0 nv up ei pl zr na pe nc
cs=001b ss=0023 ds=0023 es=0023 fs=003b gs=0000 efl=00000246
notepad!WinMainCRTStartup:
00e63689 e8c5f9ffff call notepad!__security_init_cookie (00e63053)
Теперь мы можем установить аппаратную точку останова:
Рисунок 5: Установка корректной аппаратной точки останова
Чтобы убедиться в том, что точка останова хранится в регистре процессора, можно использовать команду r (подробнее о ней мы поговорим позже). Атрибут M нужен для использования маски регистра 0x20:
Рисунок 6: Просмотр отладочных регистров
Из Рисунка 6 видно, что что-то мы сделали не так, и во всех регистрах находятся нули! Такое произошло потому, что WinDBG еще ничего не занес ни в один из этих регистров. После того, как вы продвинетесь на один шаг вперед, используя команду p (подробнее об этом поговорим чуть позже), то в регистр dr0 установится адрес нашей точки останова:
Рисунок 7: При продвижении вперед на один шаг, в отладочный регистр устанавливается адрес аппаратной точки останова
В данном конкретном случае мы, вероятно, никогда не достигнем установленной точки останова, поскольку уже находимся в точке входа приложения. Однако если бы наша точка останова стояла на функции, которая вызывается несколько раз во время выполнения программы, или на участке памяти, где хранится часто используемая переменная, наша точка останова сработала бы, и мы получили бы соответствующее сообщение, как и в случае с программной точкой останова.
Команды для работы с точками останова
Теперь, когда вы познакомились с базовой информацией о точках останова, мы рассмотрим некоторые команды для работы с ними, которые могут быть полезны во время отладки.
Просмотр точек останова
Для просмотра всех точек установленных точек останова используется команда bl (Breakpoint List).
0:000> bl
0 e 00523689 e 1 0001 (0001) 0:**** notepad!WinMainCRTStartup
Результат выполнения команды разделен на несколько колонок. Рассмотрим назначение каждой из них:
Удаление точек останова
Чтобы удалить точку останова, используйте команду bc:
В команду передается только один параметр – идентификатор точки останова (можно узнать, выполнив команду bl). По желанию можно указать символ *, чтобы удалить все точки останова.
Некоторые трюки при работе с точками останова
Существует несколько трюков, которыми я обычно пользуюсь при работе с точками останова. Ниже приводятся некоторые из них. Если вы также пользуетесь какими-либо трюками, расскажите о них в комментариях!
Самый простейший трюк при работе с точками останова – вычисление адреса памяти. Вместо того чтобы производить эти вычисления в голове, вы можете сделать это прямо в WinDBG. К примеру, в вышеупомянутых примерах мы знаем адрес загрузки notepad.exe и смещение входной точки программы (0x3689). Теперь мы можем вычислить адрес для установки точки останова:
0:000> lmf m notepad
start end module name
00770000 007a0000 notepad notepad.exe
0:000> bp 00770000 + 3689
0:000> bl
0 e 00773689 0001 (0001) 0:**** notepad!WinMainCRTStartup
Использование имен и смещений в качестве адресов
Символы (о которых мы говорили в первой части) особенно хороши тем, что дают нам информацию о местонахождении известных функций. Таким образом, мы можем использовать смещения к этим функциям в качестве адресов в точках останова. Для того чтобы выяснить смещение, используйте команду u. Команда u возьмет информацию по указанному адресу и отобразит ее в виде ассемблерных инструкций. Кроме того, команда u выводит смещение до ближайшего символа:
0:000> u 00770000 + 3689
notepad!WinMainCRTStartup:
00773689 e8c5f9ffff call notepad!__security_init_cookie (00773053)
0077368e 6a58 push 58h
Теперь мы знаем, что имя notepad!WinMainCRTStartup более красивый аналог адресу 00770000 + 3689. Поскольку в конце этого имени не стоит числового смещения, мы можем сделать вывод, что для этой функции существуют символы. Давайте проверим инструкцию, которая следует сразу за первой функцией:
0:000> u 0077368e
notepad!_initterm_e+0x61:
0077368e 6a58 push 58h
В этот раз мы получили имя функции notepad!_initterm_e плюс смещение (+0x61). Я точно не знаю, почему WinDBG добавляет смещение к notepad!_initterm_e вместо notepad!WinMainCRTStartup. Вероятно, влияет порядок сортировки во время поиска символов. Тем не менее, мы можем добавить смещение к notepad!WinMainCRTStartup, чтобы сослаться на ту же самую область памяти:
0:000> u notepad!WinMainCRTStartup+0x5
notepad!_initterm_e+0x61:
0077368e 6a58 push 58h
Вся фишка в том, что мы можем использовать это смещение во время установки точки останова, и эти смещения всегда корректны, даже когда работает ASLR. То есть нам не нужно высчитывать адреса при каждом запуске.
0:000> bp notepad!WinMainCRTStartup+0x5
0:000> bl
0 e 0077368e 0001 (0001) 0:**** notepad!_initterm_e+0x61
Прерывание загрузки модуля
На практике может возникнуть необходимость в установке точки останова во время загрузки модуля. К сожалению, не существует очевидного решения этой задачи в рамках использования стандартных команд (если вам знаком такой способ, поделитесь им в комментариях). Зато есть немного замысловатый путь, когда мы добавляем подобную точку останова, путем установки исключения при помощи команды sxe, возникающего во время загрузки модуля:
0:000> sxe ld IMM32.DLL
Выполняя эту команду, мы установили first chance исключение (sxe) во время загрузки модуля (ld) и определили конкретный модуль (IMM32.DLL), в котором возникает это исключение.
Мы можем увидеть все установленные исключения, используя команду sx (Set Exceptions). Если посмотреть на список под именем Load Module, то можно увидеть прерывание на модуле IMM32.DLL.
Рисунок 8: Прерывание на модуле IMM32.DLL
Убрать исключение можно при помощи команды sxi (Set Exception Ignore):
0:000> sxi ld IMM32.DLL
Выполнение команд при срабатывании точки останова
Может возникнуть такая ситуация, что при срабатывании точки останова будет необходимо выполнить определенные команды. К примеру, нужно узнать, что находится в стеке. В WinDBG весь процесс можно автоматизировать при помощи выполнения цепочки команд, привязанных к точке останова. В нашем примере мы будем выводить на экран информацию из стека при помощи команды dd (более подробно поговорим о ней позже). Также обратите внимание, как отображается наша команда при просмотре перечня точек останова:
0:000> bp notepad!WinMainCRTStartup «.echo \»Here are the values on the stack:\n\»; dd esp;»
0:000> bl
0 e 00ae3689 0001 (0001) 0:**** notepad!WinMainCRTStartup «.echo \»Here are the values on the stack:\n\»; dd esp;»
Теперь давайте посмотрим, что произойдет при срабатывании точки останова:
Рисунок 9: При срабатывании точки останова отображается информация из стека
Как и ожидалось, выполнилась команда, и отобразилась информация из стека. Только не забывайте экранировать кавычки, находящиеся внутри внешних кавычек. Вы даже можете добавить в такую цепочку команду g, чтобы после выполнения команд программа продолжила свою работу. Это позволит вам анализировать состояние программы во время ее работы, вместо того, чтобы каждый раз прерываться.
Оставайтесь на связи
В следующей статье мы рассмотрим инспектирование памяти и пошаговую отладку программы! Не переключайтесь!