[Mac-10.7.1 Lion Intel-based x64 gcc4.2.1 GNU gdb 6.3.50-20050815 (Apple version gdb-1708)]
Q: 给个简单的代码,然后进入调试状态。
A: 如下代码,保存为hello.c:
#include <stdio.h>
int main()
{
int i = 2;
printf("%d\n", i);
return 0;
}
gcc编译,需要有-g参数:gcc -g hello.c -o hello得到带调试信息的hello可执行文件,gdb hello进入调试状态,输入list查看源代码信息:
可以看到hello.c源代码被打印出来了。输入run命令运行程序,
可以看到程序开始运行,且输出了结果。
Q: 如何能够看到调试信息?
A: 可以通过源代码编译后的汇编代码得到信息。gcc -S -g hello.c得到hello.s文件:
.section __TEXT,__text,regular,pure_instructions
.section __DWARF,__debug_frame,regular,debug
Lsection_debug_frame:
.section __DWARF,__debug_info,regular,debug
Lsection_info:
.section __DWARF,__debug_abbrev,regular,debug
Lsection_abbrev:
.section __DWARF,__debug_aranges,regular,debug
Lsection_aranges:
.section __DWARF,__debug_macinfo,regular,debug
Lsection_macinfo:
Lsection_line:
.section __DWARF,__debug_loc,regular,debug
Lsection_loc:
.section __DWARF,__debug_pubnames,regular,debug
Lsection_pubnames:
.section __DWARF,__debug_pubtypes,regular,debug
Lsection_pubtypes:
.section __DWARF,__debug_str,regular,debug
Lsection_str:
.section __DWARF,__debug_ranges,regular,debug
Lsection_ranges:
.section __TEXT,__text,regular,pure_instructions
Ltext_begin:
.section __DATA,__data
Ldata_begin:
.section __TEXT,__text,regular,pure_instructions
.globl _main
.align 4, 0x90
_main:
Leh_func_begin1:
Lfunc_begin1:
Ltmp3:
pushq %rbp
Ltmp0:
movq %rsp, %rbp
Ltmp1:
Ltmp4:
subq $16, %rsp
Ltmp2:
movl $2, -12(%rbp)
Ltmp5:
movl -12(%rbp), %eax
xorb %cl, %cl
leaq L_.str(%rip), %rdx
movq %rdx, %rdi
movl %eax, %esi
movb %cl, %al
callq _printf
Ltmp6:
movl $0, -8(%rbp)
movl -8(%rbp), %eax
movl %eax, -4(%rbp)
movl -4(%rbp), %eax
addq $16, %rsp
popq %rbp
ret
Ltmp7:
Lfunc_end1:
Leh_func_end1:
.section __TEXT,__cstring,cstring_literals
L_.str:
.asciz "%d\n"
.section __TEXT,__eh_frame,coalesced,no_toc+strip_static_syms+live_support
EH_frame0:
Lsection_eh_frame:
Leh_frame_common:
Lset0 = Leh_frame_common_end-Leh_frame_common_begin
.long Lset0
Leh_frame_common_begin:
.long 0
.byte 1
.asciz "zR"
.byte 1
.byte 120
.byte 16
.byte 1
.byte 16
.byte 12
.byte 7
.byte 8
.byte 144
.byte 1
.align 3
Leh_frame_common_end:
.globl _main.eh
_main.eh:
Lset1 = Leh_frame_end1-Leh_frame_begin1
.long Lset1
Leh_frame_begin1:
Lset2 = Leh_frame_begin1-Leh_frame_common
.long Lset2
Ltmp8:
.quad Leh_func_begin1-Ltmp8
Lset3 = Leh_func_end1-Leh_func_begin1
.quad Lset3
.byte 0
.byte 4
Lset4 = Ltmp0-Leh_func_begin1
.long Lset4
.byte 14
.byte 16
.byte 134
.byte 2
.byte 4
Lset5 = Ltmp1-Ltmp0
.long Lset5
.byte 13
.byte 6
.align 3
Leh_frame_end1:
.section __TEXT,__text,regular,pure_instructions
Ltext_end:
.section __DATA,__data
Ldata_end:
.section __TEXT,__text,regular,pure_instructions
Lsection_end1:
.section __DWARF,__debug_frame,regular,debug
Ldebug_frame_common:
Lset6 = Ldebug_frame_common_end-Ldebug_frame_common_begin
.long Lset6
Ldebug_frame_common_begin:
.long 4294967295
.byte 1
.byte 0
.byte 1
.byte 120
.byte 16
.byte 12
.byte 7
.byte 8
.byte 144
.byte 1
.align 2
Ldebug_frame_common_end:
Lset7 = Ldebug_frame_end1-Ldebug_frame_begin1
.long Lset7
Ldebug_frame_begin1:
Lset8 = Ldebug_frame_common-Lsection_debug_frame
.long Lset8
.quad Lfunc_begin1
Lset9 = Lfunc_end1-Lfunc_begin1
.quad Lset9
.byte 4
Lset10 = Ltmp0-Lfunc_begin1
.long Lset10
.byte 14
.byte 16
.byte 134
.byte 2
.byte 4
Lset11 = Ltmp1-Ltmp0
.long Lset11
.byte 13
.byte 6
.align 2
Ldebug_frame_end1:
.section __DWARF,__debug_info,regular,debug
Linfo_begin1:
.long 201
.short 2
Lset12 = Labbrev_begin-Lsection_abbrev
.long Lset12
.byte 8
.byte 1
.ascii "4.2.1 (Based on Apple Inc. build 5658) (LLVM build 2336.1.00)"
.byte 0
.byte 1
.ascii "hello.c"
.byte 0
.quad 0
.long 0
.ascii "/Users/xichen/codes/c_simple/"
.byte 0
.byte 2
.byte 5
.ascii "int"
.byte 0
.byte 4
.byte 3
.ascii "main"
.byte 0
.ascii "main"
.byte 0
.byte 1
.byte 4
.byte 1
.long 125
.byte 1
.quad Lfunc_begin1
.quad Lfunc_end1
.byte 1
.byte 86
.byte 4
.quad Ltmp4
.quad Ltmp7
.byte 5
.byte 105
.byte 0
.byte 1
.byte 5
.long 125
.byte 2
.byte 145
.byte 116
.byte 0
.byte 0
.byte 0
.byte 0
.byte 0
.byte 0
.byte 0
Linfo_end1:
.section __DWARF,__debug_abbrev,regular,debug
Labbrev_begin:
.byte 1
.byte 17
.byte 1
.byte 37
.byte 8
.byte 19
.byte 11
.byte 3
.byte 8
.byte 82
.byte 1
.byte 16
.byte 6
.byte 27
.byte 8
.byte 0
.byte 0
.byte 2
.byte 36
.byte 0
.byte 62
.byte 11
.byte 3
.byte 8
.byte 11
.byte 11
.byte 0
.byte 0
.byte 3
.byte 46
.byte 1
.byte 3
.byte 8
.byte 135
.byte 64
.byte 8
.byte 58
.byte 11
.byte 59
.byte 11
.byte 39
.byte 12
.byte 73
.byte 19
.byte 63
.byte 12
.byte 17
.byte 1
.byte 18
.byte 1
.byte 64
.byte 10
.byte 0
.byte 0
.byte 4
.byte 11
.byte 1
.byte 17
.byte 1
.byte 18
.byte 1
.byte 0
.byte 0
.byte 5
.byte 52
.byte 0
.byte 3
.byte 8
.byte 58
.byte 11
.byte 59
.byte 11
.byte 73
.byte 19
.byte 2
.byte 10
.byte 0
.byte 0
.byte 0
Labbrev_end:
.section __DWARF,__debug_line,regular,debug
Lset13 = Lline_end-Lline_begin
.long Lset13
Lline_begin:
.short 2
Lset14 = Lline_prolog_end-Lline_prolog_begin
.long Lset14
Lline_prolog_begin:
.byte 1
.byte 1
.byte 246
.byte 245
.byte 10
.byte 0
.byte 1
.byte 1
.byte 1
.byte 1
.byte 0
.byte 0
.byte 0
.byte 1
.asciz "/Users/xichen/codes/c_simple/"
.byte 0
.asciz "hello.c"
.byte 1
.byte 0
.byte 0
.byte 0
Lline_prolog_end:
.byte 0
.byte 9
.byte 2
.quad Ltmp3
.byte 23
.byte 0
.byte 9
.byte 2
.quad Ltmp4
.byte 21
.byte 0
.byte 9
.byte 2
.quad Ltmp5
.byte 21
.byte 0
.byte 9
.byte 2
.quad Ltmp6
.byte 21
.byte 0
.byte 9
.byte 2
.quad Lsection_end1
.byte 0
.byte 1
.byte 1
Lline_end:
.section __DWARF,__debug_pubnames,regular,debug
Lset15 = Lpubnames_end1-Lpubnames_begin1
.long Lset15
Lpubnames_begin1:
.short 2
Lset16 = Linfo_begin1-Lsection_info
.long Lset16
Lset17 = Linfo_end1-Linfo_begin1
.long Lset17
.long 132
.asciz "main"
.long 0
Lpubnames_end1:
.section __DWARF,__debug_pubtypes,regular,debug
Lset18 = Lpubtypes_end1-Lpubtypes_begin1
.long Lset18
Lpubtypes_begin1:
.short 2
Lset19 = Linfo_begin1-Lsection_info
.long Lset19
Lset20 = Linfo_end1-Linfo_begin1
.long Lset20
.long 0
Lpubtypes_end1:
.section __DWARF,__debug_aranges,regular,debug
.section __DWARF,__debug_ranges,regular,debug
.section __DWARF,__debug_macinfo,regular,debug
.section __DWARF,__debug_inlined,regular,debug
Lset21 = Ldebug_inlined_end1-Ldebug_inlined_begin1
.long Lset21
Ldebug_inlined_begin1:
.short 2
.byte 8
Ldebug_inlined_end1:
.subsections_via_symbols
可以看到里面有很多关于debug的信息,使用MachOView工具也可以看到对应的可执行文件中的调试信息。
Q: 如何调试core文件?
A: 可以使用gdb 可执行文件 core文件 的方式来调试。如下,写个可以导致崩溃的代码invalid_ptr.c:
#include <stdio.h>
int main()
{
int *p = (int *)0;
*p = 1;
return 0;
}
使用-g参数编译成可执行文件invalid_ptr.先查看下系统是否支持生成core文件,
如果是0,那说明不能生成core文件。做如下修改:
接着运行invalid_ptr文件:
注意上面的这个过程可能很慢,因为mac下生成的core文件异常的大,就这个代码,在笔者的机器上core文件有340MB,有点费解。
然后使用gdb调试此core文件(命令行中的/cores/core.13890是刚刚生成的core文件,不同平台可能不同,需要根据时间自行判断):
可以看到,它正确地定位到了错误代码的位置。
Q: 如何能够得到一个变量的类型?
A: 使用whatis命令即可。如下代码保存为mem.c:
#include <stdio.h>
int main()
{
int arr[] = {1, 2, 3, 4};
arr[0] = 100;
return 0;
}
使用gdb调试:
Q: 在gdb环境,需要调用外部shell命令,如何不退出gdb来执行?
A: 使用shell命令即可。
上面是在gdb环境输出hello.c文件的内容。
Q: 有的时候,调试外部代码,为了给外部代码返回正确的数值,强制让一个函数返回某个特定的值,如何做?
A: 使用return命令。如下代码,保存为add.c, 并进入gdb调试状态:
#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
int main()
{
int i = 2;
int sum;
printf("%d\n", i);
sum = add(i, 3);
printf("sum is %d\n", sum);
return 0;
}
如下调试:
可以看到,add函数,参数为2和3,但是可以强制改变它的返回值。
Q: 有的时候,需要修改某个变量的值来调试查看可能的结果,怎么做?
A: 可以使用set var命令。使用上面的代码,进入调试状态:
可以看到使用set var i=100将i的数值改变了。
Q: 如果需要查看当前执行的函数的内部基本信息,怎么办?
A: 可以使用info frame命令(缩写为i f).依然使用上面的add.c代码,进入调试状态:
可以看到,里面包含了语言、参数、局部变量和一些寄存器信息等。
Q: 如果需要输出某个地址的数据,用什么命令?
A: 可以使用print *地址命令。依然使用add.c代码,进入调试状态:
对于内存地址的查看,也可以使用x命令查看。
Q: 有的时候,想直接跳到某一行执行,怎么做?
A: 使用jump命令。如下代码,为loop.c:
#include <stdio.h>
int main()
{
int i = 2;
while(i < 1000)
{
++i;
}
printf("end...\n");
return 0;
}
假设在while循环中有断点,想要直接跳到后面的printf函数:
Q: 如果在调试状态,需要主动调用某个函数,求其返回值,怎么做?
A: 可以使用call命令。使用add.c代码:
#include <stdio.h>
int add(int a, int b)
{
return a + b;
}
int main()
{
int i = 2;
int sum;
printf("%d\n", i);
sum = add(i, 3);
printf("sum is %d\n", sum);
return 0;
}
进入调试状态:
Q: 如果是多线程,如何给不同线程执行的代码打断点?
A: 可以使用info threads获取所有线程信息,然后使用b 行号 thread 线程号 来打断点。
xichen
2012-5-22 11:11:34