[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