分类: LINUX
2007-10-09 14:24:38
本来编译器的调试功能,应该是初学编程时最先接触的DD之一的,不过工作以后多在玩ST的芯片,那个调试器实在不好用;兼之又花了更多的时间希望写出的代码跨更多的平台,久而久之,就习惯了用打印进行调试了(有关系?呵呵,大约唯一的关系就是如果跨平台这块出了问题,不能一下子就看出来吧)。
这次的问题却有些棘手,初步判断,一个段内存被意外修改了。而这个地址的引用,不算多,也不算少,花了差不多一个下午也没有线索。求助于同事,不想祭起调试工具,还没搞清楚偶的流程,一个内存写断点,马上定位。后面的事情自然简单了,不过补补调试器的课看来是有必要的了。
实际上早就有过类似的想法,希望能够监视运行时某个地址的改变,并实时断下来,而这实际上就是内存断点,却一直没有细查。
在ST的OS20下,这个命令是break –w/r address,很容易理解,w代表写,r代表读,输入命令在view菜单下的command console处。
VC同样也有类似的功能,新建断点时选数据,变量栏直接填上要监视的地址就可以了,另外如果是地址的埃?詈们蹇丈舷挛恼庀睿?裨虺绦蚧岜涞暮苈?M??饫镆部梢蕴畋淞棵??还?舷挛木褪潜匦氲牧耍??姨畋淞康幕埃?不峤鱿抻诒淞勘旧恚?刚胧裁吹母车狡渌?胤饺チ嗽俑谋淠谌菥筒换嵊蟹从沉恕A硗猓?饫锏哪诖娑系憬鱿扌炊系悖?炼系忝挥姓业剑?还?蠖嗍?榭鱿拢?补挥昧恕?/span>
大名鼎鼎的GDB自然也有这个功能,平时用的少,这里就说详细一些,也算找个地方记一下,学一下怎么玩这个:)。注意涉及的指令就是rwatch、watch和awatch,分别表示读、写、读写。需要注意的是我用的这个版本直接用地址是断不下来的,必须用*(char*)之类来进行强制类型转换,不知道其它版本会不会也有同样的问题。
代码如下:
//main.cpp gdb memory break test code
#include
#include
int main()
{
char buf[1024];
char* pp = buf;
printf("add buf = 0x%x\r\n",buf);
for(int i=0;i<100;i++)
{
printf("addr = 0x%x ~~ 0x%x\r\n",pp+i*10,pp+i*10+9);
memset(pp+i*10,0,10);
}
printf("end");
}
过程如下,我用的是cygwin模拟环境:
xxxx@
$ gcc -g main.cpp -o main.out //编译,注意-g
xxxx @
$ gdb main.out –nw //-nw表示用文本模式
GNU gdb 5.0 (20010428-3)
Copyright 2001 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 "i686-pc-cygwin"...
(gdb) list
1 #include
2 #include
3
4 int main()
5 {
6 char buf[1024];
7
8 char* pp = buf;
9 printf("add buf = 0x%x\r\n",buf);
10
(gdb) break 9 //第9行打断点
Breakpoint 1 at 0x
(gdb) run //运行
Starting program: /cygdrive/f/main.out
Breakpoint 1, main () at main.cpp:9
9 printf("add buf = 0x%x\r\n",buf);
Current language: auto; currently c++
(gdb) display &buf //查看buf的地址
1: &buf = (char (*)[1024]) 0x
(gdb) watch *(int*)0x23fA00 //写断点buf地址后的一点,保证其几个循环后被改写
Watchpoint 2: *(int *) 2357760
(gdb) c //继续运行
Continuing.
add buf = 0x
addr = 0x
addr = 0x
……
addr = 0x
addr = 0x
Watchpoint 2: *(int *) 2357760 //断点触发
Old value = 2357808
New value = 2357760
0x6108bee
(gdb) info breakpoints //删掉这些断点
Num Type Disp Enb Address What
1 breakpoint keep y 0x
breakpoint already hit 1 time
2 watchpoint keep y *(int *) 2357760
breakpoint already hit 1 time
(gdb) delete 1
(gdb) delete 2
(gdb) info breakpoints
No breakpoints or watchpoints.
(gdb) c //继续运行
Continuing.
addr = 0x23fa02 ~~ 0x23fa0b
……
addr = 0x23fd72 ~~ 0x23fd7b
end
Program exited normally.
(gdb)
再附录google到的一篇关于gdb的总结,个人觉得还不错,转载自:http://blog.iyi.cn/hily/archives/2006/05/post_12.html,(超长了,附在后面了)当然了要看更详细的当然是到官方的http://www.gnu.org/software/gdb/documentation/了。