简体   繁体   English

如何在巨型循环中使用GDB

[英]How to use GDB inside giant loops

I have the following loop and my code breaks but I don't know at which iteration it breaks exactly. 我有以下循环,我的代码中断了,但是我不知道它在哪一次迭代中完全中断了。

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

How can I find at which iteration of n the code breaks and how can I put a breakpoint at that iteration? 如何找到代码在n的哪个迭代处中断,以及如何在该迭代处放置断点?

PS: Is there any other better debugger for this purpose in Linux? PS:在Linux中,还有其他更好的调试器可用于此目的吗? (If I don't want to use Eclipse!) (如果我不想使用Eclipse!)

Here's the error I am receiving in gdb: 这是我在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"),

How do you know the code is "breaking" in the first place? 您怎么知道代码首先是“中断”的? Usually it's because some variable suddenly takes on a value you don't expect. 通常是因为某个变量突然具有您不期望的值。 In this case, you can set a watchpoint rather than a breakpoint, and it'll break when and only when that variable goes outside of expectations. 在这种情况下,您可以设置观察点而不是断点,并且当且仅当该变量超出期望时,它才会中断。

For instance, with this program: 例如,使用此程序:

#include <stdio.h>

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

we can get gdb to stop when b hits or exceeds a certain value, and find out on exactly which iteration of the loop it occurred: 我们可以让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)

Here we can tell that b went above 20 when i was 4 , ie on the fifth iteration of the loop. 在这里,我们可以知道当i 4岁时,即循环的第五次迭代时b超过了20 You can watch for whole expressions, such as watch b > 20 && i > 10 , to look for combinations of values that you don't expect to be simultaneously true. 您可以监视整个表达式,例如watch b > 20 && i > 10 ,以查找不希望同时为真的值的组合。 gdb is pretty powerful when you get into it. 当您进入gdb时,它是非常强大的。

You can watch for a variable becoming a particular value, or a pointer becoming NULL, or a range counter going past the last element of your array, or whatever other condition is resulting in your code being broken. 您可以观察变量变为特定值,或指针变为NULL,或者范围计数器经过数组的最后一个元素,或者其他任何情况导致代码损坏。 Once it stops, you'll know exactly the point at which your error occurs, and you can poke around looking at other variables to figure out what's going wrong. 一旦停止,您将确切知道错误发生的地点,并且可以四处查看其他变量以找出问题所在。

In general, a debugger wouldn't be all that useful if you had to know where and when an error was occurring before you could use it. 通常,如果在使用调试器之前必须知道发生错误的位置和时间,那么调试器就不会有用。

EDIT: Since updating your post, in your particular case, you can just use backtrace and get right to the iteration, eg 编辑:由于更新您的帖子,在您的特定情况下,您可以只使用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)

In your case, you'd go to whatever frame corresponds to the function your loop is in, and just do print i to get the loop index. 在您的情况下,您将转到与循环所处功能相对应的任何frame ,然后执行print i以获取循环索引。

take a look at this: GDB Tutorial . 看看这个: GDB教程 You can use break (to set a breakpoint) and continue / next to do what you want: 您可以使用break (设置断点)并继续 / 下一步执行您想要的操作:

  1. Don't forget to compile with -g option: gcc -g source.c 不要忘记使用-g选项进行编译: gcc -g source.c
  2. gdb ./a.out gdb ./a.out
  3. break linenumber 打破 行号
  4. continue or next (to proceed to the next breakpoint) 继续下一个 (继续到下一个断点)
  5. print variable (to print the value of variable ) 打印 变量 (打印变量的值)

Hope it helps. 希望能帮助到你。

If I want to set a breakpoint at line 94 when I am in the 500th iteration I should do it like this: 如果我想在第500次迭代时在第94行设置一个断点,我应该这样做:

b 94 if i=500 b 94如果i = 500

generally you would say: 通常您会说:

break line_number if condition 如果有条件则中断line_number

You seem to be hung up on finding the iteration on which it breaks, but the answer from nos , above, clearly states how to do this. 您似乎很想找到中断它的迭代,但是上面nos的答案清楚地说明了如何执行此操作。

Run your program in GDB, wait for the code to crash (at which point GDB will grab it), and then work out which iteration it's crashed in by printing the value of the index variable using print i at the GDB prompt. 在GDB中运行程序,等待代码崩溃(这时GDB将抓住它),然后通过在GDB提示符下使用print i索引变量的值来确定崩溃的迭代次数。

Edit: Ok, I think I understand. 编辑:好的,我想我明白。 When you say the code "breaks", you mean it's breaking in such a way that allows it to continue to be executed: it's not crashing, and GDB isn't automatically catching it. 当您说代码“中断”时,是指它以允许其继续执行的方式进行中断:它没有崩溃,并且GDB不会自动捕获它。

In this case, there's no way to determine where to set the breakpoint you want. 在这种情况下,无法确定要在何处设置断点。 You simply don't know when the problem is occurring. 您根本不知道问题何时发生。 How are you determining that the program is breaking? 您如何确定程序正在中断? Are there any variables you could print the value of to show when the breakage occurs? 您是否可以打印任何变量以显示破损发生的时间? If so, you could have GDB print the values during each iteration (rather than writing debug directly into the code). 如果是这样,您可以让GDB在每次迭代期间打印这些值(而不是直接将调试写入代码中)。

You can do this using the commands option. 您可以使用commands选项执行此commands There's an example of how to do this in this thread. 线程中有一个如何执行此操作的示例。

On each iteration print the value of i and also the value of whichever variable you're using to track the breakage. 在每次迭代中,打印i的值以及用于跟踪破损的任何变量的值。 This should then give you the iteration on which the breakage occurs, and you can go back and set a breakpoint in the right place. 然后,这应该为您提供发生破损的迭代,并且您可以返回并在正确的位置设置断点。

From gdb's documentation 5.1.7 "Breakpoint Command Lists" : gdb文档5.1.7“断点命令列表”中

You can give any breakpoint (or watchpoint or catchpoint) a series of commands to execute when your program stops due to that breakpoint. 您可以为任何断点(或观察点或捕获点)提供一系列命令,以在程序由于该断点而停止时执行。 For example, you might want to print the values of certain expressions, or enable other breakpoints. 例如,您可能要打印某些表达式的值,或启用其他断点。

So you can set a breakpoint in the loop that displays the iteration value, i , each time it is hit. 因此,您可以在循环中设置一个断点,以在每次命中时显示迭代值i That way when you crash you can see the last value printed: 这样,当您崩溃时,您可以看到最后打印的值:

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

Of course there are other (probably more efficient) ways of debugging this problem, but the technique of using a breakpoint to display information or perform other scripted actions then continue running is a valuable thing to have in your debugging toolbox. 当然,还有其他(可能更有效)的方法来调试此问题,但是使用断点显示信息或执行其他脚本操作然后继续运行的技术是调试工具箱中的一项有价值的工作。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM