GDB 命令行调试之路(全 1-9)

1: 基本命令.
2: 断点管理/多文件调试.
3: 函数基本调试.
4: 中级命令.
5: 监视内存.
6: 高级命令.
7: 类的调试.
8: 线程调试
9: 总结.

 

1

1.hello gdb!
2.FAQ 

hello gdb!

 

首先准备好我们的调试文件test.cpp  如下

#include <iostream>
int main(0
{
int i=0;
i=10;
std::cout<<"hello,gdb"<<i<<std::endl;
return 0;

编译之。。


gcc -lStdC++ -g -Wall -o test test.cpp 

 

或者用  


g++ -g -o test test.cpp 

 

为简单起见 以后通用g++  ,这是GNU默认的c++编译器。
   参数解释:
      -g 产生相应的调试信息,
      -o 编译产生后的文件名 在这里也就test准备开始调试 执行gdb载入要调试的程序(注意,这里并没开始执行test,只是载入)

 


gdb test

 

这个时候。你会看到命令行如下输出

Codebogon:pg_019 cubase01$ gdb test
GNU gdb 6.3.50-20050815 (Apple version gdb-1820) (Sat Jun 16 02:40:11 UTC 2012)
Copyright 2004 Free Software Foundation, Inc.
GDB is free software, covered by the GNU General Public License, and you are
welcome to change it and/or 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.
This GDB was configured as "x86_64-apple-darwin"...Reading symbols for shared libraries ... done
(gdb)

此时,让我们开始在调试环境下执行test,输入

run

你将看到输出


(gdb) run 
Starting program: /Users/Desktop/Debugging/test
Reading symbols for shared libraries ++......................... done
hello,gdb10
Program exited normally.

 

好了,以上的步骤,就相当于你在xcode里用debug模式运行程序。

让程序在运行中停下来
在gdb中,有3种方式让程序停下来。

1.breakpoint  这种形式是我们最常用的,反映在xcode里就是在行前双击。产生一个蓝色的标签。
2.watchpoint  这种用的也多,如果你要监测一段内存是否发生变化。或者说一个变量是否发生变化,可以用它。
3.catchpoint  这种形式是当特点形式的事件发生时,会停止程序运行。比如说,系统抛异常了。这个在xcode里也比较常用 ,捕获异常时非常方便,能让开发人员很快的定位到代码中抛异常的位置。

这3种point 在GNU中统称breakpoint--断点GNU 参考 。比较囧 ,当然。重点说1.breakpoint 的应用。

有以下用法

break 3       //在当前调试的文件中的第3行停止程序
break main   //在当前调试的文件中的symbol table中找main这样的名字。如果找到。则停止程序。
break test.cpp:3    // 在test.cpp文件中的第3行停止程序
break test.cpp:main  //在test.cpp文件的symbol table中找main这样的名字。如果找到。则停止程序。

你可以在命令行里执行以上所有


(gdb) b 3 
Breakpoint 1 at 0x100000d34: file test.cpp, line 3.
(gdb) b main
Note: breakpoint 1 also set at pc 0x100000d34.
Breakpoint 2 at 0x100000d34: file test.cpp, line 4.
(gdb) b test.cpp:3
Note: breakpoints 1 and 2 also set at pc 0x100000d34.
Breakpoint 3 at 0x100000d34: file test.cpp, line 4.
(gdb) b test.cpp:main
Note: breakpoints 1, 2 and 3 also set at pc 0x100000d34.
Breakpoint 4 at 0x100000d34: file test.cpp, line 4. 

查看一下断点的情况 执行


info break 

这命令有点长,你可以用缩写 i b
关于缩写,gdb遵循一个这样的原则。只要缩写不会产生歧义。任何缩写都可以
比如说 info break
我打以下命令都可以 


i b 
i bre
i break
i bre 

执行i b 后,显示如下

gdb) i b
Num Type Disp Enb Address What
1 breakpoint keep y 0x0000000100000d34 in main at test.cpp:3
2 breakpoint keep y 0x0000000100000d34 in main at test.cpp:4
3 breakpoint keep y 0x0000000100000d34 in main at test.cpp:4
4 breakpoint keep y 0x0000000100000d34 in main at test.

以上各行含义解释如下
Num
这是一个断点的标示id,以后有需要索引这个断点的地方全靠它。
Type

如我们前面所说。这是3个断点中的一种
Disp

缩写(Dispensable),代表的意思就说能不能被自动删掉。有一处断点叫临时断点。就是中断一次后。断点就被删除了,下次再经过时,不会中断 tbreak  3 (在第3行设置临时断点) 这里显示的是keep ,代表永久断点。
Enb

缩写(Enable) 在xcode中。你可以暂时性的不激活断点,但是断点还存在,y代表激活。n代表不激活。
Address           
这个代表的是断点在内存中设置的具体位置。一般汇编人员用。。普通青年用不上。
What

这个是对断点的一些信息描述。

如上所示。我们在第3行打一个断点。以某种方式在第4行打了3个断点。重复的断点只会停一次。

现在,让我再次以调试模式运行test 。输入

run

显示


Starting program: 
/Users/cubase01/Desktop/Debugging/Chapter_01/insert_sort/pg_019/test
Breakpoint 1, main () at test.cpp:4
4 int i=0; 

程序停下来了。。此时程序并没有执行第4行,是将要执行这一行,切记。

我想。你有以下这几个疑问,FAQ时间到。

FAQ:

1.不是说在第3行有断点吗?怎么先到了第4行?

在xcode里调试。开发人员会有一种错觉。就是认为源文件与调试的行是一一对应的。实际上不是。g++ 在编译时通过 -g命令生成一个叫symbol table的东东,翻成中文叫符号表。作用就是将二进制代码与源文件对应起来。  将断点断在main上。gdb认为这对调试没有任何作用。所以会自动优化到int i=0 。这种优化在-g命令时还不是很明显。当你开启g++ -O9时,g++会强力优化代码 。比如说以下代码


int i=0; 
i=1;
i=2;
i=3;

 

用g++ -O9编译后。会被优化成int i=3;如果你用优化后的代码去调试。。要得到准确的行号是很难的。这可以算是一个比较麻烦的地方。因为优化很可能优化出bug。导致无法正常调试。

2.怎么查看i的值?

在命令行里输入

 


print i (缩写 p i)

输出


(gdb) p i 
$1 = 0
(gdb)

 

3 怎么单步调试?

在命令行里输入

 

next (缩写 n)

输出


(gdb) next 
5 i=10;

 

 4.我这样一步一步点好累啊!!能一次走两步么 ?

 

n 3

 

一次走3步。

5.我想重新调试程序,怎么办啊! 再次运行

 

run

 

6 我想直接执行到下一个断点,怎么办?

 


continue

 

如果后面没有断点了.那就直接结束了.

 

 

 

2


1.多文件调试断点标记方法。
2.断点基本管理。
3.函数基本调试.

 

1.多文件调试断点标记方法

首先引入两个文件。

main.c

 


#include <stdio.h>
void swap(int *a, int
*b);
int main( void )
{
int i = 3;
int j
= 5;
printf("i: %d, j: %d\n", i,
j);
swap(&i,
&j);
printf("i: %d, j: %d\n", i,
j);
return 0;
}

 

 

swapper.c

 


void swap(int *a, int *b)
{
int c =
*a;
*a = *b;
*b = c;
}

 

 

 

 

编译之


gcc -g3 -Wall main.c swapper.c
gcc -o swap main.o swapper.o

 

载入swap 程序


gdb swap 

1.那我想。怎么让我调试到swap函数呢?

   有几种方法:

1.直接用在gdb中强行指定


b swapper.c:swap 

//或者以下


b swapper.c:1

2.利用step命令,相当于xcode  里的step into 命令。首先在main 函数执行到swap时打上断点也就是


b main.c:10 

当执行到将要调用swap函数时,执行next 命令(缩写n)

n

完整的命令行输出如下:



bogon:swap cubase01$ gdb swap
GNU gdb 6.3.50-20050815 (Apple version
gdb-1820) (Sat Jun 16 02:40:11 UTC 2012)
Copyright 2004 Free Software
Foundation, Inc.
GDB is free software, covered by the GNU General Public
License, and you are
welcome to change it and/or 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.
This GDB was configured as "x86_64-apple-darwin"...Reading symbols
for shared libraries .. done
(gdb) b main.c:10
Breakpoint 1 at 0x100000e57: file main.c, line
10.
(gdb) r
Starting program:
/Users/cubase01/Desktop/Debugging/Chapter_02/swap/swap
Reading symbols for
shared libraries +........................ done
i: 3, j: 5
Breakpoint 1, main () at
main.c:10
10 swap(&i,
&j);
(gdb) s
swap (a=0x7fff5fbffac4, b=0x7fff5fbffac0) at
swapper.c:3
3 int c = *a;
(gdb)

 

 

2.断点基本管理

说到管理。我想做过数据库的都会想到 增删改查四大名捕。。。没错!那我们从4位入手。。


b 1
b main.c:4
b main.c:main


delete 1 //删除Num为1的断点。哪来的Num?? 输入 i b 在gdb中的断点列表的第一列!
delete 1 2 5 //可以同时删除多个断点
delete //如果没有参数 则删除所有断点

clear //消除gdb当前行的断点.
clear main //注意没有delete main这样的命令 clear main的意思是,清除函数main内所有的断点。
clear main.c:main //同上
clear 2
clear main.c:2


有人会问为什么一定要指定文件名?

答:因为你不一定是在这个文件里调试.

又问:哪我怎么知道我现在是在哪个文件里调试?

答:用list命令,同时你也可以用list命令切换你当前的命令作用对象.

 

禁用/启用


enable 1 //这里1代表的是i b 列表里的Num号
disable 1 5
enable once 1 5 // 只启用断点一起.中断后将置为disable状态

改的话主要用到地方是将普通断点改为条件断点,这在第3章会有具体介绍.

1:  2: cond 3 i >3 //将Num为3的断点加上i>3的条件,满足此条件时.停在此断点

1:  2: info break

 

3.函数基本调试

函数重要的就是进入函数与跳出函数,对应的gdb命令就是


step 
finish

看一下以下具体应用



(gdb) list main
1 #include <stdio.h>
2 void swap(int *a, int *b);
3
4 int main( void )
5 {
6 int i = 3;
7 int j = 5;
8
9 printf("i: %d, j: %d\n", i, j);
10 swap(&i, &j);
(gdb) b 10
Breakpoint 11 at 0x100000e57: file main.c, line 10.
(gdb) run
Starting program: /Users/cubase01/Desktop/Debugging/Chapter_02/swap/swap
i: 3, j: 5
Breakpoint 11, main () at main.c:10
10 swap(&i, &j);
(gdb) step
swap (a=0x7fff5fbffac4, b=0x7fff5fbffac0) at swapper.c:3
3 int c = *a;
(gdb) finish
Run till exit from #0 swap (a=0x7fff5fbffac4, b=0x7fff5fbffac0) at swapper.c:3
main () at main.c:11
11 printf("i: %d, j: %d\n", i, j);

 

 

 

 

 

3

前面两往篇把基本的调试命令介绍了一篇.下面.来点稍微高级的.这章将要介绍的是

1: 断点的逻辑判断

1. 断点的逻辑判断

首先准备好要调试的文件.简单简单...

1: #include <stdio.h> 2: int main( void ) 3: { 4: int i; 5: for( i = 0; i < 10; ++i 6: ) 7: printf("hello world!"); 8: return 0; 9: }

看着这段代码,有几个调试需求如下:

需求1.请在i=5的时候停下来.

需求2.请在i=5后,停下来之后.直接跳到return 0;

 

用前面说的基本方法,满足这两个需求是没问题的.但是比较麻烦.

需求1. 见以下命令行输出

1: (gdb) list main 2: 1 #include <stdio.h> 3: 2 4: 3 int main( void ) 5: 4 { 6: 5 int i; 7: 6 8: 7 for( i = 0; i < 10; ++i ) 9: 8 printf("hello world!"); 10: 9 11: 10 return 0; 12: (gdb) b 8 13: Breakpoint 1 at 0x100000eed: file until-anomaly.c, line 8. 14: (gdb) run 15: Starting program: /Users/cubase01/Desktop/Debugging/Chapter_02/until-anomaly/anomaly 16: Reading symbols for shared libraries +........................ done 17:  18: Breakpoint 1, main () at until-anomaly.c:8 19: 8 printf("hello world!"); 20: (gdb) c 5 21: Will ignore next 4 crossings of breakpoint 1. Continuing. 22:  23: Breakpoint 1, main () at until-anomaly.c:8 24: 8 printf("hello world!"); 25: (gdb) p i 26: $1 = 5 27: (gdb)

需求2.

则是在需求1的基础上在return 0 上打断点.

并删除打在printf("hello,world!")上的断点.

并执行continue

1: (gdb) b 10 2: Breakpoint 2 at 0x100000f03: file until-anomaly.c, line 10. 3: (gdb) i b 4: Num Type Disp Enb Address What 5: 1 breakpoint keep y 0x0000000100000eed in main at until-anomaly.c:8 6: breakpoint already hit 6 times 7: 2 breakpoint keep y 0x0000000100000f03 in main at until-anomaly.c:10 8: (gdb) d 1 9: (gdb) c 10: Continuing. 11:  12: Breakpoint 2, main () at until-anomaly.c:10 13: 10 return 0; 14: (gdb)

以上是用基本的命令完成的.可以看出比较麻烦.

下面介绍简单的方法.

需求1,2同时解决

1: (gdb) list main //这里例出当前正在调试谁的的具体信息 2: 1 #include <stdio.h> 3: 2 4: 3 int main( void ) 5: 4 { 6: 5 int i; 7: 6 8: 7 for( i = 0; i < 10; ++i ) 9: 8 printf("hello world!"); 10: 9 11: 10 return 0; 12: (gdb) b 8 if i==5 //这里就是所谓的条件断点.当i==5时,在第8行中断 13: Breakpoint 1 at 0x100000eed: file until-anomaly.c, line 8. 14: (gdb) r //运行调试程序 15: Starting program: /Users/cubase01/Desktop/Debugging/Chapter_02/until-anomaly/anomaly 16: Reading symbols for shared libraries +........................ done 17:  18: Breakpoint 1, main () at until-anomaly.c:8 19: 8 printf("hello world!"); 20: (gdb) p i //程序已中断,打印i值 i=5 21: $1 = 5 22: (gdb) u 10 //u 是until的缩写,它的意思是 执行到某一行.contine 类似 break 某行->continue的缩写 23: main () at until-anomaly.c:10 24: 10 return 0; 25: (gdb)

 

条件断点中的包括所有c++中的逻辑判断符(>=,<=,etc).运算符(+ , - ,* / , etc).包括位运算(| ,~ , etc).

更重要的是: 你还可以在条件断点中用function,只要这个函数链接到了这个函数所在的调试库.如果不是调试库.而发行库.那这个函数的返回值只会int类型.对于double float 或者其他类型.会解释不正确. 比如说

1:  2: (gdb) p cos(0.0) 3: $1=-13232

想强转? (gdb) p (double)(0.0)  .没用.在以后介绍gdb变量的时候.会有一个折衷的办法.再说.

 

但如果只是设置了

1:  2: b 2

想临时加 if i>3怎么办?

这样,先查找到第line 3这个断点的Num.假设为9

输入

1:  2: cond 9 i > 3

取消条件断点? 简单

1:  2: cond 9

 

4

 

 

接下来的开始命令的具体事例讲解

1: commands 2: define

引入以下文件:

1:  2: #include <stdio.h> 3: int fibonacci(int n); 4: int main( void ) 5: { 6: printf("Fibonacci(3) is %d.\n", 7: fibonacci(3)); 8: return 0; 9: } 10: int fibonacci( int n ) 11: { 12: if ( n <= 0 || n == 1 13: ) 14: return 1; 15: 16: else 17: return fibonacci(n-1) + 18: fibonacci(n-2); 19: }

 

以下命令中的括号代表的意义为[]可选  {}必须

1.commands

1:  2: (gdb){commands 1} //在断点Num 1上开始commands 3: >[slient] //不显示断点时的当前行信息 4: >print "hello ,gdb \n" //打印当前n值 5: >[continue] //继续执行当前断点 6: >{end} //必须以此结束commands

command命令里可以绑定很多函数.只要能够链接的到.库函数.你自己定义的函数都可以.甚至还可以使用函数的返回值.只要函数的返回值是int类型.

 

2.define

 

 

1:  2: {define print_and_go} 3: >printf $arg0, $arg1 4: >continue 5: >end 6:  7: commands 1 8: print_and_go "hello %d\n" n //注意这里没有逗号

 

命令行输出如下

 

1: (gdb) define print_and_go 2: Type commands for definition of "print_and_go". 3: End with a line saying just "end". 4: >printf $arg0,$arg1 5: >end 6: (gdb) break fibonacci 7: Breakpoint 1 at 0x100000e9b: file fibonacci.c, line 13. 8: (gdb) i b 9: Num Type Disp Enb Address What 10: 1 breakpoint keep y 0x0000000100000e9b in fibonacci at fibonacci.c:13 11: (gdb) commands 1 12: Type commands for when breakpoint 1 is hit, one per line. 13: End with a line saying just "end". 14: >print_and_go "the value is %d\n" n 15: >end 16: (gdb) run 17: Starting program: /Users/cubase01/Desktop/Debugging/Chapter_02/fibonacci/fibonacci 18: Reading symbols for shared libraries +........................ done 19:  20: Breakpoint 1, fibonacci (n=3) at fibonacci.c:13 21: 13 if ( n <= 0 || n == 1 ) 22: the value is 3 23: (gdb) c 24: Continuing. 25:  26: Breakpoint 1, fibonacci (n=2) at fibonacci.c:13 27: 13 if ( n <= 0 || n == 1 ) 28: the value is 2 29: (gdb) c 30: Continuing. 31:  32: Breakpoint 1, fibonacci (n=1) at fibonacci.c:13 33: 13 if ( n <= 0 || n == 1 ) 34: the value is 1 35: (gdb) c 36: Continuing. 37:  38: Breakpoint 1, fibonacci (n=0) at fibonacci.c:13 39: 13 if ( n <= 0 || n == 1 ) 40: the value is 0 41: (gdb) c 42: Continuing. 43:  44: Breakpoint 1, fibonacci (n=1) at fibonacci.c:13 45: 13 if ( n <= 0 || n == 1 ) 46: the value is 1 47: (gdb) c 48: Continuing. 49: Fibonacci(3) is 3. 50:  51: Program exited normally. 52: (gdb)

 

 

 

 

5

watchpoint,谁动了我的内存

 

1.watchpoint,谁动了我的内存

watchpoint 顾名思义,监视.在很多ide里都有这个功能.用起来跟breakpoint稍微有点不一样.我们知道breakpoint是可以在调试之前事先打好断点.但watchpoint不同.watchpoint必须要在当前scope里的设置.举例来说

拿以下fibonacci.c举例

1: #include <stdio.h> 2: int fibonacci(int n); 3: int global=0; 4: int 5: main( void ) 6: { 7: printf("Fibonacci(3) is %d.\n", 8: fibonacci(3)); 9: global=2; 10: return 11: 0; 12: } 13: int fibonacci( int n ) 14: { 15: if ( n <= 0 || n == 1 16: ) 17: return 1; 18: 19: else 20: return fibonacci(n-1) + 21: fibonacci(n-2); 22: }

 

命令行,监视全局变量


bogon:fibonacci cubase01$ gcc -g3 -o fibonacci fibonacci.c //compile 

bogon:fibonacci cubase01$ gdb fibonacci //加载gdb fibonacci
GNU gdb 6.3.50-20050815 (Apple
version gdb-1820) (Sat Jun 16 02:40:11 UTC 2012)
Copyright 2004 Free Software
Foundation, Inc.
GDB is free software, covered by the GNU General Public
License, and you are
welcome to change it and/or 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.
This GDB was configured as "x86_64-apple-darwin"...Reading symbols
for shared libraries .. done
(gdb) wa global //设置watchpoint 注意这是一个global变量.所以它的scope也是global的
Hardware watchpoint 1: global
(gdb) r
Starting
program: /Users/cubase01/Desktop/Debugging/Chapter_02/fibonacci/fibonacci

Reading symbols for shared libraries +........................
done
Fibonacci(3) is 3.
Hardware watchpoint 1: global
Old value = 0
New value = 2 //发现值改变.停下来.
main () at
fibonacci.c:8
8 return 0;
(gdb)

 

 

以上有几点要注意的地方 .

  1. watchpoint只能在当前scope里设置.
  2. watchpoint在脱离scope后.所有失去scope的变量会被自动删除.
  3. watchpoint监视的是内存值的变化.如果内存值被赋予了一个一样的值.那也不会起作用.

 

watchpoint也可以像条件断点一样加上条件.它们的区别是watchpoint会在作用域之后自动删除.没前作用域之前不会存在.

条件监视断点里可以包含的表达式有:

  1. 类似$arg0这些已经在gdb中定义的变量.
  2. 任何在当前 scpoe里的变量
  3. 定义了的字符,数字常量
  4. 预处理了的宏
  5. 语言里的条件判断

修改如下:


bogon:fibonacci cubase01$ gcc -g3 -o fibonacci fibonacci.c 

bogon:fibonacci cubase01$ gdb
GNU gdb 6.3.50-20050815 (Apple version
gdb-1820) (Sat Jun 16 02:40:11 UTC 2012)
Copyright 2004 Free Software
Foundation, Inc.
GDB is free software, covered by the GNU General Public
License, and you are
welcome to change it and/or 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.
This GDB was configured as "x86_64-apple-darwin".
(gdb) file
fibonacci
Reading symbols for shared libraries .. done
Reading symbols
from /Users/cubase01/Desktop/Debugging/Chapter_02/fibonacci/fibonacci...Reading
symbols from
/Users/cubase01/Desktop/Debugging/Chapter_02/fibonacci/fibonacci.dSYM/Contents/Resources/DWARF/fibonacci...done.
done.
(gdb)
b main
Breakpoint 1 at 0x100000e34: file fibonacci.c, line 6.
(gdb)
run
Starting program:
/Users/cubase01/Desktop/Debugging/Chapter_02/fibonacci/fibonacci
Reading
symbols for shared libraries +........................ done
Breakpoint 1, main () at
fibonacci.c:6
6 int a=1;
(gdb)
wa a
Hardware watchpoint 2: a
(gdb) r
The program being debugged
has been started already.
Start it from the beginning? (y or n) n
Program
not restarted.
(gdb) c
Continuing.
Hardware watchpoint 2: a
Old value = 0
New value = 1
main () at
fibonacci.c:7
7
printf("Fibonacci(3) is %d.\n", fibonacci(3));
(gdb)
c
Continuing.
Fibonacci(3) is 3.
Hardware watchpoint 2: a
Old value = 1
New value = 2
main () at
fibonacci.c:10
10 return
0;
(gdb)

 

 

Tips:


(gdb) i b
Num Type Disp Enb Address What
1 hw watchpoint keep y global breakpoint already hit 1 time

有没有发现上面的watchpoint type 是hw,这是因为watchpoint可以由硬件实现.速度很快.如果硬件不能实现gdb则会利用VM技术实现.也比较快.如果前两种都不行.GDB会自己通过软件实现..很慢.

 

 

 

6

前面已经把95%的调试技巧全讲完了.接下来一起学习一下方便调试的东西.这些命令或者技巧是能让你更方便的调试.

接下来将介绍以下高级命令

display //在每次断点停下来时,打印当前scope中的变量

call     //调用当前scope中某个函数

 

怎么打印数组?
怎么查看当前stack中的变量?
怎么打印其他格式的值?
怎么管理display例表?
怎么临时改变变量的值?
怎么设置启动时的命令行参数?
为什么每次print时,都有$1,$2之类的东东在前面?
怎么重复上一命令?
怎么在gdb中设置一个变量?
Tips

怎么打印数组?

准备以下文件

int *x;
main()
{
x = (int *) malloc( 25*sizeof(int) );
x[3] = 12;
}

(gdb) b 6
Breakpoint 1 at 0x100000f24: file solutions_in_gdb.c, line 6.
(gdb)
r
Starting program:
/Users/cubase01/Desktop/Debugging/Chapter_03/solutions_in_gdb/solutions_in_gdb

Reading symbols for shared libraries +........................ done
Breakpoint 1, main () at
solutions_in_gdb.c:6
6 x[3] =
12;
(gdb) p *x@25
$1 = {0 <repeats 25 times>}
(gdb)
n
7 }
(gdb)
p *x@25 //这个是关键的东西 p指针@元素个数
$2 = {0, 0, 0, 12, 0 <repeats
21 times>}
(gdb)

怎么查看当前stack中的变量?


info local

怎么打印其他格式的值?


p/x i //打印hex
p/c i //打印字符
p/s i //打印字符串
p/f i //打印float

怎么管理display例表?

(gdb) info display
Auto-display expressions now in effect:
Num Enb Expression
1: y i

Num

这个跟断点Num的意义一样.是display某值的一个标识.

Enb

缩写(enable),是否激活 

要禁用的话.启用用enable.删除display命令有点不合群.undisplay 1

 


disable display 1
enable display 1
undisplay 1

 

Expression

display 的变量值

 

 

怎么临时改变变量的值?


set i=3

 

怎么设置启动时的命令行参数?


set args 1 3 5 

当然.你设置完后.要调用run启动这些命令.跟直接执行以下是一样的


run 1 3 5

打印命令行参数

 

info args

 

为什么每次print时,都有$1,$2之类的东东在前面?

这个东西叫 value history. 恶心翻译一下就是值的历史吧. 比如说你打印


int* a;
*a =1;
(gdb)p a
$1 =(int*) 0x32fa231 //打印出值的地址
(gdb)p
$1
//打印出$1更新后的值
$2 =(int*) 0x32fa231
(gdb)p
*$2
//打印出$2指向的值
$3 = 1
(gdb) p
$
//打印出上一个value history的值
$4 = 1
(gdb) p
&$
//打印出上一个value history的地址
$5 =(int*) 0x32fa231

怎么重复上一命令??

直接按回车.

 

怎么在gdb中设置一个变量?


set $a=i 
set $b=2
$b++

Tips

大家觉得下面两个函数有什么区别? 麻烦用call命令在gdb中分别调用它们(跟gdb没关系.只是顺便举例).

1:  2: void p() 3: { 4: printf("hello"); 5: }
1:  2: void p() 3: { 4: printf("hello\n"); 5: }

发现区别没有.printf不一定要会即时调用.我建议大家看一下这篇文章.一个fork的面试题 .

 

 

 

7

这一篇主要说一下类的一些相关调试.

 

类相关gdb调试

准备以下类

// bintree.cc: routines to do insert and sorted print of a binary tree in C++

#include <cstdlib>
#include <iostream>
using namespace std;

class node {
public:
static class node *root; // root of the entire tree
int val; // stored value
class node *left; // ptr to smaller child
class node *right; // ptr to larger child
node(int x); // constructor, setting val = x
static void insert(int x); // insert x into the tree
static void printtree(class node *nptr); // print subtree rooted at *nptr
};

class node *node::root = 0;


node::node(int x)
{
val = x;
left = right = 0;
}


void node::insert(int x)
{
if (node::root == 0) {
node::root = new node(x);
return;
}
class node *tmp=root;
while (1)
{
if (x < tmp->val)
{

if (tmp->left != 0) {
tmp = tmp->left;
} else {
tmp->left = new node(x);
break;
}

} else {

if (tmp->right != 0) {
tmp = tmp->right;
} else {
tmp->right = new node(x);
break;
}

}
}
}


void node::printtree(class node *np)
{
if (np == 0) return;
node::printtree(np->left);
cout << np->val << endl;
node::printtree(np->right);
}


int main(int argc, char *argv[])
{
for (int i = 1; i < argc; i++)
node::insert(atoi(argv[i]));
node::printtree(node::root);
}

怎么打印类中的静态变量?

打印方法


p *node ::root

 

怎么查看类的结构?

 

(gdb) b main
Breakpoint 1 at 0x100000c9f: file bintree.cc, line 72.
(gdb) r
Starting program: /Users/cubase01/Desktop/Debugging/Chapter_03/bintree++/bintree
Reading symbols for shared libraries ++......................... done

Breakpoint 1, main (argc=1, argv=0x7fff5fbffac0) at bintree.cc:72
72 for (int i = 1; i < argc; i++)
(gdb) ptype node
type = class node {
public:
int val;
node *left;
node *right;
static node *root;

node(int);
node(int);
node(int);
static void insert(int);
static void printtree(node*);
}
(gdb)

 


ptype node

 

8

调试中最烦的就是线程. 线程太多队伍不好带...

在mac下.线程用的最多的还是pthread. 先准备好要调试的线程源码:

以下这个文件是从<<The art of debugging with gdb >>中借来用的.

sieve.c

// finds the primes between 2 and n; uses the Sieve of Eratosthenes,
// deleting all multiples of 2, all multiples of 3, all multiples of 5,
// etc.; not efficient, e.g. each thread should do deleting for a whole
// block of values of base before going to nextbase for more

// usage: sieve nthreads n
// where nthreads is the number of worker threads

#include <stdio.h>
#include <math.h>
#include <pthread.h>

#define MAX_N 100000000
#define MAX_THREADS 100

// shared variables
int nthreads, // number of threads (not counting main())
n, // upper bound of range in which to find primes
prime[MAX_N+1], // in the end, prime[i] = 1 if i prime, else 0
nextbase; // next sieve multiplier to be used

int work[MAX_THREADS]; // to measure how much work each thread does,
// in terms of number of sieve multipliers checked

// lock index for the shared variable nextbase
pthread_mutex_t nextbaselock = PTHREAD_MUTEX_INITIALIZER;

// ID structs for the threads
pthread_t id[MAX_THREADS];

// "crosses out" all multiples of k, from k*k on
void crossout(int k)
{ int i;

for (i = k; i*k <= n; i++) {
prime[i*k] = 0;
}
}

// worker thread routine
void *worker(int tn) // tn is the thread number (0,1,...)
{ int lim,base;

// no need to check multipliers bigger than sqrt(n)
lim = sqrt(n);

do {
// get next sieve multiplier, avoiding duplication across threads
pthread_mutex_lock(&nextbaselock);
base = nextbase += 2;
pthread_mutex_unlock(&nextbaselock);
if (base <= lim) {
work[tn]++; // log work done by this thread
// don't bother with crossing out if base is known to be
// composite
if (prime[base])
crossout(base);
}
else return;
} while (1);
}

main(int argc, char **argv)
{ int nprimes, // number of primes found
totwork, // number of base values checked
i;
void *p;

n = atoi(argv[1]);
nthreads = atoi(argv[2]);
for (i = 2; i <= n; i++)
prime[i] = 1;
crossout(2);
nextbase = 1;
// get threads started
for (i = 0; i < nthreads; i++) {
pthread_create(&id[i],NULL,(void *) worker,(void *) i);
}

// wait for all done
totwork = 0;
for (i = 0; i < nthreads; i++) {
pthread_join(id[i],&p);
printf("%d values of base done\n",work[i]);
totwork += work[i];
}
printf("%d total values of base done\n",totwork);

// report results
nprimes = 0;
for (i = 2; i <= n; i++)
if (prime[i]) nprimes++;
printf("the number of primes found was %d\n",nprimes);

}

 

怎么列举当前的线程?

info threads

在断点停下后.怎么切换到其他线程去

thread n

怎么指定在某个断点停下,当在某个线程时.

break 30 thread 1

 

9

为什么你的程序会崩溃?

在写c/c++程序时.最常见的崩溃就是

invalid access of memory 读取了没有权限的内存导致崩溃.出现这种情况时. 硬件会执行一个jump命令到操作系统.由操作系统处理.

调试时,内存是在Virtual Memory(VM)里模拟.这也是为了方便内存调试.

反应在xcode里就是segementation fault/seg fault

在visual studio里是general protection fault 反正不管怎么取名.它的意思就是说程序读了它不该读的内存.

 

正是因为在调试时内存是在虚拟内存里分配的.所以有一些segmentation fault不是很明显.原因是:

在VM里的内存分配有一个最小分配值.取名叫page. 在奔腾系统处理器里.这个值默认为4096 bytes.所以当你有一个程序占用了10000 bytes时.它总共会占用3个page.而不是2.5个.page已经是最小单位.不能再分割.

这就会出现一个问题.如果程序在多出来的page里出了错.很可能在调试时并不会报错.

posted @ 2012-12-26 17:42  cubase01  阅读(7238)  评论(0编辑  收藏  举报