gdb调试总结

一,gdb调试基础

(1)用gdb编译程序时,首先在编译程序时加-g

gcc test.c -o gdb_test -g

(2)运行程序

  • gdb + 编译后的文件名
  • 在命令行中先输入gdb,按回车,再输入file + 编译后的文件

(3)run命令就可以将程序运行起来了,简写 r

(4)断点

  • 可以对某一行进行打断点 例:对程序的第三行进行打断点 b 3
  • 多个文件,可以对某个文件的某一行打断点, 例:对test.c的第三行打断点 b test.c:3 
  • 可以对某个函数进行打断点 例:对程序中函数打断点 b func
  • 也可以对多个文件中的某一个文件的函数打断点,例: b test.c:func
  • 还可以以条件表达式设置断点, 例: break n if 条件

(5)暂停某个断点:

  • 如果不需要程序在该断点暂停时,有两种方法,一种是使该断点失效,一种是直接删除该断点
  • enable和disable break启用和暂停某个断点
  • delete break 删除所有的断点
  • delete break n 删除某个断点 n为断点号
  • clear 行号    删除设在某一行的断点

(6)查看断点信息

  • info b  查看所有断点信息

  • info b n  查看第n个断点的信息

(7)打印变量值print,简化p

(8)程序继续执行continue,简化c

(9)显示程序list,简化l

  • list 5,10   显示第5行到第10行的代码;
  • list func   显示func函数周围的代码,显示范围和list参数有关;
  • list test.c:5,10  显示源文件test.c第5行到第10行的代码,一般用于调试含多个源文件的程序。

(10)清屏shell clear

(11)next和step

next,继续执行下一条语句;还有一条命令step,与之类似,不同的是,当下一条语句遇到函数调用的时候,next不会跟踪进入函数,而是继续执行下面的语句,而step命令则会跟踪进入函数内部。

函数返回可以使用return和finish命令

(12)退出gdb调试 quit

二,函数

(1)直接执行函数,使用“call”或“print”命令

#include <stdio.h>

int global = 1;

int func(void) 
{
	return (++global);
}

int main(void)
{
	printf("%d\n", global);
	return 0;
}

使用gdb调试程序时,可以使用“call”或“print”命令直接调用函数执行。以上面程序为例:

(gdb) start
Temporary breakpoint 1 at 0x4004e3: file a.c, line 12.
Starting program: /data2/home/nanxiao/a

Temporary breakpoint 1, main () at a.c:12
12              printf("%d\n", global);
(gdb) call func()
$1 = 2
(gdb) print func()
$2 = 3
(gdb) n
3
13              return 0;

可以看到执行两次func函数后,global的值变成3

(2)选择函数堆栈帧“frame n”命令

#include <stdio.h>

int func1(int a)
{
        return 2 * a;
}

int func2(int a)
{
        int c = 0;
        c = 2 * func1(a);
        return c;
}

int func3(int a)
{
        int c = 0;
        c = 2 * func2(a);
        return c;
}

int main(void)
{
        printf("%d\n", func3(10));
        return 0;
}

用gdb调试程序时,当程序暂停后,可以用“frame n”命令选择函数堆栈帧,其中n是层数。以上面程序为例:

(gdb) b test.c:5
Breakpoint 1 at 0x40053d: file test.c, line 5.
(gdb) r
Starting program: /home/nanxiao/test

Breakpoint 1, func1 (a=10) at test.c:5
5               return 2 * a;
(gdb) bt
#0  func1 (a=10) at test.c:5
#1  0x0000000000400560 in func2 (a=10) at test.c:11
#2  0x0000000000400586 in func3 (a=10) at test.c:18
#3  0x000000000040059e in main () at test.c:24
(gdb) frame 2
#2  0x0000000000400586 in func3 (a=10) at test.c:18
18              c = 2 * func2(a);

可以看到程序断住后,最内层的函数帧为第0帧。执行frame 2命令后,当前的堆栈帧变成了fun3的函数帧。

也可以用“frame addr”命令选择函数堆栈帧,其中addr是堆栈地址。仍以上面程序为例:

(gdb) frame 2
#2  0x0000000000400586 in func3 (a=10) at test.c:18
18              c = 2 * func2(a);
(gdb) i frame
Stack level 2, frame at 0x7fffffffe590:
 rip = 0x400586 in func3 (test.c:18); saved rip = 0x40059e
 called by frame at 0x7fffffffe5a0, caller of frame at 0x7fffffffe568
 source language c.
 Arglist at 0x7fffffffe580, args: a=10
 Locals at 0x7fffffffe580, Previous frame's sp is 0x7fffffffe590
 Saved registers:
  rbp at 0x7fffffffe580, rip at 0x7fffffffe588
(gdb) frame 0x7fffffffe568
#1  0x0000000000400560 in func2 (a=10) at test.c:11
11              c = 2 * func1(a);

使用“i frame”命令可以知道0x7fffffffe568func2的函数堆栈帧地址,使用“frame 0x7fffffffe568”可以切换到func2的函数堆栈帧。

(3)用gdb调试程序时,当程序暂停后,可以用“up n”或“down n”命令向上或向下选择函数堆栈帧,其中n是层数。

(4)退出正在调试的函数“finish”命令或者“return”命令退出

三,断点

(1)在程序入口处打断点

获取程序入口

方法一:

$ strip a.out
$ readelf -h a.out 
ELF Header:
  Magic:   7f 45 4c 46 02 01 01 00 00 00 00 00 00 00 00 00 
  Class:                             ELF64
  Data:                              2's complement, little endian
  Version:                           1 (current)
  OS/ABI:                            UNIX - System V
  ABI Version:                       0
  Type:                              EXEC (Executable file)
  Machine:                           Advanced Micro Devices X86-64
  Version:                           0x1
  Entry point address:               0x400440
  Start of program headers:          64 (bytes into file)
  Start of section headers:          4496 (bytes into file)
  Flags:                             0x0
  Size of this header:               64 (bytes)
  Size of program headers:           56 (bytes)
  Number of program headers:         9
  Size of section headers:           64 (bytes)
  Number of section headers:         29
  Section header string table index: 28

方法二:

$ gdb a.out 
>>> info files
Symbols from "/home/me/a.out".
Local exec file:
	`/home/me/a.out', file type elf64-x86-64.
	Entry point: 0x400440
	0x0000000000400238 - 0x0000000000400254 is .interp
	0x0000000000400254 - 0x0000000000400274 is .note.ABI-tag
	0x0000000000400274 - 0x0000000000400298 is .note.gnu.build-id
	0x0000000000400298 - 0x00000000004002b4 is .gnu.hash
	0x00000000004002b8 - 0x0000000000400318 is .dynsym
	0x0000000000400318 - 0x0000000000400355 is .dynstr
	0x0000000000400356 - 0x000000000040035e is .gnu.version
	0x0000000000400360 - 0x0000000000400380 is .gnu.version_r
	0x0000000000400380 - 0x0000000000400398 is .rela.dyn
	0x0000000000400398 - 0x00000000004003e0 is .rela.plt
	0x00000000004003e0 - 0x00000000004003fa is .init
	0x0000000000400400 - 0x0000000000400440 is .plt
	0x0000000000400440 - 0x00000000004005c2 is .text
	0x00000000004005c4 - 0x00000000004005cd is .fini
	0x00000000004005d0 - 0x00000000004005e0 is .rodata
	0x00000000004005e0 - 0x0000000000400614 is .eh_frame_hdr
	0x0000000000400618 - 0x000000000040070c is .eh_frame
	0x0000000000600e10 - 0x0000000000600e18 is .init_array
	0x0000000000600e18 - 0x0000000000600e20 is .fini_array
	0x0000000000600e20 - 0x0000000000600e28 is .jcr
	0x0000000000600e28 - 0x0000000000600ff8 is .dynamic
	0x0000000000600ff8 - 0x0000000000601000 is .got
	0x0000000000601000 - 0x0000000000601030 is .got.plt
	0x0000000000601030 - 0x0000000000601040 is .data
	0x0000000000601040 - 0x0000000000601048 is .bss

当调试没有调试信息的程序时,直接运行start命令是没有效果的:

(gdb) start
Function "main" not defined.

如果不知道main在何处,那么可以在程序入口处打断点。先通过readelf或者进入gdb,执行info files获得入口地址,然后:

(gdb) b *0x400440
(gdb) r

(2)保存已经设置的断点

在gdb中,可以使用如下命令将设置的断点保存下来:

(gdb) save breakpoints file-name-to-save

下此调试时,可以使用如下命令批量设置保存的断点:

(gdb) source file-name-to-save
(gdb) info breakpoints 
Num     Type           Disp Enb Address            What
1       breakpoint     keep y   0x00000000005a7af0 in gdb_main at /home/xmj/project/binutils-trunk/gdb/main.c:1061
2       breakpoint     keep y   0x00000000005a6bd0 in captured_main at /home/xmj/project/binutils-trunk/gdb/main.c:310
3       breakpoint     keep y   0x00000000005a68b0 in captured_command_loop at /home/xmj/project/binutils-trunk/gdb/main.c:

(3)设置临时断点tbreak命令

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

typedef struct
{
        int a;
        int b;
        int c;
        int d;
        pthread_mutex_t mutex;
}ex_st;

int main(void) {
        ex_st st = {1, 2, 3, 4, PTHREAD_MUTEX_INITIALIZER};
        printf("%d,%d,%d,%d\n", st.a, st.b, st.c, st.d);
        return 0;
}

在使用gdb时,如果想让断点只生效一次,可以使用“tbreak”命令(缩写为:tb)。以上面程序为例:


                
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值