最新消息:

GDB调试实例两则

GDB admin 3098浏览 0评论
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>

int
main()
{
    int n = 0x3fc00000;
    printf("%fn", n);
    return 0;
}
$ cc main.c -g
main.c: In function ‘main’
main.c:9: warning: format ‘%f’ expects type ‘double’, but argument 2 has type ‘
$ gdb a.out
Reading symbols from /home/dutor/Wdir/Cpp/GDB/a.out...done.
(gdb) l
1	#include
2	#include
3	#include
4
5	int
6	main()
7	{
8	    int n = 0x3fc00000;
9	    printf("%fn", n);
10	    return 0;
(gdb)
11	}
(gdb) start
Temporary breakpoint 1 at 0x80483cd: file main.c, line 8.
Starting program: /home/dutor/Wdir/Cpp/GDB/a.out

Temporary breakpoint 1, main () at main.c:8
8	    int n = 0x3fc00000;
(gdb) i program
	Using the running image of child process 7519.
Program stopped at 0x80483cd.
It stopped at a breakpoint that has since been deleted.
(gdb) n
9	    printf("%fn", n);
(gdb) p/x n
$2 = 0x3fc00000
(gdb) p/f n
$3 = 1.5
(gdb) disassemble
Dump of assembler code for function main:
   0x080483c4 <+0>:	push   %ebp
   0x080483c5 <+1>:	mov    %esp,%ebp
   0x080483c7 <+3>:	and    $0xfffffff0,%esp
   0x080483ca <+6>:	sub    $0x20,%esp
   0x080483cd <+9>:	movl   $0x3fc00000,0x1c(%esp) # 为n赋值
=> 0x080483d5 <+17>:	mov    $0x80484c0,%eax # 格式字符串地址
   0x080483da <+22>:	mov    0x1c(%esp),%edx
   0x080483de <+26>:	mov    %edx,0x4(%esp) # printf参数入栈
   0x080483e2 <+30>:	mov    %eax,(%esp)
   0x080483e5 <+33>:	call   0x80482f4
   0x080483ea <+38>:	mov    $0x0,%eax
   0x080483ef <+43>:	leave
   0x080483f0 <+44>:	ret
End of assembler dump.
(gdb) si
0x080483da	9	    printf("%fn", n);
(gdb) display /i $eip # 每次暂停都打印下一条指令
2: x/i $eip
=> 0x80483da :	mov    0x1c(%esp),%edx
(gdb) x/s $eax
0x80484c0:	 "%fn"
(gdb) si
0x080483de	9	    printf("%fn", n);
2: x/i $eip
=> 0x80483de :	mov    %edx,0x4(%esp)
(gdb)
0x080483e2	9	    printf("%fn", n);
2: x/i $eip
=> 0x80483e2 :	mov    %eax,(%esp)
(gdb)
0x080483e5	9	    printf("%fn", n);
2: x/i $eip
=> 0x80483e5 :	call   0x80482f4
(gdb) x/x $esp
0xbfffec30:	0x080484c0
(gdb) x/xw $esp+4
0xbfffec34:	0x3fc00000
(gdb) x/fw $esp+4
0xbfffec34:	1.5
(gdb) c
Continuing.
0.000000

Program exited normally.
(gdb) q
$

我们发现,传给printf的整数n的正是浮点数1.5的二进制形式(0x3fc00000参考IEEE 754浮点数标准),但为什么输出确实0.000000呢?同样的方法调试下面程序,

int
main()
{
    printf("%fn", 1.5);
    return 0;
}

会发现这次传递给printf的是8字节的0x3fff 8000 0000 0000,是1.5的双精度表示!可见gcc中printf对格式字符串中的f是按双精度对待的(I’m wondering: how about a single float?)
那么下面的程序的输出就应该是1.5了,你不妨试试

int
main()
{
    printf("%fn", 0x0, 0x3fff8000);
    return 0;
}

调试内存转储文件

内存转储文件(core dump)是程序发生严重错误时操作系统产生的文件,它包含了程序崩溃时占用的内存页面的拷贝,因此使用core文件在一定程度上可以再现崩溃前夕程序的状态。
多种原因下程序会崩溃,从而被系统终止,生成core文件,经常见到的是访存错误(段错误,Segment fault)。另外,系统是否生成core文件以及core文件的最大尺寸还受系统参数的控制。例如ubuntu下面普通用户程序是不允许生成core文件的,这可以使用ulimit命令来修改。不带参数的ulimit -c输出当前core文件的最大允许值,为了能够生成core文件,使用ulimit -c size设置大小,简单地,ulimit -c unlimited将其设为没有限制。

void foo(const char* s)
{
    char c = *s;
}
int
main()
{
    foo(0);
    return 0;
}

编译,执行,调试该程序,

$ ulimit
unlimited
$ cc main.c -g
$ ./a.out
Segmentation fault (core dumped) # 段错误,生成名为core的core文件
$ gdb a.out core
Reading symbols from /home/dutor/Wdir/Cpp/GDB/a.out...done.
[New Thread 11199]

warning: Can't read pathname for load map: Input/output error.
Reading symbols from /lib/libc.so.6...(no debugging symbols found)...done.
Loaded symbols for /lib/libc.so.6
Reading symbols from /lib/ld-linux.so.2...(no debugging symbols found)...done.
Loaded symbols for /lib/ld-linux.so.2
Core was generated by `./a.out'.
Program terminated with signal 11, Segmentation fault. # 程序终止原因
#0  0x0804839d in foo (s=0x0) at main.c:7 # 崩溃时程序执行到第7行foo函数。
7	    char c = *s;
(gdb) bt
#0  0x0804839d in foo (s=0x0) at main.c:7
#1  0x080483b7 in main () at main.c:12
(gdb) p /x s # 噢,s竟然是0!
$1 = 0x0
(gdb) q
$

转载请注明:爱开源 » GDB调试实例两则

您必须 登录 才能发表评论!