c - 如何在巨型循环中使用 GDB

标签 c linux debugging gdb breakpoints

我有以下循环,我的代码中断了,但我不知道它在哪一次迭代中中断了。

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;
                                }
                        }
                }
        }

如何找到代码在第 n 次迭代中中断的位置以及如何在该迭代中放置断点?

P.S.:在 Linux 中是否有其他更好的调试器用于此目的? (如果我不想使用 Eclipse!)

这是我在 gdb 中收到的错误:

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"),

最佳答案

您怎么知道代码首先“损坏”了?通常是因为某些变量突然取了您不期望的值。在这种情况下,您可以设置一个观察点而不是断点,当且仅当该变量超出预期时它才会中断。

例如,对于这个程序:

#include <stdio.h>

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

我们可以让 gdb 在 b 达到或超过某个值时停止,并找出它发生在循环的确切迭代中:

paul@local:~/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)

这里我们可以看出当 i4 时,b 超过了 20,即在第五次迭代中的循环。您可以观察整个表达式,例如 watch b > 20 && i > 10,以查找您不希望同时为真的值的组合。当您开始使用 gdb 时,它非常强大。

您可以观察一个变量变成一个特定的值,或者一个指针变成 NULL,或者一个范围计数器超过数组的最后一个元素,或者任何其他导致您的代码被破坏的情况。一旦它停止,您就会确切地知道错误发生的时间点,并且您可以四处查看其他变量以找出问题所在。

一般来说,如果您在使用调试器之前必须知道错误发生的位置和时间,那么调试器就不会那么有用。

编辑:由于更新了您的帖子,在您的特定情况下,您可以只使用 backtrace 并直接进行迭代,例如

paul@local:~/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 以获取循环索引。

关于c - 如何在巨型循环中使用 GDB,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/19600293/

相关文章:

c - 同时读取和写入变量

linux - 编写修改 gcc c 编译器的 bash 脚本

linux - bash with ssh 和 for i 语句

将 php 应用程序从 linux 系统移动到一个正在运行的带有 wamp 的 Windows 7 时,php define 语句失败

php - Yii 即使在 Debug模式下也显示标准错误

c - copy_from_user 调用中对目标参数的声明和内存分配

c - 如何从c中的另一个结构访问指向一个结构的双指针

objective-c - 如何符号化用户通过电子邮件发送给我的 Mac OS X 应用程序的崩溃报告?

javascript - 有没有办法从 Internet Explorer 中的错误对象获取行号或堆栈跟踪?

c - 我无法在 else 语句中使用 scanf()