<?xml version="1.0" encoding="utf-8"?>
<?xml-stylesheet type="text/css" href="http://wiki2.linuxformat.ru/skins/common/feed.css?97"?>
<feed xmlns="http://www.w3.org/2005/Atom" xml:lang="ru">
		<id>http://wiki2.linuxformat.ru/index.php?action=history&amp;feed=atom&amp;title=LXF120%3Adebug</id>
		<title>LXF120:debug - История изменений</title>
		<link rel="self" type="application/atom+xml" href="http://wiki2.linuxformat.ru/index.php?action=history&amp;feed=atom&amp;title=LXF120%3Adebug"/>
		<link rel="alternate" type="text/html" href="http://wiki2.linuxformat.ru/index.php?title=LXF120:debug&amp;action=history"/>
		<updated>2026-05-14T03:10:31Z</updated>
		<subtitle>История изменений этой страницы в вики</subtitle>
		<generator>MediaWiki 1.11.1</generator>

	<entry>
		<id>http://wiki2.linuxformat.ru/index.php?title=LXF120:debug&amp;diff=10367&amp;oldid=prev</id>
		<title>Crazy Rebel: викификация, оформление, иллюстрация</title>
		<link rel="alternate" type="text/html" href="http://wiki2.linuxformat.ru/index.php?title=LXF120:debug&amp;diff=10367&amp;oldid=prev"/>
				<updated>2010-06-15T06:36:59Z</updated>
		
		<summary type="html">&lt;p&gt;викификация, оформление, иллюстрация&lt;/p&gt;
&lt;p&gt;&lt;b&gt;Новая статья&lt;/b&gt;&lt;/p&gt;&lt;div&gt;: '''Отладчик GNU''' Идейно выдержанное средство поиска ошибок в ваших приложениях&lt;br /&gt;
&lt;br /&gt;
==''GDB'': Избавимся от ошибок==&lt;br /&gt;
&lt;br /&gt;
: Один из основных принципов открытого ПО – «больше глаз – меньше ошибок»; так чего же вы ждете? '''Андрей Боровский''' познакомит вас с необходимым инструментарием.&lt;br /&gt;
&lt;br /&gt;
При первом знакомстве отладчик ''GNU Debugger (GDB)'' может напугать программистов, привыкших к встроенным отладчикам графических интегрированных сред разработки. На самом деле все не так страшно. Выучив несколько простых команд, вы сможете сделать с помощью отладчика GNU все, что вы могли бы сделать в плане отладки в средах Microsoft или Borland. Выучив еще несколько команд, вы сможете делать такое, что пользователям графических IDE и не снилось. И хотя в наше время безалкогольного шампанского и бескофеинового кофе в Linux появились свои графические IDE со встроенными функциями отладки (''Eclipse, Qt Creator''), изучение возможностей ''GDB'' все равно будет вам полезно, поскольку «за кулисами» указанные среды вызывают именно его.&lt;br /&gt;
&lt;br /&gt;
Выдумывать специальные примеры для отладки – дело неблагодарное, поэтому мы рассмотрим этот процесс на примере программы ''Cuneiform'', «доводкой» которой я занимаюсь уже некоторое время ([[LXF118:Компьютер слушает|LXF118]]). Не пугайтесь, вам не придется вникать в логику работы ''Cuneiform''. Все выбранные нами примеры самоочевидны.&lt;br /&gt;
&lt;br /&gt;
===Приступаем к отладке===&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Заголовок=Помощь придет|Содержание=Для получения справки по работе с ''GDB'' вовсе не обязательно выходить из интерактивного режима – достаточно ввести команду '''help''' или '''help имя_команды'''. Например,&lt;br /&gt;
&lt;br /&gt;
 (gdb) help exec-file&lt;br /&gt;
&lt;br /&gt;
распечатает справочную информацию о команде '''exec-file'''. Получать справку о конкретной команде имеет смысл, если вы знаете, что именно вам нужно. Если же вы – новичок в работе с отладчиком, вам прежде всего понадобится информация о том, какие вообще команды существуют в системе. В интерактивном режиме отладчика GNU программисту доступны сотни команд (большая часть которых никогда ему не понадобится). Для удобства навигации в справочной системе ''GDB'' они сгруппированы по нескольким разделам:&lt;br /&gt;
* '''aliases''' – псевдонимы других команд&lt;br /&gt;
* '''breakpoints''' – команды, управляющие точками останова&lt;br /&gt;
* '''data''' – команды, позволяющие манипулировать данными программы в процессе отладки&lt;br /&gt;
* '''files''' – команды для работы с файлами&lt;br /&gt;
* '''internals''' – внутренние команды ''GDB''&lt;br /&gt;
* '''obscure''' – команды для продвинутых пользователей&lt;br /&gt;
* '''running''' – команды, управляющие запуском отлаживаемой программы&lt;br /&gt;
* '''stack''' – команды, управляющие просмотром стека&lt;br /&gt;
* '''status''' – команды (тысячи, тысячи их), которые сообщают различные сведения об отлаживаемой программе, отладчике и системе&lt;br /&gt;
* '''support''' – разные полезные команды, управляющие отладчиком&lt;br /&gt;
* '''tracepoints''' – команды, которые управляют трассировкой&lt;br /&gt;
* '''user-defined''' – команды, определенные пользователем.&lt;br /&gt;
&lt;br /&gt;
Например, для того, чтобы получить сведения о командах, управляющих точками останова, введите:&lt;br /&gt;
&lt;br /&gt;
 (gdb) help breakpoints|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
Чтобы извлечь из ''GDB'' максимум, программу, предназначенную для отладки, следует скомпилировать с дополнительной отладочной информацией. Ее добавлением управляет ключ '''-g''' команд ''gcc'' и ''g++''. Файл программы или библиотеки, скомпилированный с добавлением отладочной информации, занимает больше места, чем обычный, однако вам вовсе не обязательно перекомпилировать модуль по окончании отладки. Удалить отладочную информацию из исполняемого файла можно в любой момент с помощью утилиты ''strip''.&lt;br /&gt;
&lt;br /&gt;
Подготовив двоичные модули ''Cuneiform'', мы запускаем отладчик с помощью команды ''gdb''. Перед нами появляется приглашение командной строки: ''(gdb)''. Далее в примерах команд мы будем указывать его, чтобы отличать команды интерактивного режима отладчика от других. Интерактивный режим ''GDB'' похож на таковой в командной оболочке ''Bash''. Более того, в ''GDB'' задействованы многие полезные функции командной оболочки: например, автоматическое завершение команды с помощью клавиши табуляции, преобразование символа '''~''' и история команд. Есть даже свой аналог сценариев оболочки. Для выхода из ''GDB'' служит команда '''quit'''.&lt;br /&gt;
&lt;br /&gt;
Мы должны указать отладчику имя программы, которую собираемся отлаживать. Это можно сделать во время запуска ''GDB'':&lt;br /&gt;
&lt;br /&gt;
 $ gdb cuneiform&lt;br /&gt;
&lt;br /&gt;
А можно и после запуска ''Cuneiform'' с помощью команды '''exec-file''':&lt;br /&gt;
&lt;br /&gt;
 (gdb) exec-file cuneiform&lt;br /&gt;
&lt;br /&gt;
В любом случае, ''GDB'' лишь подготовит среду для отладки программы, но не запустит ее на выполнение. Вообще, следует помнить, что отладчик всегда находится в одном из трех режимов: отлаживаемая программа работает, отлаживаемая программа приостановлена и программа не выполняется. Большую часть команд отладчика можно вводить в последних двух режимах. Для запуска программы служит команда '''run''':&lt;br /&gt;
&lt;br /&gt;
 (gdb) run rf2.bmp -l rus_fra -o out.txt&lt;br /&gt;
&lt;br /&gt;
Все аргументы, которые мы указываем в команде '''run''', передаются непосредственно программе, запускаемой на отладку. После ввода приведенной выше команды мы увидим:&lt;br /&gt;
&lt;br /&gt;
 Starting program: /usr/local/bin/cuneiform rf2.bmp -l rus_fra -o out.txt&lt;br /&gt;
 Cuneiform for Linux 0.7.0 (multilang)&lt;br /&gt;
 Program exited normally.&lt;br /&gt;
&lt;br /&gt;
Текст, появляющийся между строками '''«Starting program:...»''' и '''«Program exited normally.»''', представляет собой консольный вывод отлаживаемой программы. Пока что отладчик не сообщил нам каких-либо полезных сведений о ней, но даже от запуска приложения в этом режиме может быть толк. Если во время выполнения произойдет ошибка сегментации, отладчик, помимо прочего, покажет нам состояние стека процедур на момент ее возникновения. Также, если программа зависнет и мы завершим ее выполнение с помощью '''Ctrl+C''', нам будут выданы сведения о том, в каком месте программы была прервана ее работа, например:&lt;br /&gt;
&lt;br /&gt;
 Program received signal SIGINT, Interrupt.&lt;br /&gt;
 0xb7d8c8b4 in IntervalsBuild (y=979) at /home/andrei/bazaar/cuneiform-multilang/cuneiform_src/Kern/rblock/sources/c/ltexcomp.c:144&lt;br /&gt;
 144 while (x &amp;lt; nWidth &amp;amp;&amp;amp; (pLine [x] &amp;amp; BlackMask) == 0)&lt;br /&gt;
&lt;br /&gt;
Здесь мы видим имя функции, во время выполнения которой была прервана работа программы (то есть '''IntervalsBuild'''), значение параметров, с которыми она была вызвана (в нашем случае – один параметр, '''y''', со значением '''979'''), имя файла и номер строки исходного текста, соответствующего прерванному фрагменту, и саму строку кода.&lt;br /&gt;
&lt;br /&gt;
Очень часто даже этой информации достаточно для того, чтобы вызвать озарение у программиста, ищущего ошибку. Но ''GDB'' способен показать нам гораздо больше. Мы можем просмотреть значения переменных, доступных нам в данном контексте (как минимум, это '''x, nWidth, pLine''', и '''BlackMask'''). Для этого воспользуемся командой '''print''':&lt;br /&gt;
&lt;br /&gt;
 (gdb) print x&lt;br /&gt;
 Результат:&lt;br /&gt;
 $1 = 681&lt;br /&gt;
&lt;br /&gt;
Команда:&lt;br /&gt;
 (gdb) print pLine[x]&lt;br /&gt;
 Результат:&lt;br /&gt;
 $2 = 0 '\0'&lt;br /&gt;
&lt;br /&gt;
Таким образом мы узнаем, что на момент прерывания переменная '''x''' содержала значение '''681''', а элемент массива '''pLine[681]''' – символ ''''\0'''' . Если мы забыли или не знали, какой тип имеет переменная '''pLine''', мы можем узнать это, не заглядывая в исходники:&lt;br /&gt;
&lt;br /&gt;
 (gdb) ptype pLine&lt;br /&gt;
 type = unsigned char *&lt;br /&gt;
 &lt;br /&gt;
Но и это еще не все. Можно изменить значение переменной:&lt;br /&gt;
&lt;br /&gt;
 (gdb) set x=0&lt;br /&gt;
&lt;br /&gt;
а затем возобновить выполнение программы с помощью команды '''continue'''.&lt;br /&gt;
&lt;br /&gt;
===Точки останова===&lt;br /&gt;
&lt;br /&gt;
{{Врезка|left|Заголовок=Скорая помощь|Содержание=Собирая программу с отладочной информацией, не забудьте отключить и оптимизацию ('''-O0'''). Код оптимизированной программы не совсем похож на ваши исходники, и это может привести к трудноразрешимым проблемам.|Ширина=150px}}&lt;br /&gt;
&lt;br /&gt;
Поскольку современные микропроцессоры работают очень быстро, комбинация клавиш '''Ctrl+C''' далеко не всегда останавливает программу именно там, где нам нужно. Как правило, мы хотим, чтобы ее выполнение было прервано в заранее определенном месте. Для этого и служат точки останова ('''breakpoint'''). Наберите&lt;br /&gt;
&lt;br /&gt;
 (gdb)break copy_text&lt;br /&gt;
&lt;br /&gt;
Эта команда создает точку останова в начале функции '''copy_text''' (ленивые могут ввести просто '''b copy_text'''). В ответ на ввод команды ''GDB'' скажет:&lt;br /&gt;
&lt;br /&gt;
 Breakpoint 1 at 0xb7f57f35: file /home/andrei/bazaar/cuneiform-multilang/cuneiform_src/Kern/puma/c/spcheck.cpp, line 85.&lt;br /&gt;
&lt;br /&gt;
Это значит, что отладчик нашел интересующую нас функцию и строку кода, соответствующую точке останова. Теперь мы снова запускаем программу ''Cuneiform'' на выполнение с помощью команды '''run'''. Когда процессор достигнет точки останова (если это случится), выполнение программы будет прервано, и на экране появится следующее сообщение:&lt;br /&gt;
&lt;br /&gt;
 Breakpoint 1, copy_text (word=0x9452338) at /home/andrei/bazaar/cuneiform-multilang/cuneiform_src/Kern/puma/c/spcheck.cpp:85&lt;br /&gt;
 85 word-&amp;gt;text = (Word8 *) malloc((word-&amp;gt;wlen + 1)*sizeof(Word8));&lt;br /&gt;
 Current language: auto; currently c++&lt;br /&gt;
&lt;br /&gt;
Мы снова видим имя функции, выполнение которой было приостановлено, имя и значение переданного ей параметра и строку исходного текста, которая будет выполнена далее. Команда&lt;br /&gt;
&lt;br /&gt;
 (gdb) ptype word&lt;br /&gt;
сообщает нам нам следующее:&lt;br /&gt;
&lt;br /&gt;
 type = struct _SPWord {&lt;br /&gt;
 Bool32 is_latin;&lt;br /&gt;
 CSTR_rast begin;&lt;br /&gt;
 CSTR_rast end;&lt;br /&gt;
 Word8 *text;&lt;br /&gt;
 int wlen;&lt;br /&gt;
 } *&lt;br /&gt;
&lt;br /&gt;
Мы видим, что переменная '''word''' представляет собой указатель на экземпляр структуры '''_SPWord'''. Чтобы узнать значения полей структуры, наберите&lt;br /&gt;
&lt;br /&gt;
 (gdb) output * word&lt;br /&gt;
&lt;br /&gt;
Команда '''output''' делает то же, что и команда '''print''', но при этом не утруждает себя излишним форматированием. Результат выполнения команды выглядит так:&lt;br /&gt;
&lt;br /&gt;
 {is_latin = 1, begin = 0x93e7008, end = 0x93c2a20, text = 0x1cc08f3f &amp;lt;Address 0x1cc08f3f out of bounds&amp;gt;, wlen = 6}&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что отладчик любезно сообщил нам о том, что поле '''text''' указывает на невыделенную область памяти. Эта информация может очень пригодиться при поиске ошибок, но не в данном случае. Поле '''text''' просто еще не инициализировано (это произойдет в следующей строке).&lt;br /&gt;
Если вам хочется изучить работу программы подробнее, начиная с этого момента, к вашим услугам команды '''step''' и '''next'''. Они выполняют операции, соответствующие одной строке исходного текста (когда это возможно), и снова приостанавливают выполнение программы. Серия вызовов '''step''' или '''next''' позволяет вам производить отладку построчно. В нашем примере, в результате выполнения команды&lt;br /&gt;
&lt;br /&gt;
 (gdb) step&lt;br /&gt;
&lt;br /&gt;
мы переходим к следующей строке:&lt;br /&gt;
&lt;br /&gt;
 86 CSTR_rast rast = word-&amp;gt;begin;&lt;br /&gt;
&lt;br /&gt;
Разница между командами '''step''' и '''next''' заключается в том, что step «заходит» в каждую функцию, вызов которой встречается у нее на пути, и проходит ее построчно, тогда как '''next''' «перепрыгивает» вызов функции, выполняя его за один шаг. Команда '''step''' по смыслу соответствует командам '''Trace into/Step into''' интегрированных отладчиков Borland и Microsoft, тогда как команда '''next''' соответствует их командам '''Step over'''. Запуск приостановленной программы осуществляется командой '''continue'''. Вместо полных имен команд '''step, next''' и '''continue''' можно использовать их однобуквенные псевдонимы – '''s, n''' и '''c''' соответственно. Если вы хотите, чтобы программа сделала сразу 5 шагов, можете просто скомандовать&lt;br /&gt;
&lt;br /&gt;
 (gdb) s 5&lt;br /&gt;
&lt;br /&gt;
Если же построчной отладки вам недостаточно, перейдите на уровень отслеживания выполнения отдельных инструкций процессора с помощью команд '''stepi''' и '''nexti'''.&lt;br /&gt;
&lt;br /&gt;
Точки останова не обязательно должны располагаться в начале функций. Например, если мы скомандуем&lt;br /&gt;
&lt;br /&gt;
 (gdb) break 97&lt;br /&gt;
&lt;br /&gt;
следующая точка останова будет создана в строке 97 файла '''/home/andrei/bazaar/cuneiform-multilang/cuneiform_src/Kern/puma/c/spcheck.cpp''' (поскольку он является текущим). Если вы хотите создать точку останова на заданной строке в другом исходном файле, команда должна выглядеть так:&lt;br /&gt;
&lt;br /&gt;
 (gdb) break имя_файла:номер_строки&lt;br /&gt;
&lt;br /&gt;
Можно также указывать для точки останова определенный адрес.&lt;br /&gt;
&lt;br /&gt;
Следует, однако, учитывать, что не каждой строке текста программы соответствуют операции микропроцессора. Если мы попытаемся создать точку останова в строке, для которой отладчик не может найти исполняемый код, она будет создана на одной из следующих строк, иногда в довольно неожиданном месте. Например, если мы попытаемся создать точку останова в строке 155 в следующем фрагменте:&lt;br /&gt;
&lt;br /&gt;
 151 if (!strchr(“,.():;!?\» «» %”, nxt-&amp;gt;vers-&amp;gt;Alt[0].Code[0])) {&lt;br /&gt;
 152 rast-&amp;gt;vers-&amp;gt;Alt[0].Code[0] = ' ';&lt;br /&gt;
 153 rast-&amp;gt;vers-&amp;gt;Alt[0].Code[1] = 0;&lt;br /&gt;
 154 rast = CSTR_GetPrev(rast);&lt;br /&gt;
 155 continue;&lt;br /&gt;
 156 } else{&lt;br /&gt;
 157 i++ ... }&lt;br /&gt;
&lt;br /&gt;
отладчик разместит ее в строке 157. Дело в том, что строке 155 (как и строке 156) нельзя сопоставить машинный код. Первая строка после строки 155, для которой это можно сделать – строка 157, но она находится в другом логическом блоке. Очевидно, что это совсем не то, чего мы хотели. Самое неприятное заключается в том, что отладчик не покажет нам номер строки, на которой на самом деле была создана точка останова, до тех пор, пока эта точка не будет вызвана. Правильным решением может быть создание новой точки останова в строке 154, но в этом случае программа будет приостановлена до вызова функции '''CSTR_GetPrev()'''. Если нам нужно отследить результат выполнения '''CSTR_GetPrev()''', точку останова следует создавать внутри этой функции (можно, конечно, остановиться до вызова '''CSTR_GetPrev()''', а затем пройтись по функции серией команд '''step''').&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Заголовок=Назад, в будущее|Содержание=В ряде случаев бывает удобным проходить программу не только в прямом порядке, но и в обратном, «оборачивая время вспять». Некоторые ошибки очень сложно вызвать, и если она все же случилась, появляется большое желание развернуть ход выполнения программы в обратном направлении и поглядеть, что же к ней привело. Такой возможностью обладает отладчик ''UndoDB'' (http://www.undodb.com). Увы, это не свободное ПО, но если вы работаете над открытым проектом, то сможете получить лицензию бесплатно. Приятнее всего то, что ''UndoDB'' является надстройкой над ''GDB'' и просто добавляет новые команды, не изменяя старые, так что вам не придется переучиваться.|Ширина=200px}}&lt;br /&gt;
&lt;br /&gt;
Помимо локаций, команда '''break''' позволяет задать для точки останова условие. Им может быть любое выражение, возвращающее значение, приводимое к типу '''int''' и действительное в контексте данного кадра отладки. Вы можете создать несколько точек останова в одной строке (это имеет смысл для условных точек останова).&lt;br /&gt;
&lt;br /&gt;
Если вы не хотите больше прерывать выполнение программы на текущей точке останова, очистите ее с помощью команды '''clear'''. Любую точку останова можно удалить с помощью команды '''delete''', указав в качестве аргумента номер точки останова (он присваивается автоматически при выполнении команды '''break'''). Если вы заранее уверены, что точка останова понадобится вам только один раз, создайте однократную точку останова с помощью команды '''tbreak''' (ее синтаксис такой же, как и у '''break''').&lt;br /&gt;
&lt;br /&gt;
===Предъявите ваши данные===&lt;br /&gt;
&lt;br /&gt;
С некоторыми командами, позволяющими заглянуть в содержимое переменных отлаживаемой программы, мы уже знакомы. Когда выполнение программы приостановлено, мы можем просмотреть содержимое любой переменной, доступной в данном контексте. Очень часто в процессе отладки бывает необходимо отследить, как меняется значение некоторой переменной по ходу выполнения программы. Чтобы не вызывать каждый раз команду '''print''', мы можем создать контрольную точку доступа к данным ('''watch''').&lt;br /&gt;
&lt;br /&gt;
Рассмотрим практический пример. В программе ''Cuneiform'' есть функция '''make_tokens''', которая в ходе своей работы перебирает элементы некоего связного списка. Указатель на текущий элемент списка хранится в локальной переменной '''rast'''. В ходе отладки программы мне требовалось посмотреть, как меняются значения '''rast''', для чего я решил создать контрольную точку доступа к данным. Такие точки осуществляют мониторинг обращения&lt;br /&gt;
к определенному адресу памяти на аппаратном уровне. Это означает, между прочим, что контрольную точку доступа нельзя определить до тех пор, пока наблюдаемая переменная не будет создана, то есть, в нашем примере, до тех пор, пока не будет вызвана функция '''make_tokens'''. Таким образом, прежде чем устанавливать контрольную точку доступа, мне необходимо остановить программу в начале вызова '''make_tokens''':&lt;br /&gt;
&lt;br /&gt;
 (gdb) break make_tokens&lt;br /&gt;
 (gdb) c&lt;br /&gt;
 Breakpoint 16, make_tokens (line=0x957a108, words=0xbf867b98) at /home/andrei/bazaar/cuneiform-multilang/cuneiform_src/Kern/puma/c/spcheck.cpp:140&lt;br /&gt;
 140 CSTR_rast rast=CSTR_GetFirstRaster(line);&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF120_75_1.jpg|300px]] ''Qt Creator'' (мы говорили о нем в [[LXF119:Review4|LXF119]]) — отладка доверена ''GDB''. Обратите внимание, где расположена точка останова и где программа остановилась на самом деле.|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
Теперь можно установить контрольную точку доступа к переменной '''rast''':&lt;br /&gt;
&lt;br /&gt;
 (gdb) watch rast&lt;br /&gt;
 Hardware watchpoint 17: rast&lt;br /&gt;
&lt;br /&gt;
Обратите внимание, что значение '''rast''' изменяется в той самой строке (140), на которой было приостановлено выполнение программы. Это значит, что уже следующий вызов '''next''' приведет к изменению содержимого переменной:&lt;br /&gt;
&lt;br /&gt;
 (gdb) n&lt;br /&gt;
 Hardware watchpoint 17: rast&lt;br /&gt;
 Old value = (CSTR_rast) 0x0&lt;br /&gt;
 New value = (CSTR_rast) 0x957a19c&lt;br /&gt;
&lt;br /&gt;
Отладчик сообщает нам, что значение '''rast''' изменилось с 0x0 на 0x957a19c. Ниже показан дальнейший результат пошагового выполнения функции:&lt;br /&gt;
&lt;br /&gt;
 142 bool wb = true;&lt;br /&gt;
 (gdb) n&lt;br /&gt;
 143 int wc = 0;&lt;br /&gt;
 (gdb) n&lt;br /&gt;
 144 for(rast = CSTR_GetNext(rast);rast;rast=CSTR_GetNext(rast))&lt;br /&gt;
 (gdb) n&lt;br /&gt;
 Hardware watchpoint 17: rast&lt;br /&gt;
 Old value = (CSTR_rast) 0x957a19c&lt;br /&gt;
 New value = (CSTR_rast) 0x95776d0&lt;br /&gt;
&lt;br /&gt;
Мы видим, что при входе в цикл '''for''' значение '''rast '''(которая является его управляющей переменной) тоже изменилось. Если бы значение '''rast''' было случайно перезаписано где-то между двумя явными обращениями к переменной, отладчик сообщил бы нам об этом.&lt;br /&gt;
&lt;br /&gt;
Установленная нами контрольная точка существует столько же, сколько и переменная '''rast''', то есть до выхода из функции '''make_tokens''': при следующем вызове '''make_tokens''' ее придется создавать снова. Для удаления контрольных точек доступа служит уже известная нам команда '''delete'''.&lt;br /&gt;
&lt;br /&gt;
Отслеживать изменение содержимого переменной с помощью комбинации команд '''watch''' и '''step/next''' не очень-то удобно. У отладчика GNU есть другой, лучший способ. Команда '''awatch''' будет останавливать выполнение программы всякий раз, когда значение заданной переменной считывается или записывается. Так же, как и '''watch''', команда '''awatch''' стремится использовать аппаратные ловушки для перехвата обращений к конкретному адресу и может выявлять неявные обращения к нему.&lt;br /&gt;
&lt;br /&gt;
===Как я сюда попала?===&lt;br /&gt;
&lt;br /&gt;
Иногда программисты тоже пытаются найти ответ на этот сакраментальный вопрос. Если в программе во время отладки происходит нечто, требующее вашего внимания, вам может понадобится не только информация о функции, при вызове которой случилось страшное, но и сведения о полном состоянии стека вызовов. Команда '''backtrace''' позволяет узнать, какими путями программа попала в данную точку. Посмотрим результат ее выполнения для многострадальной функции '''copy_text''' (предполагается, что выполнение программы ''Cuneiform'' приостановлено в ее начале):&lt;br /&gt;
&lt;br /&gt;
 (gdb) backtrace&lt;br /&gt;
 #0 copy_text (word=0x983d348) at /home/andrei/bazaar/cuneiform-multilang/cuneiform_src/Kern/puma/c/spcheck.cpp:85&lt;br /&gt;
 #1 0xb7f213ff in make_tokens (line=0x9789278, words=0xbff78a88) at /home/andrei/bazaar/cuneiform-multilang/cuneiform_src/Kern/puma/c/spcheck.cpp:172&lt;br /&gt;
 #2 0xb7f2158e in mix_lines (ruseng=0x9789278, local=0x97af118, rus=0x9794578) at /home/andrei/bazaar/cuneiform-multilang/cuneiform_src/Kern/puma/c/spcheck.cpp:369&lt;br /&gt;
 #3 0xb7f1eeaf in MultilangRecognizeStringsPass1 () at /home/andrei/bazaar/cuneiform-multilang/cuneiform_src/Kern/puma/c/partrecog.cpp:425&lt;br /&gt;
 #4 0xb7f1fb55 in Recognize () at /home/andrei/bazaar/cuneiform-multilang/cuneiform_src/Kern/puma/c/partrecog.cpp:798&lt;br /&gt;
 #5 0xb7f226f7 in PUMA_XFinalRecognition () at /home/andrei/bazaar/cuneiform-multilang/cuneiform_src/Kern/puma/main/puma.cpp:600&lt;br /&gt;
 #6 0x0804ad18 in?? ()&lt;br /&gt;
 #7 0xb7463685 in __libc_start_main () from /lib/tls/i686/cmov/libc.so.6&lt;br /&gt;
 #8 0x08049fb1 in?? ()&lt;br /&gt;
&lt;br /&gt;
В переводе на русский язык сказанное отладчиком звучит так: «Функция '''PUMA_XFinalRecognition ()''', вызванная из функции верхнего уровня, вызвала функцию '''Recognize ()''', которая вызвала функцию '''MultilangRecognizeStringsPass1 ()''', которая вызвала функцию '''mix_lines ()''', которая вызвала функцию '''make_tokens ()''', которая и вызвала функцию '''copy_text()'''». Но это не все. Благодаря команде '''backtrace''' мы можем узнать не только адреса функций и значения их параметров (они приведены в скобках), но и локации вызовов в исходных текстах программы ('''copy_text''' вызывается в нескольких разных местах функции '''make_tokens()''', и нам, разумеется, полезно знать, из какого именно места она была вызвана на этот раз). Не могу не отметить, что команда '''backtrace''' помогает не только при отладке кода, но и при изучении работы программы, написанной другими людьми. Фактически у нас перед глазами «живая» цепочка вызовов функций в сложной программе, снабженная значениями их аргументов и другими полезными сведениями.&lt;br /&gt;
&lt;br /&gt;
===Графический отладчик ''DDD''===&lt;br /&gt;
&lt;br /&gt;
{{Врезка|Содержание=[[Изображение:LXF120_75_2.jpg|300px]] Отладчик ''DDD'' — тонкий слой графики поверх ''GDB''|Ширина=300px}}&lt;br /&gt;
&lt;br /&gt;
Из всех графических отладчиков, использующих ''GDB'', мы рассмотрим только ''DDD''. Такая честь выпала ему потому, что этот отладчик наиболее прозрачно интегрирован с ''GDB''. Основные команды графической оболочки соответствуют командам ''GDB'', а в нижней части главного окна ''DDD'' мы видим фрагмент консоли ''GDB'', в которой отображаются вывод отладчика GNU и его командная строка. Таким образом, если возможностей ''DDD'' вам не хватает, вы всегда можете обратиться к отладчику ''GDB'' напрямую. Но главное преимущество ''DDD'' по сравнению с «чистым» ''GDB'' – это возможность легко ориентироваться в исходных текстах программы. '''LXF'''&lt;/div&gt;</summary>
		<author><name>Crazy Rebel</name></author>	</entry>

	</feed>