2013-10-25 2 views
0

У меня следующий цикл, и мой код ломается, но я не знаю, на какой итерации он точно разрывается.Как использовать GDB внутри гигантских петель

int n=1000; 
for (i=0; i<n; i++) { 
       slot = random() % max_allocs; 
       doAlloc = random() % 4; 
       doWrite = writeData; 

       if (!doAlloc || ptr[slot] != NULL) { 
         if (ptr[slot] == NULL) 
           ;//assert(Mem_Free(ptr[slot]) == -1); 
         else 
         { 
           printf("I got here \n"); 
           printf("mem free ptr slot is %d \n",Mem_Free(ptr[slot])); 
         } 
         free(shadow[slot]); 
         ptr[slot] = NULL; 
         shadow[slot] = NULL; 
       } 

       if (doAlloc) { 
         size[slot] = min_alloc_size + 
           (random() % (max_alloc_size - min_alloc_size + 1)); 
         printf("size[slot] :%d\n", size[slot]); 
         ptr[slot] = Mem_Alloc(size[slot], BESTFIT); 
         printf("ptr slot is %p \n",ptr[slot]); 
         assert(ptr[slot] != NULL); 
         if (doWrite) { 
           shadow[slot] = malloc(size[slot]); 
           int j; 
           for (j=0; j<size[slot]; j++) { 
             char data = random(); 
             *((char*)(ptr[slot] + j)) = data; 
             *((char*)(shadow[slot] + j)) = data; 
           } 
         } 
       } 
     } 

Как я могу найти на котором итерации п кодовых перерывов и как я могу поставить точку останова на этой итерации?

P.S .: Есть ли какой-либо другой лучший отладчик для этой цели в Linux? (Если я не хочу использовать Eclipse,!)

Вот ошибка я получаю в БГД:

mymain: mymain.c:104: main: Assertion `ptr[slot] != ((void *)0)' failed. 

Program received signal SIGABRT, Aborted. 
0x000000368da328e5 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 
64 return INLINE_SYSCALL (tgkill, 3, pid, selftid, sig); 
(gdb) backtrace 
#0 0x000000368da328e5 in raise (sig=6) at ../nptl/sysdeps/unix/sysv/linux/raise.c:64 
#1 0x000000368da340c5 in abort() at abort.c:92 
#2 0x000000368da2ba0e in __assert_fail_base (fmt=<value optimized out>, assertion=0x40114b "ptr[slot] != ((void *)0)", file=0x401142 "mymain.c", line=<value optimized out>, function=<value optimized out>) 
    at assert.c:96 
#3 0x000000368da2bad0 in __assert_fail (assertion=0x40114b "ptr[slot] != ((void *)0)", file=0x401142 "mymain.c", line=104, function=0x401199 "main") at assert.c:105 
#4 0x0000000000400e2a in main (argc=4, argv=0x7fffffffdb68) at mymain.c:104 
(gdb) frame 1 
#1 0x000000368da340c5 in abort() at abort.c:92 
92  raise (SIGABRT); 
(gdb) frame 3 
#3 0x000000368da2bad0 in __assert_fail (assertion=0x40114b "ptr[slot] != ((void *)0)", file=0x401142 "mymain.c", line=104, function=0x401199 "main") at assert.c:105 
105 __assert_fail_base (_("%s%s%s:%u: %s%sAssertion `%s' failed.\n%n"), 
+1

Я считаю, что 'gdb' может печатать значения переменных, печатать переменную взаимодействия ... – Kninnug

+0

Я знаю это. Проблема в том, что я не знаю, при какой итерации код ломается. –

+2

@MonaJalal, но если вы напечатаете переменную 'i', вы увидите, какая она итерация. Итак, в gdb введите 'p i' – nos

ответ

2

посмотрите на это: GDB Tutorial. Вы можете использовать перерыв (чтобы установить контрольную точку) и продолжают/следующий делать то, что вы хотите:

  1. Не забудьте компилировать с опцией -g: Gcc -g источника. с
  2. GDB ./a.out
  3. перерывномер_строки
  4. продолжает или следующий (перейти к следующей контрольной точке)
  5. печатьпеременной (напечатать значение переменной )

Надеется, что это помогает.

+0

, проблема в том, что я не знаю, на какой итерации выполняется выполнение кода! Кроме того, что я нашел, как поставить точку останова на определенной строке, например, на 500-й итерации, но это не помогает моему делу. –

+0

Какое сообщение об ошибке вы получаете? GDB должен отображать явное сообщение об ошибке, такое как «Программный принятый сигнал SIGSEGV, ошибка сегментации». 0x08048464 в main() на test-gdb.c: 12 "=>, поэтому в строке 12 (например) есть проблема. Вы можете добавить printfs, чтобы проследить, где находится код: printf("i = %d", i); //at the end of your loop. kukinsula

+0

спасибо. Я отредактировал сообщение и добавил ошибку, которую я получаю. Также спасибо за подсказку. Я просто печатаю итерацию, на которой он ломается. –

1

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

б 94, если я = 500

обычно вы бы сказали:

break line_number, если условие

1

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

Запустите вашу программу в GDB, дождитесь, пока код не сработает (в какой момент GDB возьмет его), а затем выработайте, с какой итерацией он разбился, распечатав значение индексной переменной с помощью print i в приглашении GDB.

Редактировать: Ок, я думаю, я понимаю. Когда вы говорите, что код «ломается», вы имеете в виду, что он ломается таким образом, что позволяет ему продолжать выполняться: он не сбой, и GDB автоматически не поймает его.

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

Вы можете сделать это, используя опцию commands. Вот пример того, как это сделать в потоке this.

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

3

Откуда вы знаете, что код «ломается» в первую очередь? Обычно это потому, что какая-то переменная внезапно принимает значение, которого вы не ожидаете. В этом случае вы можете установить точку наблюдения , а не точку останова, и она будет ломаться тогда и только тогда, когда эта переменная выходит за рамки ожиданий.

Например, с помощью этой программы:

#include <stdio.h> 

int main(void) { 
    int b = 0; 
    for (int i = 0; i < 20; ++i) { 
     b += 5; 
    } 
    return 0; 
} 

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

[email protected]:~/src/c/scratch$ gdb testwatch 
GNU gdb (GDB) 7.4.1-debian 
Copyright (C) 2012 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law. Type "show copying" 
and "show warranty" for details. 
This GDB was configured as "x86_64-linux-gnu". 
For bug reporting instructions, please see: 
<http://www.gnu.org/software/gdb/bugs/>... 
Reading symbols from /home/paul/src/c/scratch/testwatch...done. 
(gdb) list 
1  #include <stdio.h> 
2 
3  int main(void) { 
4   int b = 0; 
5   for (int i = 0; i < 20; ++i) { 
6    b += 5; 
7   } 
8   return 0; 
9  } 
(gdb) break 5 
Breakpoint 1 at 0x400567: file testwatch.c, line 5. 
(gdb) run 
Starting program: /home/paul/src/c/scratch/testwatch 

Breakpoint 1, main() at testwatch.c:5 
5   for (int i = 0; i < 20; ++i) { 
(gdb) watch b > 20 
Hardware watchpoint 2: b > 20 
(gdb) continue 
Continuing. 
Hardware watchpoint 2: b > 20 

Old value = 0 
New value = 1 
main() at testwatch.c:5 
5   for (int i = 0; i < 20; ++i) { 
(gdb) print b 
$1 = 25 
(gdb) print i 
$2 = 4 
(gdb) 

Здесь мы можем указать, что b прошел выше 20, когда i был 4, т.е. на пятой итерации цикла. Вы можете наблюдать за целыми выражениями, такими как watch b > 20 && i > 10, для поиска комбинаций значений, которые вы не ожидаете одновременно. gdb довольно мощный, когда вы входите в него.

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

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

EDIT: Начиная с обновления вашего сообщения, в вашем конкретном случае вы можете просто использовать backtrace и получить право на итерацию, например.

[email protected]:~/src/c/scratch$ gdb segfault 
GNU gdb (GDB) 7.4.1-debian 
Copyright (C) 2012 Free Software Foundation, Inc. 
License GPLv3+: GNU GPL version 3 or later <http://gnu.org/licenses/gpl.html> 
This is free software: you are free to change and redistribute it. 
There is NO WARRANTY, to the extent permitted by law. Type "show copying" 
and "show warranty" for details. 
This GDB was configured as "x86_64-linux-gnu". 
For bug reporting instructions, please see: 
<http://www.gnu.org/software/gdb/bugs/>... 
Reading symbols from /home/paul/src/c/scratch/segfault...done. 
(gdb) list 1,16 
1  #include <stdlib.h> 
2 
3  void segfault(int * p) { 
4   int n = *p; 
5  } 
6 
7  int main(void) { 
8   int n = 0; 
9   int * parray[] = {&n, &n, &n, &n, NULL}; 
10 
11   for (int i = 0; i < 10; ++i) { 
12    segfault(parray[i]); 
13   } 
14 
15   return 0; 
16  } 
(gdb) run 
Starting program: /home/paul/src/c/scratch/segfault 

Program received signal SIGSEGV, Segmentation fault. 
0x0000000000400568 in segfault (p=0x0) at segfault.c:4 
4   int n = *p; 
(gdb) backtrace 
#0 0x0000000000400568 in segfault (p=0x0) at segfault.c:4 
#1 0x00000000004005c1 in main() at segfault.c:12 
(gdb) frame 1 
#1 0x00000000004005c1 in main() at segfault.c:12 
12    segfault(parray[i]); 
(gdb) print i 
$1 = 4 
(gdb) 

В вашем случае, вы пошли бы к тому, что frame соответствует функциям вашего цикл находится, и просто сделать print i, чтобы получить индекс цикла.

+0

Можете ли вы проверить мой отредактированный пост? Я написал, что «backtrace» дает мне. Знаете ли вы, что вызывает проблему? –

+1

Да, проблема в том, что это утверждение не выполняется: 'assert (ptr [slot]! = NULL);'. В этот момент в вашей программе 'ptr [slot]' явно равен «NULL», поэтому ваша программа прерывается, потому что вы сказали это. Так как это происходит сразу после 'ptr [slot] = Mem_Alloc (size [slot], BESTFIT);', похоже, ваша функция распределения памяти возвращает 'NULL'. –

+1

Использование gdb не было необходимо, чтобы сказать вам, что, между прочим. Сообщение 'mymain: mymain.c: 104: main: Assertion 'ptr [slot]! = ((Void *) 0)' failed. 'Рассказал вам все, что вам нужно было знать, чтобы выяснить, что происходит не так. –

1

От gdb's documentation 5.1.7 "Breakpoint Command Lists":

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

Таким образом, вы можете установить точку останова в цикле, которая отображает значение итерации, i, каждый раз, когда он попадает.Таким образом, когда вы аварии вы можете увидеть последнее значение напечатал:

break <line number just after start of the loop> 
commands 
silent 
printf "i == %d\n", i 
continue 
end 

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

Смежные вопросы