Wiki

Пример сеанса GDB

Вы можете пользоваться этим руководством в свое удовольствие, чтобы прочитать о GDB все. Однако, достаточно небольшого количества команд, чтобы начать пользоваться отладчиком. Эта глава иллюстрирует эти команды.

В этом примере сеанса мы выделяем ввод пользователя так: ввод, чтобы его было проще отличить от находящегося рядом вывода программы.

В одной из предварительных версий программы GNU m4 (настраиваемый макропроцессор), была допущена следующая ошибка: иногда, при замене строк, определяющих кавычки, со значений по умолчанию, команды, использовавшиеся для поиска одного макроопределения внутри другого, прекращали работать. В следующем коротком сеансе m4, мы
определим макрос foo, который расширяется до 0000; затем мы используем встроенную процедуру m4 defn, чтобы определить bar точно также. Однако, когда мы изменим открывающую кавычку на <QUOTE>, а закрывающую на <UNQUOTE>, та же самая процедура не сможет определить новый синоним baz:

   $ <B>cd gnu/m4</B>
   $ <B>./m4</B>
   <B>define(foo,0000)</B>
 
   <B>foo</B>
   0000
   <B>define(bar,defn(`foo'))</B>
 
   <B>bar</B>
   0000
   <B>changequote(&#60;QUOTE&#62;,&#60;UNQUOTE&#62;)</B>
 
   <B>define(baz,defn(&#60;QUOTE&#62;foo&#60;UNQUOTE&#62;))</B>
   <B>baz</B>
   <B>C-d</B>
   m4: End of input: 0: fatal error: EOF in string 2</A>

Попытаемся с помощью GDB понять, что же происходит.
   $ <B>gdb m4</B>
   GDB is free software and you are welcome to distribute copies
      of it under certain conditions; type "show copying" to see
      the conditions.
      There is absolutely no warranty for GDB; type "show warranty"
       for details.
 
   GDB 5.0, Copyright 1999 Free Software Foundation, Inc...
     (gdb)

GDB читает только минимум символьных данных, достаточный для того, чтобы знать, где в случае
необходимости искать остальные; в результате первое приглашение появляется очень быстро. Теперь мы велим GDB использовать меньшую ширину экрана, чем обычно, чтобы примеры умещались на страницах этого руководства.
  (gdb) <B>set width 70</B>

Нам необходимо увидеть, как работает встроенная процедура m4 changequote. Посмотрев сходный текст, мы знаем, что соответствующей подпрограммой является m4_changequote, так что мы устанавливаем там точку останова с помощью команды GDB break.
   (gdb) <B>break m4_changequote</B>
   Breakpoint 1 at 0x62f4: file builtin.c, line 879.

Используя комманду run, мы запускаем m4 под управлением GDB; до тех пор, пока управление не достигло подпрограммы m4_changequote, программа выполняется как обычно:
   (gdb) <B>run</B>
   Starting program: /work/Editorial/gdb/gnu/m4/m4
   <B>define(foo,0000)</B>
 
   <B>foo</B>
   0000

Чтобы активировать точку останова, мы вызываем changequote. GDB приостанавливает выполнение m4, выводя на экран информацию о том месте, где он остановился.
   <B>changequote(&#60;QUOTE&#62;,&#60;UNQUOTE&#62;)</B>
 
   Breakpoint 1, m4_changequote (argc=3, argv=0x33c70)
       at builtin.c:879
   879         if (bad_argc(TOKEN_DATA_TEXT(argv[0]),argc,1,3))

Теперь мы используем команду n (next), чтобы продолжить выполнение до следующей строки текущей функции.
   (gdb) <B>n</B>
   882         set_quotes((argc &#62;= 2) ? TOKEN_DATA_TEXT(argv[1])\
    : nil,

set_quotes выглядит как нужная нам подпрограмма. Мы можем войти в нее, используя команду s (step) вместо next. step переходит на следующую исполняемую строку любой подпрограммы, так что она входит в set_quotes.
   (gdb) <B>s</B>
   set_quotes (lq=0x34c78 "&#60;QUOTE&#62;", rq=0x34c88 "&#60;UNQUOTE&#62;")
       at input.c:530
   530         if (lquote != def_lquote)

Отображение, показывающее подпрограмму (и ее параметры), где m4 сейчас приостановлен, называется отображением кадра стека. Оно показывает обзор стека. Мы можем использовать команду backtrace (которая может сокращаться как bt), чтобы посмотреть, в каком месте стека мы находимся: команда backtrace выводит кадр стека для каждой активной подпрограммы.
   (gdb) <B>bt</B>
   #0  set_quotes (lq=0x34c78 "&#60;QUOTE&#62;", rq=0x34c88 "&#60;UNQUOTE&#62;")
       at input.c:530
   #1  0x6344 in m4_changequote (argc=3, argv=0x33c70)
    at builtin.c:882
   #2  0x8174 in expand_macro (sym=0x33320) at macro.c:242
   #3  0x7a88 in expand_token (obs=0x0, t=209696, td=0xf7fffa30)
       at macro.c:71
   #4  0x79dc in expand_input () at macro.c:40
   #5  0x2930 in main (argc=0, argv=0xf7fffb20) at m4.c:195

Чтобы посмотреть, что же происходит, мы проходим по шагам еще несколько строк. Первые два раза мы можем использовать `s'; следующие два раза мы пользуемся командой n, чтобы избежать вхождения в подпрограмму xstrdup.
   (gdb) <B>s</B>
   0x3b5c  532         if (rquote != def_rquote)
   (gdb) <B>s</B>
   0x3b80  535         lquote = (lq == nil || *lq == '\0') ?  \
   def_lquote : xstrdup(lq);
   (gdb) <B>n</B>
   536         rquote = (rq == nil || *rq == '\0') ? def_rquote\
    : xstrdup(rq);
   (gdb) <B>n</B>
   538         len_lquote = strlen(rquote);

Последняя выведенная строка выглядит несколько странно; мы можем исследовать переменные lquote и rquote, чтобы понять, действительно ли это определенные нами новые левая и правая кавычки. Мы используем команду p (print), чтобы посмотреть их значения.
   (gdb) <B>p lquote</B>
   $1 = 0x35d40 "&#60;QUOTE&#62;"
   (gdb) <B>p rquote</B>
   $2 = 0x35d50 "&#60;UNQUOTE&#62;"

Действительно, lquote и rquote являются новыми кавычками. Для просмотра контекста, мы можем вывести десять строк исходного текста, окружающих текущую строку, используя команду l (list).
	(gdb) <B>l</B>
	533             xfree(rquote);
	534
	535         lquote = (lq == nil || *lq == '\0') ? def_lquote\
	: xstrdup (lq);
	536         rquote = (rq == nil || *rq == '\0') ? def_rquote\
	: xstrdup (rq);
	537
	538         len_lquote = strlen(rquote);
	539         len_rquote = strlen(lquote);
	540     }
	541
	542     void

Давайте пройдем еще две строки, которые устанавливают len_lquote и len_rquote, и затем исследуем значения этих переменных.
	(gdb) <B>n</B>
	539         len_rquote = strlen(lquote);
	(gdb) <B>n</B>
	540     }
	(gdb) <B>p len_lquote</B>
	$3 = 9
	(gdb) <B>p len_rquote</B>
	$4 = 7

Это, очевидно, неправильно, так как len_lquote и len_rquote обозначают длины переменных lquote и rquote соответственно. Мы можем присвоить им лучшие значения, используя команду p, так как она может выводить значение любого выражения, а выражение может содержать вызовы подпрограмм и присваивания.
	(gdb) <B>p len_lquote=strlen(lquote)</B>
	$5 = 7
	(gdb) <B>p len_rquote=strlen(rquote)</B>
	$6 = 9

Достаточно ли этого, чтобы решить проблему использования новых кавычек во встроенной процедуре m4 defn? Мы можем продолжить выполнение m4 командой c (continue), и затем попробовать пример, первоначально вызывавший ошибку:
	(gdb) <B>c</B>
	Continuing.
 
	<B>define(baz,defn(&#60;QUOTE&#62;foo&#60;UNQUOTE&#62;))</B>
 
	baz
	0000

Успех! Теперь новые кавычки работают так же хорошо, как и стандартные. Кажется, проблема заключалась лишь в двух опечатках, приводивших к неправильному определению длин. Мы позволим m4 выйти, подавая ему на вход EOF:
	<B>C-d</B>
	Program exited normally.(3)

Сообщение `Program exited normally.' исходит от GDB; оно показывает, что m4 закончил выполнение. Мы можем завершить наш сеанс работы с GDB командой quit.
	(gdb) <B>quit</B>