Разное

Книги по debug: 📕 25 лучших книг для программистов

Содержание

Работа с Debug — «Хакер»

Привет, юный хакер! Ты уже многое знаешь, но крутой хакер никогда не останавливается на достигнутом. Эта статья посвящена работе с стандартным дебаггером системы ДОС. Ты скажешь: «На кой фиг мне это надо мне, крутому перцу?». 
Представь ситуацию: ты приходишь в компьютерный клуб (интернет-кафе, к другу домой), а там на тачке дисководы сняты, сидюки заклеены, а пакость сделать все же хочется. Естественно, на любом «нормальном» компе нет никаких компиляторов С, ассемблеров… но почти на каждом «нормальном» компе есть ДОС! Да, именно ДОС, и его последователи — Винды всех типов а конкретнее программа
DEBUG.

Как? Набрать короткую (если времени мало, да и сил жалко), но неприятную программку, сохранить ее на диске и потом запустить, получив моральное удовлетворение. Посмотрим, как это делается, но для начала изучим несколько простых, но весьма полезных команд.

Итак, вы запустили программу DEBUG

Первая команда –D (dump) <adress>.

Эта команда позволяет просмотреть некоторую область памяти, адрес которой задан в параметре <adress> в формате сегмент:смещение.

Для начала посмотрим ПЗУ BIOS:

-d F000:E000

Здесь вы видите фирму-производителя вашей
BIOS. А по адресу:

-d F000:EC6C

получаем интересную информацию о системе,
такую как дата создания БИОС, чипсет… А по данному адресу
(0000:046C) находится таймер БИОС. Отчетливо видно, что значения все время меняются.
Для программиста удобно просматривать сегменты команд, данных и стека (CS, DS и SS, соответственно).

-d DS:0000

Выше мы видим содержимое сегмента данных, т. е.
значения определенных переменных.

-d CS:100

А тут представлено содержимое сегмента команд, т.е. машинные коды команд, готовых к исполнению.
Освоив команды просмотра памяти, впоследствии мы сможем эффективно отлаживать наши программы и просматривать введенный нами код перед исполнением (для нас сейчас это приоритетная задача).

Еще одна важная команда -R (register) <register name>, позволяющая просматривать состояние конкретного регистра и изменять его состояние или же сразу перейти к первой выполняемой команде с просмотром всех регистров.

-r AX

AX 1203
: 0

В данном фрагменте мы просматриваем регистр АХ и очищаем его (пишем в него 0).
Чтобы перейти к первой выполняемой команде (по адресу CS:100):

-r

AX=0000 BX=0000 CX=0000 DX=0000 SP=FFEE BP=0000
SI=0000 DI=0000 
DS=3B9A ES=3B9A SS=3B9A CS=3B9A IP=0100 NV UP EI PL NZ NA PO NC 
3B9A:0100 E82421 CALL 2227

Третья команда –E (enter) Addres <command list>.

Предназначена она для изменения значений в
памяти – с помощью нее можно уже вводить команды в машинных кодах. Замечание: при вводе данных сначала пишется младший байт
(по младшему адресу), затем – старший (по старшему), т. е. 
чтобы записать по адресу DS:0000 число 1234h необходимо ввести:

-E DS:0000 34 12

Например введем следующее:

-E cs:100 B8 34 12
-D CS:100

А с помощью команды U (unassemble) <starting address>, <ending adress> дизассемблируем введенные команды и получим:
-U CS:100,102
3B9A:0100 B83412 MOV AX,1234

Таким же образом можно дизассемблировать любой участок памяти, что очень полезно.
Но вместо ввода команд на машинном языке, можно воспользоваться встроенным
ассемблером программы DEBUG. Для этого существует команда
-A (assemble) <adress>. С помощью этой команды вы можете написать уже нормальную программку на ассемблере, выполняющую необходимые действия.:

-A 
0B3B:0100 mov ax,1234
0B3B:0103 mov ah, 4c
0B3B:0105 int 21
0B3B:0107

А как же теперь сохранить программу на диске? Сначала задается имя файла:

-N my_file.com

Затем в регистр СХ необходимо поместить размер программы в байтах. Он будет равен разности конечного и начального смещений. Теперь остается только осуществить запись на диск командой W и в результате увидеть записанное количество байтов. В итоге мы получаем программу, готовую к исполнению. Выход осуществляется командой q. Пример:

-A 
0B3B:0100 mov ax,1234
0B3B:0103 mov ah, 4c
0B3B:0105 int 21
0B3B:0107 
-u CS:100, 106
0B3B:0100 B83412 MOV AX,1234 
0B3B:0103 B44C MOV AH,4C 
0B3B:0105 CD21 INT 21 
-r cx
CX 0000
:7
-r
AX=0000 BX=0000 CX=0007 DX=0000 SP=FFEE BP=0000 SI=0000 DI=0000 
DS=0B3B ES=0B3B SS=0B3B CS=0B3B IP=0100 NV UP EI PL NZ NA PO NC 
0B3B:0100 B83412 MOV AX,1234 
-N my.com
-W
Запись 00007 байт
-q

В заключение можно сказать, что данный способ создания программ открывает новые возможности для любителей компьютерных пакостей, приколов, да и просто программистов-любителей – ведь теперь для создания небольших программ, вместо установки компиляторов, можно воспользоваться стандартными средствами системы, а DEBUG входит в поставку во все Винды вплоть до ХР. Я думаю, что это поможет вам веселее провести время за чужим компом, вызывая истинное удивление хозяина (дисков и дискет-то вы не приносили!!!) новыми эффектами работы его оборудования. Успехов, юные любители хакерного экстрима!

Программа Debug


Главная /
Ассемблер /
Для чайников /
Быстрый старт /


ПРИМЕЧАНИЕ

Рисунки на этой странице не отображаются, но вы можете найти их в книге.


Как уже говорилось (см. ВВЕДЕНИЕ),
программа Debug входит в состав Windows. Запустить программу Debug
можно из командной строки или непосредственно из папки, в которой она находится. Чтобы
запустить программу из командной строки, выберите команду из меню ПУСК – ВЫПОЛНИТЬ или
нажмите комбинацию клавиш WIN + R (если вы не знаете, что такое комбинация клавиш, см.
книгу Компьютер для чайников).
В открывшемся окне (рис. 1.5) напечатайте слово debug и нажмите клавишу ENTER или щёлкните кнопку ОК.


После этого откроется окно с пустым экраном и чёрточкой в левом верхнем углу,
которая приглашает вас ввести какую-либо команду. Например, чтобы выйти из программы Debug,
напечатайте букву q и нажмите ENTER.


Написать программу, используя Debug, можно не единственным способом, но мы пока
рассмотрим тот, который больше похож на написание программы для
Emu8086.


Чтобы написать уже известную нам программу, используя Debug, сделаем следующее
(подразумевается, что Debug вы уже запустили, и увидели черный экран с маленькой мигающей
черточкой в левом верхнем углу).


Введем букву «а» (напоминаю в последний раз — все команды вводятся на
английском языке) и нажмем ENTER.


Затем введем программу, нажимая ENTER в конце каждой строки:

 
0B72: 0100 MOV AH, 02
0B72: 0102 MOV DL, 41
0B72: 0104 INT 21
0B72: 0106 INT 20
0B72: 0108

Результат будет примерно таким, как показано на рис. 1.6.


ПРИМЕЧАНИЕ 1

Обратите внимание, что все числовые значения пишутся без буковки h в конце. Это потому,
что Debug работает только с шестнадцатеричными числами, и ему не надо объяснять,
в какой системе исчисления вводятся данные.

ПРИМЕЧАНИЕ 2

После ввода команды -а, появляются символы: 0B72: 0100. В вашем случае первые четыре
символа могут быть другими, но нас они пока не интересуют. А как вы думаете, что означает
число 0100? Помните директиву ORG 100h (см. раздел
Emu8086)?
Вот-вот – это адрес, с которого начинается выполнение программы. То есть в память с
этим адресом заносится первая команда программы (для файлов СОМ). Каждая команда занимает
2 байта, поэтому следующий адрес будет 0102 и т.д.


Сами команды мы уже знаем (см. раздел
Emu8086),
поэтому описывать их здесь не будем.


Программа написана – нужно проверить ее работу. Нажмём ENTER ещё раз, чтобы на экране
появилась чёрточка, которая говорит о том, что можно вводить команду для Debug. Затем
введем команду g (от английского «GO») и нажмем клавишу ENTER. На экране увидим следующее:


-g
A
Программа завершилась нормально
-

Здесь A – та самая буква, которая выводится на экран в результате работы программы.
Затем идёт сообщение о нормальном завершении программы (оно может отличаться в зависимости
от версии Debug).


А теперь, если интересно, можно проверить программу в пошаговом режиме, то есть
понаблюдать, как выполняются команды одна за другой. Для этого придется по новой
набрать текст программы (не забудьте сначала ввести команду а), затем:


Введем команду t и нажмем клавишу ENTER. Увидим нечто вроде этого:


AX=0200  BX=0000  CX=0000  DX=0000  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B72  ES=0B72  SS=0B72  CS=0B72  IP=0102  NV UP EI PL NZ NA PO NC
0B72:0102 B241		MOV	DL,41

Это есть ни что иное, как состояние регистров процессора после выполнения первой
строки программы. Как вы можете видеть, в регистр АН записалось число 02. В нижней
строке находится адрес команды и сама команда, которая будет выполняться следующей.


Снова введем команду t и нажмем клавишу ENTER. Увидим следующее:


AX=0200  BX=0000  CX=0000  DX=0041  SP=FFEE  BP=0000  SI=0000  DI=0000
DS=0B72  ES=0B72  SS=0B72  CS=0B72  IP=0104  NV UP EI PL NZ NA PO NC
0B72:0104 CD21		INT	21

Команда MOV DL, 41, как ей и полагается, записала в регистр DL число 41.


Снова введем команду t и нажмем клавишу ENTER. Увидим следующее:


AX=0200  BX=0000  CX=0000  DX=0041  SP=FFE8  BP=0000  SI=0000  DI=0000
DS=0B72  ES=0B72  SS=0B72  CS=0347  IP=0225  NV UP EI PL NZ NA PO NC
0347:0225 80FC4B	CMP	AH,4B

Команды CMP AH,4B нет в нашей программе. Наша программа завершила свою работу.
Мы можем долго еще вводить команду t – нам будут выдаваться состояния регистров.
Почему это происходит, нам пока не интересно. Лучше введем команду g и нажмем клавишу ENTER,
таким образом окончательно выполним нашу программу, и увидим то, что мы уже видели.


Программа написана и проверена. Но как сделать ее самостоятельной, то есть как создать
файл СОМ? Ведь то, что мы сделали, работает только с помощью Debug. Чтобы создать
исполняемый файл, нужно ответить на несколько вопросов:

  1. Какого размера будет наш файл? Выполнение программы начинается с адреса 0100h,
    а последняя строка в программе содержит адрес 0108h. Это значит, что размер файла
    будет 8 байт (108h – 100h = 8).
  2. Как мы назовем наш файл? А хоть как. Однако, рекомендуется давать файлам английские
    имена, в которых содержится не более 8 символов (DOSу так приятнее работать). Назовем,
    например, debug_1.com

А теперь выполним следующие действия:

  1. Снова напишем нашу программу (тренируйтесь, тренируйтесь…).
  2. Запишем в регистр СХ размер файла. Для этого введем команду r cx и нажмем ENTER. Затем введем размер файла (8 байт) и нажмем ENTER.
  3. Введем команду n, затем один пробел и имя файла. Нажмем ENTER.
  4. И, наконец, введем команду w и нажмем ENTER.

В результате всех этих действий на экране появится следующая информация (см. также рис. 1.7):


-r cx
СХ 0000
:8
-n debug_1.com
-w
Запись: 00008 байт
-

Если вы работаете в режиме эмуляции DOS из под WINDOWS, то файл debug_1.com
сохранится на рабочий стол, либо в папку текущего пользователя. Это зависит от
версии и/или настроек WINDOWS. Теперь его можно запустить как обычную программу.
Если в указанных папках вы не нашли этот файл, то найдите его через поиск файлов.
Ну а если вы не знаете, как это сделать, см. книгу Компьютер для чайников.


Чувствую, что мы уже устали. Выход из Debug осуществляется командой q.


Набравшись сил и терпения, изучим еще одну опцию Debug – дизассемблер. С его помощью
можно дизассемблировать какой-нибудь СОМ-файл (то есть выполнить действие, обратное
ассемблированию – преобразовать исполняемый файл в исходный код на языке ассемблера).
Допустим, у вас есть программка, написанная не вами – ее исходный код вы не знаете,
а посмотреть очень хочется. Для этого и существует дизассемблер.


Итак, программа Debug у нас закрыта. Набираем в командной строке:


debug debug_1.com

(где debug_1.com – это имя файла, который мы хотим дизассемблировать) и нажимаем ENTER.


ПРИМЕЧАНИЕ

Если программа не запустилась, значит нужно указать полный путь к ней, например


C:\WINDOWS\COMMAND\debug debug_1.com

Если же программа запустилась, но выдала ошибку (например: Ошибка 1282 или «Файл не найден»),
то нужно указать полный путь к файлу, например:


C:\WINDOWS\COMMAND\debug C:\MYPROG\debug_1.com

Если и это не помогло, то, возможно, вы всё-таки где-то допустили ошибку в пути или
путь не соответствует требованиям DOS. В таком случае лучше поместить программу в
корень диска С, откуда она гарантированно загрузится по пути «C:\debug_1.com».


Если Debug запустилась без сообщений об ошибках, то вводим команду u и нажимаем ENTER.
Вот что мы увидим (примерно, см. также рис 1.8):


-u
0BC6:0100 B402		MOV	AH, 02
0BC6:0102 B241		MOV	DL, 41
0BC6:0104 CD21		INT	21
0BC6:0106 CD20		INT	20
0BC6:0108 56		PUSH	SI
0BC6:0109 2E		CS:
0BC6:010A 8A04		MOV	AL, [SI]
0BC6:010C 0AC0		OR	AL, AL
0BC6:010E 741A		JZ	012A
0BC6:0110 3C3A		CMP	AL, 3A
0BC6:0112 750D		JNZ	0121
0BC6:0114 2E		CS:	
0BC6:0115 807C0100	CMP	BYTE PTR [SI+01], 00
0BC6:0119 7506		JNZ	0121
0BC6:011B 2E		CS:
0BC6:011C C60400	MOV 	BYTE PTR [SI], 00
0BC6:011F EB09		JMP 	012A
-

Посмотрите на первые четыре строки. Узнаете? Это наша программа. Остальные строки
нас не интересуют (это инструкции, оставшиеся от программ или данных, отработавших
до запуска Debug). Ну а если мы рассматриваем незнакомый файл, как узнать, где
кончается программа и начинается «мусор»? Ориентировочно это можно сделать по размеру
файла (для очень маленьких программ). Размер можно посмотреть в свойствах файла.
Только следует учитывать, что в свойствах файла размер дан в десятичной форме, а
Debug нам выдает шестнадцатеричные адреса. Поэтому придется перевести десятичное число
в шестнадцатеричное.


Есть еще вариант (который тоже не всегда приемлем) – найти в полученном списке строку,
содержащую команду выхода из программы (INT 20).


Если программа большая, то список ее команд не поместится на экран. Тогда снова вводим
команду u и нажимаем ENTER. И так до конца программы.


Возможно, вы не увидите на экране свою программу. Это может быть либо из-за того,
что программа почему-то не загрузилась, либо по причине несоответствия адресов.
Будьте внимательны: обращайте внимание на адреса памяти, которые указаны в левой колонке.
Наша программа начинается с адреса 0100. Если адрес другой, то это, соответственно,
не наша программа.

Debug — это… Что такое Debug?

Debug — Программа-отладчик, которую используют для проверки и отладки выполняемых файлов. Использовалась при операционной системе MS-DOS. Под более поздние версии операционных систем работает через эмулятор MS-DOS и имеет ограниченные возможности.

Назначение

Данная программа является консольным приложением и предназначена для создания или изменения кода файлов. С помощью неё можно создавать простые приложение под MS-DOS и отслеживать их работу. Данный отладчик находится на самом низком уровне компиляторов assembler. Но обладает неплохими возможностями такими как просмотр, изменение памяти и получение состояния регистров.

Команды

Запуск отладчика

Программа вызывается через командную строку:

DEBUG

DEBUG [[диск:][путь]имя_файла [параметры]]

DEBUG C:\мойпуть\My.com

Работа с файлами

Команда Описание Пример
-N -N Путь_Имя_Файла. С помощью этой команды можно загружать и сохранять файлы. Сокращённо от слова Name. -N My.com [Нажать Enter]
-L Загрузка файла. Сокращённо от слова Load. -N My.com [Нажать Enter]
-L [Нажать Enter]
-W -W Путь_Имя_Файла. Сохранить файл. Сокращённо от слова Write. -N My.com [Нажать Enter]
-W [Нажать Enter]

 Writing Число_Байт bytes

Отображение и изменение значений регистров

Команда Описание Пример
-R Выдаёт содержание всех регистров. -R [Нажать Enter]

  AX=D3E0 BX=0000 CX=0000 DX=0000 SP=FFFE BP=0000 SI=0000 DI=0000  
DS=16BB ES=16BB SS=16BB CS=16BB IP=0100 NV UP DI PL NZ NA PO NC
15A3:0100 30C0 XOR AL,AL
-R [регистр] Просмотр регистра и запись нового значения в регистр. -R AX [Нажать Enter]

 AX 0000  
666 [Нажать Enter]

Дамп памяти

Команда Описание Пример
-D Выдаёт содержимое памяти. Сокращённо от слова Dump. -D [Нажать Enter]
-D [Начало_Сегмента] L [Конец_Сегмента] Выдаёт содержимое памяти от начального сегмента до конечного сегмента.
Чтобы вывести всё память нужно ввести -D 0 L 0 [Нажать Enter]
-D 0000 L 0005 [Нажать Enter]

 1814:0000 CD 20 FF 9F 00

Дизассемблирование

Команда Описание Пример
-U Команда преобразования кода в инструкции ассемблера. Сокращённо от слова Unassemble. -U [Нажать Enter]

 1814:0100 ADD [BX+SI],AL 
1814:0102 XOR AL,00

Ассемблирование

Команда Описание Пример
-A Преобразования инструкции ассемблера в машинный код. Сокращённо от слова Assemble. -A [Нажать Enter]
1814:0100 MOV AX,0009
1814:0103 [Вводим_Дальше] [Нажать Enter]

Компиляция

Команда Описание Пример
-G Запуск исполнения программы. Сокращённо от слова Go. -G [Нажать Enter]

 Program terminated normally
-G =[Адрес_Начала_Работы] Начиная с этого адреса начинается компиляция. -G =100
-G [Адрес_Брейкпоинта] [Адрес_Брейкпоинта] … Программа запускается и выполняется пока не дойдёт до брейкпоинта
после чего она остановится и выведет значения регистров да продолжения
работы необходимо нажать -G. Максимальное число брейкпоинтов 10.
-G 176 47d 537 647 [Нажать Enter]

Трассировка

Команда Описание Пример
-T Команда имеет сходство с командой (-G) Go, но отличается тем что
выводит значения регистров поле каждой инструкции. Сокращённо от слова Trace.
-T [Нажать Enter]
-T =[Адрес_Начала_Работы] [Количество_Иструкций] Дополнительно указывает с какого адреса запускаться программе
и количество исполняемых инструкций.
-T =100 5[Нажать Enter]

См. также

Примечания

Ссылки

  Общие команды MS-DOS и Windows
Append • Attrib • Break • Call • Cd • Chcp • Chdir • Chkdsk • Cls • Command • Copy • Date • Debug • Defrag • Del • Dir • Diskcomp • Diskcopy • Doskey • Echo • Edit • Edlin • Erase • Exit • Expand • Fastopen • Fc • Find • For • Format • Goto • Graphics • Help • If • Label • Loadfix • Md • Mem • Mkdir • Mode • More • Move • Nlsfunc • Path • Pause • Print • Prompt • Rd • Rem • Ren • Rename • Replace • Rmdir • Set • Setver • Share • Shift • Sort • Subst • Time • Tree • Type • Ver • Verify • Vol • Xcopy
См. также

Debugging tools for Windows / Хабр

Раньше я не знал, что такое сабж и не умел его использовать. Теперь немного узнал и впечатлён. Расскажу про свой опыт общения с ним, может кому-то будет полезно.


Эти тулзы содержат мощные отладчики (WinDbg, Cdb) и позволяют делать всякие полезности, типа создания symservers (symstore.exe), создания дампа с процесса (cdb, windbg), отладки мемори ликов (umdh.exe) и других ошибок работы с памятью (gflags — позволяет включать многие «скрытые» системные проверки как для конкретного exe файла, так и для всей системы в целом). Также в комплекте есть много других полезных тулзов, типа просмотрщика debug output.

Взять можно тут:  Майкросайт

Например, как получить мемори лики для любой программы:

Нам понадобится umdh.exe, tlist.exe и gflags.exe. Все их надо запускать с админскими правами.

Запускаем gflags.exe, выставляем галочку Create user mode stack database. Перезагружаемся — теперь для всех запущенных программ будет создаваться этот database. Можно для каждого приложения отдельно настроить.

Далее запускаем нужную программу, ждем, пока все загрузится и получаем PID программы с помощью tlist.exe (или как угодно еще). Например, PID == 111.

Далее запускаем umdh.exe -p:111 -f:c:\temp\log1.log

Эта строка сохранит в файл log1.log инфу о всех текущих выделениях памяти в процессе 111.

Далее работаем в программе, ждем сколько-нибудь времени и снова пишем:

umdh.exe -p:111 -f:c:\temp\log2.log

Получаем второй лог с выделениями памяти.

Теперь их можно сравнить и получить лики:

umdh.exe -d -v -l c:\temp\log1.log c:\temp\log2.log 1> c:\temp\log_result.log

Теперь у нас в log_result.log будут все выделенные и не освобожденные куски памяти с калстэками!

Чтобы калстэки были правильные, нужно настроить enviroment variable _NT_SYMBOL_PATH. В хелпе написано, как его настроить для майкрософтовских exe и dll.

Свои pdb лучше всего сохранять на symbol server, который можно пополнять после билдов с помощью symstore.exe — тогда всегда отладчик будет иметь правильный pdb.

Если сервера нет, можно просто положить pdb рядом с ехе — должен подцепиться. Если не подцепится, то добавить путь к pdb в _NT_SYMBOL_PATH.

Если у вас есть дамп файл и надо его проверить, то опять же проще всего использовать WinDbg. Он использует ту же переменную _NT_SYMBOL_PATH и, в отличие от VisualStudio, он не требует ни исходников ни правильных бинарников для отладки. Просто дамп и подходящий pdb! Запускаешь WinDbg.exe, File\open crash dump…, открываешь дамп, пишешь !analyze -v, потом !uniqstack и уже обычно этого достаточно в простых случаях. Видишь, какие pdb нашлись, какие нет и получаешь анализ дампа. Можно открыть окошки с callstack, Processes and threads и отлаживаться. Если надо увидеть код — File\Source File Path… — указать путь к исходникам и можно смотреть место в коде, где что произошло (лучше сразу эти пути прописать в enviroment variable _NT_SOURCE_PATH, чтобы не вбивать их каждый раз). Короче, опять все просто и удобно, если есть правильный pdb 🙂

Проблемы с зависаниями чего-либо отлично решаются с помощью создания дампа зависшего процесса. Для этого можно использовать тот же WinDbg или специальные проги или стандартную системную фичу в висте в таск менеджере — создать дамп:)

Причем DebuggingTools можно установить уже после зависания — никакой перезагрузки не надо. Установил — снял дамп. Для снятия дампа юзеру не надо никаких pdb.

Потом этот дамп анализируешь и исправляешь (в Windbg есть специальные команды для поиска дедлоков и т.п. — команда !locks и другие).

Вывод:

Чтобы не иметь проблем с отладкой, надо озаботиться системой хранения pdb файлов для КАЖДОГО билда ну или хотя бы для официальных билдов. А также изучить Debugging tools и написать простые рекоммендации тестерам и программистам — что делать в случае ошибки или зависания, как создавать дамп, куда его класть и с какими коментариями. А некоторые тестеры даже могут запускать WinDBG и копипастить в отчет о баге оттуда нужные данные типа калстэка с ошибкой — очень помогает в предварительном анализе.

В дополнение пара полезных ссылок для начинающих про WinDBG:
WinDbg. From A to Z!
Common WinDbg Commands (Thematically Grouped)

Профилирование и отладка Python, отладка / Блог компании Mail.ru Group / Хабр

В предыдущей статье мы закончили разговор о профилировании обзором событийных профайлеров.

Сегодня я предлагаю рассмотреть методы отладки программ.

Прежде, чем начинать разговор об отладке, нам нужно определиться, что же это такое. По традиции, обратимся к Википедии: «Отладка — обнаружение, локализация и устранение ошибок». Вообще, для успешной отладки программы, нам необходимо (но не всегда достаточно) две вещи: значение переменных в том месте программы, в котором произошла ошибка, а так же стектрейс: порядок вызова функций, вплоть до ошибочной. Полезно так же знать об окружении, в котором выполняется программа: наличие (или отсутствие) свободной памяти, системные ограничения (например, на количество файловых дескрипторов) и так далее, но это слегка выходит за пределы нашей статьи.

Классика жанра

Что делает начинающий программист, когда хочет «проникнуть» внутрь программы и изучить содержимое переменных (в нужных местах) и логику работы программы (вызовы функций, выполнение условий)? Он прибегает к самому распространённому, самому простому и самому «действенному» способу отладки: расставляет по всему коду «принты» (оператор print в Python 2.x и функция print() в Python 3.x). Но не только начинающие грешат этим: продвинутые разработчики частенько ленятся использовать специальные инструменты для отладки, надеясь быстренько, за пару минут, найти причину ошибки и всё исправить, и не замечая, что поиски ошибок растягиваются на часы и даже дни. Кстати, такой подход называют «журналированием».

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

Но мы же пишем на Python, так почему бы не воспользоваться встроенными средствами отладки или инструментами, предлагаемыми сообществом? Например, вместо обычного логгирования в файл имеет смысл использовать Sentry, чтобы кроме сообщения об ошибке можно было отправить дополнительную информацию: стектрейс со всеми локальными переменными, любые другие переменные и вообще всё, что посчитаете нужным.

The Python Debugger

Python имеет встроенный отладчик: модуль pdb. В принципе, на этом можно было бы закончить статью, т.к. pdb — чрезвычайно мощный отладчик и всё остальное, по сути, всего лишь «украшательства» к нему. Но мы продолжим =)

Как можно заметить из названия, pdb многое взял от gdb (GNU Project debugger) — отладчика Си (и не только) программ. К слову, программы на Python можно отлаживать и с помощью gdb, просто это немножко сложнее и дольше, хотя тем, кто хочет углубиться в устройство языка, а так же тем, кто пишет сишные модули для питона без gdb никак не обойтись. Кроме того, gdb позволяет подключиться к уже работающей программе (через её pid) и заниматься её отладкой «прямо на месте».

Я сейчас не буду подробно описывать pdb, вот замечательная статья Дага Хеллманна (Doug Hellmann): pdb – Interactive Debugger на очень полезном ресурсе Python Module of the Week, а вот её хороший перевод на хабре: pdb – Интерактивный отладчик, выполненный пользователем xa4a.

IPython pdb

Предлагаю сразу поставить IPython и модуль ipdb для него:

➜ pip install ipython ipdb

IPython (и ipdb, как его часть) предлагает «более лучшую» консоль и, как следствие, более удобную отладку программ: подсветка кода, автодополнение, историю команд, динамическую интроспекцию любых объектов, магические функции, алиасы и многое другое. Полный список улучшений можно посмотреть в документации или прямо из консоли IPython, введя «?» в качестве команды. Всё это помогает при отладке и делает её простой и увлекательной.

Запустить отладку скрипта в ipdb можно несколькими способами:

➜ python -m ipdb script.py
➜ ipdb script.py

Эти команды откроют программу в отладчике, дальше можно делать всё, что угодно: ставить брейкпоинты, изучать её работу по шагам или просто запустить программу — отладчик автоматически остановится при возникновении неотловленного исключения.

Но обычно такой вариант чересчур изнурителен: пока доберёшься до нужного места всеми этими «next», «step», да и ставить точку останова («break») руками каждый раз утомительно. Гораздо удобнее в нужном месте программы вставить следующую строку:

import ipdb; ipdb.set_trace()

И тогда при исполнении этой строки выполнение программы приостановится и будет запущен отладчик, — дальше можно начинать углубляться в изучение программы. По сути, функция «set_trace» — это установка точки останова (breakpoint).
Примечание для эстетов

Любой, кому знакома аббревиатура PEP8, в этом месте может обвинить меня в использовании двух команд в одной строке через точку с запятой, однако такой подход вполне имеет право на жизнь. Во-первых, это временный код, который никогда не будет закоммичен в репозиторий (об этом позаботится специальный хук, который проверяет код на соответствие PEP8 перед коммитом и пушем, а так же автопроверка кода в текстовом редакторе). Во-вторых, так проще вставлять и удалять эту строку в код. Ну и в-третьих, как написано в PEP8: «A Foolish Consistency is the Hobgoblin of Little Minds».

Python Debugger имеет ещё один режим работы, который в некоторых случаях оказывается удобнее фукнции set_trace. Он называется «post mortem»: запуск отладчика с заданным трейсбеком:

try:
    some_code()
except:
    import sys
    import ipdb
    tb = sys.exc_info()[2]
    ipdb.post_mortem(tb)

или так:

import sys
import ipdb


def run_debugger(type, value, tb):
    ipdb.pm()


sys.excepthook = run_debugger
some_code()

В случае возникновения любых неотлавливаемых исключений в функции «some_code» будет вызван отладчик в том месте программы, где произошло исключение.

debug

Интересной заменой функции «set_trace» является модуль debug, который просто импортирует библиотеки ipdb и see (удобная альтернатива функции dir) и запускает отладку. Единственным плюсом модуля является удобство использования, достаточно в любом месте программы вставить строку:

import debug

И при выполнении этой строки будет вызван отладчик «ipdb» и импортирован модуль «see».

ipdbplugin

Ещё одна интересная и, на этот раз, полезная библиотека: nose-ipdb. С её помощью можно автоматически запускать отладчик при ошибках (исключениях) или же просто при неверно отработанных тестах (я надеюсь, вы используете nose? =). Для запуска отладчика ipdb при ошибках, достаточно при запуске тестов добавить ключ «—ipdb»:

➜ nosetests --ipdb

А для запуска отладчика при некорректно завершившихся тестов нужно добавить ключ «—ipdb-failures»:

➜ nosetests --ipdb-failures

Конечно, можно ловить всё и сразу:

➜ nosetests --ipdb --ipdb-failures

Я каждый день использую этот модуль и просто не представляю себе жизни без него.

werkzeug

Потрясающий проект Армина Ронахера (Armin Ronacher), автора фреймворка Flask и вообще одного из крутейших программистов Python называется werkzeug и представляет собой сборник различных утилит для WSGI приложений. Одна из них — клёвый отладчик, который позволяет выводить удобный трейсбек ошибки, а так же запускать консоль Python в соответствующем месте трейсбека прямо на странице браузера:

Использовать его очень просто, достаточно обернуть приложение с помощью соответствующего middleware:

from werkzeug.debug import DebuggedApplication
from myapp import app
app = DebuggedApplication(app, evalex=True)

Говорят, что werkzeug умеет отлаживать даже Ajax-запросы, но, к сожалению, я сам лично никогда этого не делал. Буду рад любым комментариям на эту тему.

django-pdb

Ещё один хороший модуль, на этот раз для Django: django-pdb. Он позволяет запускать отладчик при наличии соответствующего GET-параметра в запросе (например: http://127.0.0.1:8000/app/view?ipdb) либо для всех запросов:

➜ python manage.py runserver --ipdb

Либо вызывать отладчик при возникновении исключений (режим «post-mortem»):

➜ python manage.py runserver --pm

или

POST_MORTEM = True

в settings.py.

django-extensions

Но гораздо лучше в Django использовать модуль django-extensions, который добавляет очень полезную команду runserver_plus. С помощью этой батарейки можно подружить Django и Werkzeug (см. выше) и начать получать удовольствие от страниц с пятисотой ошибкой =)

Для использования всего этого чуда достаточно запустить девелоперский сервер с помощью команды runserver_plus:

➜ python manage.py runserver_plus

sentry

Отладка программы в девелоперском окружении это, конечно, удобно и хорошо, но самое сложное — локализовать проблему по багрепорту от живого пользователя. Иногда это бывает сложно. Несмотря на все преимущества Python, модуля «телепатии» не существует, и разработчик остаётся один на один со словами пользователя «ничего не работает!!!11».

Проект Sentry позволяет сохранять каждую ошибку пользователя с текстом исключения, полным стектрейсом исключения и значениями всех локальных переменных в каждой из функций стектрейса, а так же много другой информации: окружение пользователя (браузер, ОС), все заголовки запроса и вообще всё, что пожелает разработчик.


Одинаковые ошибки группируются, таким образом можно наблюдать за «пульсом» проекта и чинить в первую очередь самые критичные места. Ещё один пример использования sentry — логгирование. Можно просто добавить в спорное место запись в лог сообщения с любыми интересующими разработчика переменными, и всё это окажется в sentry.

Но самый большой плюс в том, что всё это можно (и нужно!) использовать в продакшене.

PuDB

Ещё один интересный отладчик: PuDB представляет собой консольный дебагер с графическим интерфейсом:

Не буду много о нём писать (честно говоря, я сам активно им не пользовался), предлагаю прочитать короткую заметка на хабре: Удобный отладчик для Python/Django проектов от пользователя int22h или более полный обзор: Отладка Python/Django при помощи PuDB.

Winpdb

Standalone отладчик Python, на этот раз с полноценным графическим интерфейсом: Winpdb:

Его разработчики утверждают, что winpdb в 20 раз быстрее pdb, а так же поддерживает работу с тредами. Очень большой и подробный туториал можно найти на этой странице: code.google.com/p/winpdb/wiki/DebuggingTutorial.

IDE

Отдельного слова заслуживают универсальные «комбайны» программирования: IDE, которые позволяют не выходя из редактора запустить код, отпрофилировать его или запустить встроенный отладчик. Я, пожалуй, выделю несколько продуктов, предназначенных для разработки на Python: PyCharm, PyDev, Wing IDE и PTVS.

Лирическое отступление

К сожалению, лично я сколько не пытался, так и не смог пересилить себя и променять скорость, удивительную гибкость и удобство работы с консолью и любимым текстовым редактором (будь то vim, emacs или sublime text) на любую из вышеперечисленных IDE, однако мои коллеги успешно ими пользуются и поэтому я советую хотя бы дать этим замечательным продуктам шанс и попробовать их.

Если честно, я не вижу особого смысла рассматривать каждую из этих IDE, достаточно знать что они есть, что они успешно справляются со своими задачами и вы можете использовать встроенный отладчик прямо из редактора, — это действительно удобно, круто и здорово.

Спасибо всем, кто дочитал и прокомментировал.

Владимир Рудных,

Технический руководитель Календаря Mail.Ru.

Продвинутый Debug / Хабр

Debug Area — полезная функция в работе iOS разработчика в Xcode. Как только мы начинаем осваивать разработку под iOS, и пытаемся отойти от привычного и любимого print метода, и найти более быстрые и удобные методы понимания состояния системы в определенный период мы начинаем изучать область дебага (Debug Area).

Скорее всего, в Debug панель ваш взгляд упадёт до того, как вы будете понимать, что именно там происходит. При первом падении приложения нижнее меню открывается автоматически, оно изначально может послужить помощью для понимания проблемы (Вспомним старую добрую “Fatal error: Index out of range”), в основном в самом начале вы не будете понимать, что от нас хочет Xcode и приметесь гуглить ошибки, но по ходу роста всё больше и больше информации станет понятной.

С самого начала программист старается оптимизировать свою работу. Для этого мы стремимся понять в какой момент наша программа перешла в некорректное состояние. И тут в зависимости от точки в которой находится эволюция программиста, методы могут разниться. Сначала как правильно Debug осуществляется методом “print()”, потом идёт расстановка Breakpoints и вызов методов “po”, далее ознакомление с Debug Variable Input (области рядом с консолью в Xcode), а далее приходит понимание и способов компиляции кода в процессе остановки на Breakpoint методов — “expression” (По крайней мере, такая была эволюция у меня).

Давайте попробуем разные способы которые нам помогут понять и изменить состояние нашего приложения. Самые простые вроде “print()”, и “po” рассматривать не будем, я думаю, вы и так понимаете их суть и умеете применять.

Создадим простое приложение с одним экраном в котором будем всего один тип ячеек (TableViewcell) c двумя элементами внутри: UIImageView и UILabel. В ячейках будем писать её порядковый номер, а в картинку ставить либо image1, либо image2.

Метод tableViewCellForRowAtIndexPath будет создавать для нас ячейки, проставлять данные и возвращать:


Данный метод будет генерировать такую таблицу:

Breakpoint

Давайте остановим нашу программу и допишем какой-нибудь текст в наш Label.

1. Ставим Breakpoint:

2. Программа остановила выполнение на 55 строке, сразу после присваивания текста. Так как мы находимся на строке, расположенной в зоне видимости ячейки, мы можем взаимодействовать с нашей ячейкой.

3. Пишем в консоли команду изменить текст ячейки:

4. Убираем наш Breakpoint и нажимаем кнопку «продолжить выполнения программы».

5. На экране нашего телефона видим, что всё успешно получилось:

expression выполняет выражение и возвращает значение на текущем потоке.

Edited Breakpoint

Но, что если нам понадобиться изменить текст в большом количестве ячеек? Или мы уже в процессе выполнения программы поняли, что нам надо поменять?

Мы можем оптимизировать выполнение этой операции и немного ускорить работу, сделать изменение текста в ячейки тогда, когда он доходит до Breakpoint и продолжить выполнять программу, это сократит много времени и позволит не печатать одно и тоже для каждой ячейки.

Для этого нам понадобиться немного модифицировать наш Breakpoint, прописать туда дополнительно код, который будет в зоне видимости нашей ячейки менять её текст и продолжать работу программы.

  1. Создаем breakpoint.
  2. Левой кнопкой мыши по стрелочке breakpoint’a.
  3. Нажимаем Edit Breakpoint.
  4. Condition — условия при котором Breakpoint сработает, сейчас он нам не нужен.
  5. Ignore — сколько раз пропустить Breakpoint прежде чем он сработает (тоже не то).
  6. А вот Action — то, что надо, выбираем тип действий Debugger Command.
  7. Пишем выражение которое нам нужен выполнить:
  8. expression cell.desriptionTextOutlet.text = «\(indexPath.item) mission complete”.
  9. Ставим галочку — Продолжить выполнение после успешного выполнения команды.

9. Пробуем.

Это успех, получилось изменить текст для каждой ячейки во время формирования таблицы, и нам не пришлось жертвовать временем и прописывать операции для каждой.

Breakpoint function

Всегда бывают моменты когда в нашем приложении происходит что-то, что мы не можем объяснить, текст не меняется или меняется больше чем необходимо, казалось бы Breakpoint в таком случае ставить некуда. Но это не совсем так, если вы знаете Obj-C, и знаете какой метод выполняет компилятор который вы хотите отследить вы можете поставить на него Breakpoint и в следующий раз, когда метод вызовется, приложение остановиться в процессе выполнения Assembler кода.

1. В Breakpoint навигаторе выбираем Symbolic Breakpoint.

2. Мы хотим отследить метод установки текста в ячейке, пишем -[UILabel setText:].

3. Нулевого аргумента не существует, и счет начинается с первого. Первый пойманный метод не тот, что нам нужен (он устанавливаем текущее время в статус бар), а второй как раз наш:

4. Под “$arg1” храниться описание объекта.

5. Под “$arg2” храниться selector функции.

6. Под “$arg3” храниться текст получаемый методом.

Ок, с этим вроде бы понятно. Но иногда возникают ситуации, когда установкой одного текста в статус бар дело не ограничивается, и надо отследить выполнение метода в конкретном контроллере, что же делать? Можно включить Breakpoint подобный тому, что мы установили ранее, но установив его позицию в коде. Что это значит? Мы точно знаем, что наш view появится когда мы будем устанавливать текст в ячейку, значит самое то поставить его во viewDidLoad или после создания ячейки.

Для создания breakpoint мы устанавливаем его на линии, и в action прописываем следующий код:

breakpoint set --one-shot true --name "-[UILabel setText:]”

breakpoint set —one-shot true — создаем breakpoint
—name — имя символьного breakpoint
“-[UILabel setText:]” вызываемый метод

Вот что получилось:

Skip Lines

А что если мы заподозрили, что какая-то строка кода портит нам всю программу? В процессе выполнения кода можно избежать выполнения определенной строки кода так:

  1. Ставим breakpoint на строку, которую мы не хотели бы выполнять.
  2. Когда выполнение остановиться, перетаскиваем его в строку, с которой хотим продолжить выполнение программы (забавно, но это не всегда работает, ниже вариант без перетаскивания).

Так же есть другой вариант, который позволит оптимизировать пропускание строк, — это прописывание соответствующей команды в “edit breakpoint”. Команда является рискованной, так как суть таких скачков — это избавить нас от ребилда, но если вы пропустите инициализацию объекта и попытаетесь к нему обратиться программа упадёт.

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

Звучит довольно неплохо, но картинку всё же присвоить хочется, давайте добавим метод присвоения в breakpoint:

Удачная комбинация, теперь у нас в каждой ячейке только один тип картинки.

Watchpoint

Еще одна удобная функция в дебагере — это отслеживание значений в программе, watchpoints. Watchpoint чем то похожа на KVO, мы ставим breakpoint на изменение состояния объекта, и каждый раз, когда он меняет своё состояние, процесс выполнения программы останавливается, и мы можем посмотреть значение и места, откуда и кем было изменено значение. Например, я поставил watchpoint на ячейку, что бы узнать, что происходит в момент листания таблицы и иницилизации новой ячейки. Список команд получился очень большой, поэтому его я приводить не буду просто упомяну некоторые: выполнения layout view находящихся внутри ячейки и простановка constraint, анимация, простановка состояний для ячейки и многое-многое другое.

Для простановки watchpoint на значение необходимо остановить выполнение программы breakpoint в области видимости свойств, который вы хотите отслеживать, выбрать свойство в “debug variable” панели и выбрать watch “<параметр>”.

Для того, что бы снять watchpoint с переменной надо заглянуть в breakpoint navigator, там вместе с остальными breakpoint будет находиться и наш watchpoint.

Breakpoint UI Change

Иногда нам надо узнать больше об объекте, который мы пытаемся отдебажить. Самый простой вариант — это использовать “po”, для вывода информации об объекте, и там же посмотреть на расположение объекта в памяти. Но бывает, что мы не имеем прямой ссылки на объект, он не представлен в API view, на которой лежит или возможно скрыт библиотекой. Один из вариантов использовать View Hierarchy, но это не всегда удобно да и понять, что вы нашли нужный view не всегда сложно. Можно попробовать использовать команду:

expression self.view.recursiveDescription()

Она есть в Obj-C но в Swift её убрали из за особенностей работы языка выполнить мы её не можем, но так как на Debuger работает с Obj-C, в теории ему можно скормить эту команду, и он поймёт, что вы от него хотите. Для выполнения кода Obj-C в консоли необходимо ввести команду:

expression -l objc -O - - [`self.view` recursiveDescription] 

Что вы тут видите? Я вижу довольно не удобную конструкцию, к котором можно было бы привыкнуть со временем, но лучше мы не будем этого делать, а используем typealias для упрощения команды:

command alias poc expression -l objc -O —

Теперь наша команда сокращается и упрощается, но продолжает делать работу:

poc [`self.view` recursiveDescription]

Будет ли она работать после закрытия Xcode или в другом проекте? Увы, нет. Но это можно исправить! Создав файл .lldbinit и вписав туда наш alias. Если не знаете как, вот инструкция по пунктам:

1. Создаете файл .lldbinit (в качестве прототипа можете взять .gitignore, он относится к тому же типу текстовых невидимых файлов).

2. Напишите в этом файле ровно следующую команду:

 command alias poc expression -l objc -O - -	


3. Файл поместите в папку по адесу “MacintoshHD/Users/”.

И так мы получили описание всех view, представленных на экране. Давайте попробуем посмотреть, что мы сможем сделать с адресом объектов в памяти. Для Swift тут имеется метод с недостатоком, надо всё время приводить тип объекта в памяти к определенному значению:

po unsafeBitCast(0x105508410, to: UIImageView.self)

Теперь мы видимо положение нашей картинки в ячейке, давайте её подвинем что бы она была по центу ячейки и имела отступ с боку 20 px.

Бывает не сразу заметно изменение, а необходимо снять с debug приложение что бы заметить изменение.

Но если мы хотим видеть нечто подобное в каждой ячейки, надо ускорить выполнение команд, можно написать на Python несколько скриптов которые будут работать на нас (как добавлять скрипты можно посмотреть здесь www.raywenderlich.com/612-custom-lldb-commands-in-practice), и если вы умеете обращаться с Python и хотите написать на нём для lldb то вам пригодиться.

Я же решил написать расширение для класса UIView, который просто будет двигать view в нужном направлении, мне показалось так будет меньше проблем с подключением новых скриптов к LLDB и не сложно для любого iOS программиста (иначе надо осваивать Python для LLDB).

Я не стал искать место объекта в памяти и приводить его в нужный класс, что бы потом взять frame, это так же займет слишком много времени. Вопрос решился написанием функции в расширении UIView:

К сожалению, она плохо работает с ячейками, скорее всего из за того, что в момент исполнения команды flush не все позиции ячейки просчитаны и она не появилась на экране (мы пока не вернули tableViewCell). С остальными статическими элементами оно работает отлично.

Зная положение view в иерархии, мы можем получить к нему доступ и менять его положение.

А теперь обратная ситуация, когда мы можем получить доступ к ViewHierarchy и хотим оттуда получить данные о view. В Xcode есть возможность просматривать иерархию view в процессе выполнения программы, так же там можно просмотреть цвета, расположение, типы и привязки к другим объектам в том числе. Давайте попробуем получить доступ к constraints нашего UIImageView.

Для получения данных о constraint:

1. Нажмите на Debug View Hierarchy.

2. Включите Clipped Content на панели внизу появившегося экрана.

3. Включите Constraints на той же панели.

4. Выберите Contraint.

5. В меню нажмите Edit -> Copy (Command + C).

6. Копируется привязка вот такого вида: ((NSLayoutConstraint *)0x2838a39d0).

7. И теперь, так же как мы меняем её через код так же можно поменять и в lldb:
expression [((NSLayoutConstraint *)0x2838a39d0) setConstant: 60]

8. После нажатия кнопки продолжить, элемент обновит своё положение на экране.

Таким же образом можно менять цвета, текст и многое другое:

expression [(UILabel *)0x102d0a260] setTextColor: UIColor.whiteColor]

Demo проект получился слишком простым (60 строк кода во ViewController), большую часть кода, который я написал, представлена в статье, так что сложности в воспроизведении тестового проекта не возникнет.

P.S.: Если есть вопросы или замечания пишите. Посматривайте WWDC и Дебажте как Pro.

Советую так же ознакомиться с материалами:

Вдохновлялся Advanced Debugger WWDC 18 Session
Команды Debugger
Добавление скриптов Python в LLDB Xcode

AVR. Учебный Курс. Отладка программ. Часть 2

Метод 2. Моргалки (Работа портами Ввода-вывода)

Трассировка и аналитика это все замечательно, но когда мы начинаем отлаживать что то внешнее, то тут трассировка нам поможет мало. Т.к. глючить может не внутри, а снаружи.
 

Либо у нас будет не глюк, а банальное непонимание ситуации. Фразу из даташита, например, неправильно перевел или глаз замылился. Что то забыл или не туда припаял. Да мало ли как можно накосячить.
 

В общем, правильный алгоритм может работать из-за кривой аппаратной реализации. А чтобы понять где косяк надо проследить и знать как это работает внутри. В общем, заглянуть в код программы.
 

Причем нам не обязательно точно следить за тем, что там происходит покомандно — это мы или трейсом или туплением отладим. Интересней знать куда ушла прога.
 

Самым простым методом тут будет отладочный вывод. Все просто — мы берем и определяем один из выводов под отладку. Причем даже если у нас какая-нибудь крошечная тинька и все выводы расписаны буквально по нескольку раз, то все равно можно найти один лишний вывод — достаточно закомментить код который его использует, но в данный момент его правильность нас не интересует.
 

А у вывода может быть три состояния — Hi, Lo и Hi-Z. Так что рекомендую скреативить такой вот пробничек:
 

 

Тогда если у нас Hi-Z то будут тускленько гореть оба диода. Ну, а на соответствующий уровень свой диод в гордом одиночестве.
 

А в код пихаем дебажные секции вида:
 

1
2
3
;Set Hi
	SBI	DEBUGDDR,DEBUG
	SBI	DEBUGPORT,DEBUG

;Set Hi
SBI DEBUGDDR,DEBUG
SBI DEBUGPORT,DEBUG

1
2
3
;Set Lo
	SBI	DEBUGDDR,DEBUG
	CBI	DEBUGPORT,DEBUG

;Set Lo
SBI DEBUGDDR,DEBUG
CBI DEBUGPORT,DEBUG

1
2
3
;Set Hi-Z
	CBI	DEBUGDDR,DEBUG
	CBI	DEBUGPORT,DEBUG

;Set Hi-Z
CBI DEBUGDDR,DEBUG
CBI DEBUGPORT,DEBUG

 

Можно их в макросы завернуть. Удобней будет.
 

По состоянию дебаг вывода мы можем увидеть в каком месте программа прошла. А комбинируя нашу троичную систему получим целых 9 возможных комбинаций на 2 вывода.
 

Однако если у нас надо отследить последовательность, то мы можем и не успеть разглядеть переимгивание светиков. Но никто не мешает воткнуть в код после смены состояния дебагвывода тупую задержку вида:
 

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
	PUSHF			; Макрос сохранения флагов
	PUSH 	R16
	PUSH	R17
	PUSH	R18
 
	LDI	R16,255	; Грузим три байта
	LDI	R17,255	; Нашей выдержки
	LDI	R18,255
 
Dloop:	SUBI	R16,1		; Вычитаем 1
	SBCI	R17,0		; Вычитаем только С
	SBCI	R18,0		; Вычитаем только С
 
	BRCC	DLoop 		; Если нет переноса - переход
 
	POP	R18
	POP	R17
	POP	R16
	POPF			; Макрос восстановления флагов

PUSHF ; Макрос сохранения флагов
PUSH R16
PUSH R17
PUSH R18

LDI R16,255 ; Грузим три байта
LDI R17,255 ; Нашей выдержки
LDI R18,255

Dloop: SUBI R16,1 ; Вычитаем 1
SBCI R17,0 ; Вычитаем только С
SBCI R18,0 ; Вычитаем только С

BRCC DLoop ; Если нет переноса — переход

POP R18
POP R17
POP R16
POPF ; Макрос восстановления флагов

 

Оформляется как прерывание для того, чтобы иметь минимальное влияние на код. Можно тоже оформить в виде макроса и втыкать его одной строчкой. Запрет прерываний опционально.
 

Либо вставлять затуп:

 

Контроллер на этой команде встанет и дальше никуда не пойдет (правда если включен вачдог, то он ребутнется по вачдогу).
 

А можно же сразу после задержки перевести отладочный вывод в режим входа PullUp и просить кнопку пробника. Если нажата, можно идти дальше. Можно и без задержки, сделать, но надо смотреть, чтобы дребезг не помешал.
 

1
2
3
4
5
6
;STOP DB_BTN
	CBI	DEBUGDDR,DEBUG
	SBI	DEBUGPORT,DEBUG	
 
	SBIC	DEBUGPIN,DEBUG
	RJMP	PC-1

;STOP DB_BTN
CBI DEBUGDDR,DEBUG
SBI DEBUGPORT,DEBUG

SBIC DEBUGPIN,DEBUG
RJMP PC-1

 

Можно просто наставить таких кнопочных чекпоинтов. И пускать программу по ним своей могучей волевой рукой. А пока программа тупит на задержках или ожиданиях кнопок, можно спокойно замерить напряжения/пощупать лог уровни, состояние других выводов, да просто подумать.
 

Разумеется, если в схеме уже присутствуют светодиоды и кнопки, то и пробник тут не нужен — обойдемся имеющимися средствами — переназначив их на время отладки конкретного участка.
 

Правда в случаях отладки асинхронных устройств, работающих на четких временных выдержках данная затея может не прокатить, но для них есть другие варианты, о них позже.

R Debug — основные принципы и функции, которые нельзя пропустить!

В этом руководстве мы собираемся изучить очень интересную тему, а именно отладку R. Здесь мы обсудим основные принципы отладки R и его различные функции в программировании на R с помощью примеров. Мы также подробно рассмотрим отладку установленных пакетов и обработку ошибок и восстановление.

Итак, приступим к уроку.

Что такое R Debug?

Грамматически правильная программа может давать неверные результаты из-за логических ошибок.В случае возникновения таких ошибок (т. Е. Ошибок) нам нужно выяснить, почему и где они возникают, чтобы вы могли их исправить. Процедура выявления и исправления ошибок называется « отладка ».

Существует ряд функций отладки R, например:

  • трассировка ()
  • Отладка

  • ()
  • браузер ()
  • след ()
  • восстановление ()

Мы обсудим вышеупомянутые функции по очереди в следующем разделе этой статьи.Перед этим давайте взглянем на основные принципы отладки в R.

.

Секундочку! Вы проверили — Загрузка в R Programming

Основные принципы отладки R

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

1. Суть отладки

Принцип подтверждения:

Исправление программы с ошибками — это процесс подтверждения, одно за другим, что многие вещи, которые, как вы считаете, верны в коде, действительно верны.2 + 3 * g (z, 2)
w <- 28
if (w + q> 0) u <- 1 else v <- -10

2. Начните с малого

Придерживайтесь небольших простых тестов, по крайней мере, в начале процесса отладки R. Работа с большими объектами данных может затруднить осознание проблемы. Конечно, мы должны в конечном итоге протестировать наш код в больших, сложных случаях, но начнем с малого.

3. Отладка в модульном

Правила поведения сверху вниз:

Большинство профессиональных разработчиков программного обеспечения согласны с тем, что код должен быть написан по модульному принципу.Наш код первого уровня не должен быть достаточно длинным, поскольку большая часть его состоит из вызовов функций. И эти функции не должны быть слишком длинными и при необходимости должны вызывать другую функцию. Это упрощает код на этапе написания, а также позволяет другим понять, когда придет время расширять код.

Мы должны отлаживать сверху вниз. Предположим, мы установили статус отладки нашей функции f () , и она содержит эту строку.

Например:

Y <- g (x, 8)

В настоящее время не вызывайте отладку (g).Выполните строку и посмотрите, возвращает ли g () ожидаемое значение. Если это так, то мы должны просто избежать трудоемкого процесса пошагового выполнения g (). Если g () возвращает неправильное значение, то сейчас самое время вызвать debug (g).

Узнайте больше о векторных функциях R

4. Защита от ошибок

Если у нас есть часть кода, в которой переменная x должна быть положительной, то мы можем вставить эту строку:

Stopifnot (x> 0)

Если в предыдущем коде есть ошибка, которая отображает x равным, скажем, -3, вызов stopifnot () сразу же приведет к этому с сообщением об ошибке вроде этого:

Ошибка: x> 0 НЕ ИСТИНА

R Функции отладки

Теперь мы обсудим вышеупомянутые функции для отладки в R:

.

1.трассировка ()

Если наш код уже потерпел крах, и мы хотим знать, где находится строка с нарушением, попробуйте traceback (). Это (иногда) показывает местонахождение в коде возникшей проблемы.

Когда функция R не работает, на экран выводится сообщение об ошибке. Сразу после ошибки вы можете вызвать traceback (), чтобы узнать, в какой функции произошла ошибка. Функция traceback () печатает список функций, которые были вызваны до возникновения ошибки. Функции печатаются в обратном порядке.3
}

Отображение кода:

Выход:

2. отладка ()

Функция debug () в R позволяет пользователю пошагово выполнить выполнение функции, строка за строкой. В любой момент мы можем распечатать значения переменных или построить график результатов внутри функции. Во время отладки мы можем просто набрать «c», чтобы продолжить до конца текущего раздела кода. traceback () не сообщает нам, где произошла ошибка в функции.2
получить <- сумма (sqr) получить } set.seed (100) val <- rnorm (100) веселье (1, val) #Author DataFlair

Выход:

> # Автор DataFlair
> отладка (весело)
> веселье (1, val) 

Выход:

После того, как вы увидите приглашение «Обзор [1]>», вы можете делать разные вещи:

  • При вводе n выполняется текущая строка и печатается следующая;
  • Набрав Q, мы можем выйти из отладки;
  • Ввод «где» указывает, где вы находитесь в стеке вызовов функций;
  • Набрав ls () , мы можем вывести список всех объектов в локальной среде.

Ввод имени объекта или печати (<имя объекта>) сообщает нам текущее значение объекта. Если ваш объект имеет имя n, c или Q, мы должны использовать print () , чтобы увидеть их значения.

Знаете ли вы об объектно-ориентированном программировании в R

3. браузер ()

Функция отладки R browser () останавливает выполнение функции, пока пользователь не разрешит ее продолжить. Это полезно, если мы не хотим выполнять пошаговое выполнение всего кода построчно, но хотим, чтобы он останавливался на определенном этапе, чтобы мы могли проверить, что происходит.3
}

Отображение кода:

Выход:

4. трассировка ()

Вызов trace () для функции позволяет пользователю вставлять биты кода в функцию. Синтаксис функции отладки R trace () немного странен для начинающих пользователей. Возможно, лучше использовать debug ().

Например:

 #Author DataFlair
f <-функция (x) {
  г <-x-g (х)
  р
}
g <-функция (y) {
  г <-у * ч (у)
  р
}
h <-функция (z) {
  г <-log (г)
  если (r <10)
    г ^ 2
  еще
    г ^ 3
}
 

Отображение кода:

В консоли набираем следующие команды:

> как.список (тело (h))
> trace ("h", цитата (if (is.nan (r)) {browser ()}), at = 3, print = FALSE)
> f (1)
> f (-1)
Обзор [1]> n
Обзор [2]> ls ()
Предупреждающее сообщение:
В журнале (z): произведено NaN
Обзор [2]> r
Обзор [2]> z
Обзор [2]> trace ("h", цитата (if (z <0) {z <-1}), at = 2, print = FALSE)
Обзор [2]> f (-1) 

Выход:

5. восстановить ()

Когда мы отлаживаем функцию, recovery () позволяет нам проверять переменные в функциях верхнего уровня.

Набрав число в выделенном фрагменте, мы переходим к функции в стеке вызовов и помещаемся в среду браузера.

  • Мы можем использовать recovery () как обработчик ошибок, установленный с помощью опций () (например, опций (error = recovery)).
  • Когда функция выдает ошибку, выполнение останавливается в точке сбоя. Мы можем просматривать вызовы функций и исследовать среду, чтобы найти источник проблемы.

При восстановлении мы используем предыдущие функции f (), g () и h () для отладки.

> trace ("h", цитата (if (is.nan (r)) {Recovery ()}), at = 3, print = FALSE)
> f (-1)

Выбор: 1
Обзор [1]> n

Выбор: n
Выбор: 2
Обзор [3]> n

Выбор: n
Выбор: 3
Обзор [5]> n

Выбор: n
Выбор: 0
Обзор [4]> 

Выход:

При вводе числа в выделенном фрагменте мы переходим к функции в стеке вызовов и помещаемся в среду браузера.

Полное руководство по рекурсивной функции R

Отладка установленных пакетов в R

Возможна ошибка, связанная с установленным пакетом R. Вот несколько способов решить эту проблему:

  • Настройка параметров (ошибка = восстановление), а затем построчное выполнение кода с помощью n.
  • При возникновении сложных проблем вы можете иметь при себе копию кода функции. При вводе имени функции в консоли R будет распечатан код функции, который можно скопировать в текстовый редактор.Затем вы можете отредактировать его, загрузить в глобальную рабочую область и затем выполнить отладку.
  • Если проблемы все еще не решены, загрузите исходный код. Вы также можете использовать пакет devtools и функции install (), load_all () , чтобы ускорить процесс.

Обработка ошибок и восстановление в R

Обработка исключений или ошибок - это процесс реагирования на аномальные события в коде, которые нарушают его выполнение. В общем, область действия обработчиков исключений начинается с попытки и заканчивается уловкой.R предоставляет для этого же функции try () и trycatch () .

Функция try () является функцией-оболочкой для trycatch (), которая печатает ошибку и затем продолжает работу. С другой стороны, trycatch () дает вам контроль над функцией ошибки, а также, необязательно, продолжает процесс функции.

 #Author DataFlair
f <- функция (значение) {
  if (значение == 0) {
    stop («Значение не может быть 0»)
  } else {
    печать (значение)
  
}

 

Отображение кода:

> inp <- sapply (0: 3, функция (i) f (i))
> Inp <- sapply (0: 3, функция (i) try (f (i)))
> Inp <- sapply (0: 3, функция (i) tryCatch (f (i), error = function (e) NA)) 

Выход:

Сводка

В этом руководстве по функциям отладки R мы поняли концепцию отладки в R вместе с их функциями и примерами.Мы также изучили отладку установленных пакетов и обработку ошибок и восстановление в R-программировании.

Подробнее о функциях ввода-вывода в программировании на языке R

Если у вас есть какие-либо вопросы, связанные с отладкой в ​​R, не стесняйтесь поделиться с нами. Надеюсь, мы поможем вам.

.Отладка

- инструкция отладки browser () R

Переполнение стека

  1. Около
  2. Продукты

  3. Для команд
  1. Переполнение стека
    Общественные вопросы и ответы

  2. Переполнение стека для команд
    Где разработчики и технологи делятся частными знаниями с коллегами

  3. Вакансии
    Программирование и связанные с ним технические возможности карьерного роста

  4. Талант
    Нанимайте технических специалистов и создавайте свой бренд работодателя

  5. Реклама
    Обратитесь к разработчикам и технологам со всего мира

  6. О компании

Загрузка…

  1. Авторизоваться
    зарегистрироваться

  2. текущее сообщество

.

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *