gdb入门系列2
mufiye 内核新手

GDB入门系列2

一、help命令的使用

1
ubuntu@VM-0-14-ubuntu:~/learn_gdb$ gdb
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
(gdb) help
List of classes of commands:

aliases -- Aliases of other commands.
breakpoints -- Making program stop at certain points.
data -- Examining data.
files -- Specifying and examining files.
internals -- Maintenance commands.
obscure -- Obscure features.
running -- Running the program.
stack -- Examining the stack.
status -- Status inquiries.
support -- Support facilities.
--Type <RET> for more, q to quit, c to continue without paging--c
tracepoints -- Tracing of program execution without stopping the program.
user-defined -- User-defined commands.

Type "help" followed by a class name for a list of commands in that class.
Type "help all" for the list of all commands.
Type "help" followed by command name for full documentation.
Type "apropos word" to search for commands related to "word".
Type "apropos -v word" for full documentation of commands related to "word".
Command name abbreviations are allowed if unambiguous.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
(gdb) help breakpoints
Making program stop at certain points.

List of commands:

awatch -- Set a watchpoint for an expression.
break -- Set breakpoint at specified location.
break-range -- Set a breakpoint for an address range.
catch -- Set catchpoints to catch events.
catch assert -- Catch failed Ada assertions, when raised.
catch catch -- Catch an exception, when caught.
catch exception -- Catch Ada exceptions, when raised.
catch exec -- Catch calls to exec.
--Type <RET> for more, q to quit, c to continue without paging--c

二、关于Tab自动补全

  1. 补全用于命令(输入字符后按两下Tab,显示所有该字符开头的命令)
    1
    2
    (gdb) b
    backtrace bookmark break break-range bt
    1
    2
    (gdb) n
    new-ui next nexti ni nosharedlibrary
  2. 补全用于函数名(输入b ma后按下Tab会自动补全为b main)

三、在GDB中运行unix的shell程序

shell

1
2
(gdb) shell ls
tst tst.c

四、其它关于GDB调试

1. 设置程序运行参数

为了尝试设置运行参数,我更改了tst的代码,更改的部分如下所示。

1
2
3
4
5
6
7
8
9
...
...
main(int argc, char *argv[])
{
for(int index = 1; index<argc; index++){
printf("argv[%d]: %s\n",index,argv[index]);
}
...
...
1
2
3
4
5
6
7
8
(gdb) set args yemufi pdzhu
(gdb) r
Starting program: /home/ubuntu/learn_gdb/tst yemufi pdzhu
argv[1]: yemufi
argv[2]: pdzhu
result[1-100] = 5050 /nresult[1-250] = 31125 /n[Inferior 1 (process 2986037) exited normally]
(gdb) show args
Argument list to give program being debugged when it is started is "yemufi pdzhu".

2. 设置运行环境

1
2
3
4
path <dir> 可设定程序的运行路径。
show paths 查看程序的运行路径。
set environment varname [=value] 设置环境变量。如:set env USER=hchen
show environment [varname] 查看环境变量。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
(gdb) show paths
Executable and object file path: /home/ubuntu/.vscode-server/bin/ccbaa2d27e38e5afa3e5c21c1c7bef4657064247/bin:/home/ubuntu/.vscode-server/bin/ccbaa2d27e38e5afa3e5c21c1c7bef4657064247/bin:/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin:/usr/games:/usr/local/games
(gdb) show environment
SHELL=/bin/bash
COLORTERM=truecolor
TERM_PROGRAM_VERSION=1.62.3
HISTSIZE=1000
LANGUAGE=en_US.utf8:
HISTTIMEFORMAT=%F %T
PWD=/home/ubuntu/learn_gdb
LOGNAME=ubuntu
XDG_SESSION_TYPE=tty
VSCODE_GIT_ASKPASS_NODE=/home/ubuntu/.vscode-server/bin/ccbaa2d27e38e5afa3e5c21c1c7bef4657064247/node
MOTD_SHOWN=pam
HOME=/home/ubuntu
--Type <RET> for more, q to quit, c to continue without paging--

3. 设置工作目录

1
2
3
4
5
6
7
8
(gdb) cd dirA
Working directory /home/ubuntu/learn_gdb/dirA.
(gdb) pwd
Working directory /home/ubuntu/learn_gdb/dirA.
(gdb) cd ..
Working directory /home/ubuntu/learn_gdb.
(gdb) pwd
Working directory /home/ubuntu/learn_gdb.

4. 程序的输入输出

1
2
3
info terminal 显示你程序用到的终端的模式。
使用重定向控制程序输出。如:run > outfile
tty命令可以指写输入输出的终端设备。如:tty /dev/ttyb
1
2
3
4
(gdb) set args yemufi pdzhu big
(gdb) run > outfile
Starting program: /home/ubuntu/learn_gdb/tst > outfile
[Inferior 1 (process 2988331) exited normally]

以下是outfile的内容(之前代码最后的/n我已经改成了\n),很奇怪没有打印出输入参数相关的内容!

1
2
result[1-100] = 5050 
result[1-250] = 31125

5. 调试已经运行的程序

1、在UNIX下用ps查看正在运行的程序的PID(进程ID),然后用gdb PID格式挂接正在运行的程序。
2、先用gdb 关联上源代码,并进行gdb,在gdb中用attach命令来挂接进程的PID。并用detach来取消挂接的进程。

6. 断点相关

6.1设置断点

  • break
    在进入指定函数时停住。C++中可以使用class::function或function(type,type)格式来指定函数名。

  • break
    在指定行号停住。

  • break +offset
    在当前行号的前面的offset行停住。offiset为自然数。

  • break -offset
    在当前行号的后面的offset行停住。offiset为自然数。

  • break filename:linenum
    在源文件filename的linenum行处停住。

  • break filename:function
    在源文件filename的function函数的入口处停住。

  • break *address
    在程序运行的内存地址处停住。

  • break
    break命令没有参数时,表示在下一条指令处停住。

  • break … if
    …可以是上述的参数,condition表示条件,在条件成立时停住。比如在循环境体中,可以设置break if i=100,表示当i为100时停住程序。

6.2 查看断点时(n表示断点号)

  • info breakpoints [n]
  • info break [n]

6.3 维护停止点

  • clear
    清除所有的已定义的停止点。
  • clear
    清除所有设置在函数上的停止点。
  • clear filename:function
    清除所有设置在函数上的停止点。
  • clear
    清除所有设置在指定行上的停止点。
  • clear filename:linenum
    清除所有设置在指定行上的停止点。
  • delete [breakpoints] [range…]
    删除指定的断点,breakpoints为断点号。如果不指定断点号,则表示删除所有的断点。range 表示断点号的范围(如:3-7)。其简写命令为d。
  • disable [breakpoints] [range…]
    比删除更好的一种方法是disable停止点,disable了的停止点,GDB不会删除,当你还需要时,enable即可,就好像回收站一样。disable所指定的停止点,breakpoints为停止点号。如果什么都不指定,表示disable所有的停止点。简写命令是dis.
  • enable [breakpoints] [range…]
    enable所指定的停止点,breakpoints为停止点号。
  • enable [breakpoints] once range…
    enable所指定的停止点一次,当程序停止后,该停止点马上被GDB自动disable。
  • enable [breakpoints] delete range…
    enable所指定的停止点一次,当程序停止后,该停止点马上被GDB自动删除。
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    (gdb) break 20
    Breakpoint 1 at 0x11d7: file tst.c, line 20.
    (gdb) break 30
    Breakpoint 2 at 0x1210: file tst.c, line 30.
    (gdb) info breakpoints
    Num Type Disp Enb Address What
    1 breakpoint keep y 0x00000000000011d7 in main at tst.c:20
    2 breakpoint keep y 0x0000000000001210 in main at tst.c:30
    (gdb) disable breakpoints 1
    (gdb) info breakpoints
    Num Type Disp Enb Address What
    1 breakpoint keep n 0x00000000000011d7 in main at tst.c:20
    2 breakpoint keep y 0x0000000000001210 in main at tst.c:30
    (gdb) disable breakpoints 1-2
    (gdb) info breakpoints
    Num Type Disp Enb Address What
    1 breakpoint keep n 0x00000000000011d7 in main at tst.c:20
    2 breakpoint keep n 0x0000000000001210 in main at tst.c:30
    (gdb) enable breakpoints once 1-2
    (gdb) info breakpoints
    Num Type Disp Enb Address What
    1 breakpoint dis y 0x00000000000011d7 in main at tst.c:20
    2 breakpoint dis y 0x0000000000001210 in main at tst.c:30
    (gdb) break 31
    Breakpoint 3 at 0x1228: file tst.c, line 31.
    (gdb) r
    Starting program: /home/ubuntu/learn_gdb/tst

    Breakpoint 1, main (argc=1, argv=0x7fffffffe148) at tst.c:20
    20 j = 1;
    (gdb) c
    Continuing.

    Breakpoint 2, main (argc=1, argv=0x7fffffffe148) at tst.c:30
    30 printf("result[1-100] = %d \n", result);
    (gdb) c
    Continuing.
    result[1-100] = 5050

    Breakpoint 3, main (argc=1, argv=0x7fffffffe148) at tst.c:31
    31 printf("result[1-250] = %d \n", func(250));
    (gdb) info breakpoints
    Num Type Disp Enb Address What
    1 breakpoint dis n 0x00005555555551d7 in main at tst.c:20
    breakpoint already hit 1 time
    2 breakpoint dis n 0x0000555555555210 in main at tst.c:30
    breakpoint already hit 1 time
    3 breakpoint keep y 0x0000555555555228 in main at tst.c:31
    breakpoint already hit 1 time
    (gdb) c
    Continuing.
    result[1-250] = 31125
    [Inferior 1 (process 2996651) exited normally]
    (gdb) info breakpoints
    Num Type Disp Enb Address What
    1 breakpoint dis n 0x00005555555551d7 in main at tst.c:20
    breakpoint already hit 1 time
    2 breakpoint dis n 0x0000555555555210 in main at tst.c:30
    breakpoint already hit 1 time
    3 breakpoint keep y 0x0000555555555228 in main at tst.c:31
    breakpoint already hit 1 time
    (gdb) clear 31

    (gdb) info breakpoints
    Deleted breakpoint 3 Num Type Disp Enb Address What
    1 breakpoint dis n 0x00005555555551d7 in main at tst.c:20
    breakpoint already hit 1 time
    2 breakpoint dis n 0x0000555555555210 in main at tst.c:30
    breakpoint already hit 1 time
    (gdb) delete breakpoint 1
    (gdb) info breakpoints
    Num Type Disp Enb Address What
    2 breakpoint dis n 0x0000555555555210 in main at tst.c:30
    breakpoint already hit 1 time
    (gdb) clear
    No breakpoint at this line.
    (gdb) delete 1-10
    No breakpoint number 1.
    No breakpoint number 3.
    No breakpoint number 4.
    No breakpoint number 5.
    No breakpoint number 6.
    No breakpoint number 7.
    No breakpoint number 8.
    No breakpoint number 9.
    No breakpoint number 10.
    (gdb) info breakpoints
    No breakpoints or watchpoints.

6.4 停止条件维护

  • condition
    修改断点号为bnum的停止条件为expression。
  • condition
    清除断点号为bnum的停止条件。
  • ignore
    表示忽略断点号为bnum的停止条件count次。

6.5 为停止点设定运行命令

为断点号bnum指写一个命令列表。当程序被该断点停住时,gdb会依次运行命令列表中的命令。
commands [bnum]
… command-list …
end

1
2
3
4
5
6
7
8
9
10
11
12
13
(gdb) break 23
Breakpoint 1 at 0x11ec: file tst.c, line 24.
(gdb) commands 1
Type commands for breakpoint(s) 1, one per line.
End with a line saying just "end".
>printf "mufiye: it is broken at line 23\n"
>end
(gdb) r
Starting program: /home/ubuntu/learn_gdb/tst

Breakpoint 1, main (argc=1, argv=0x7fffffffe148) at tst.c:24
24 long result = 0;
mufiye: it is broken at line 23

6.6 断点菜单

在C++中,由于函数重载的存在,断点指定函数名可能会有多个函数与之对应。此时如果在该函数设置断点,会弹出菜单让你选择设置断点的具体函数。

6.7 恢复程序运行和单步调试

当程序被停住了,你可以用continue命令恢复程序的运行直到程序结束,或下一个断点到来。也可以使用step或next命令单步跟踪程序。

  • continue [ignore-count],c [ignore-count],fg [ignore-count]
    恢复程序运行,直到程序结束,或是下一个断点到来。ignore-count表示忽略其后的断点次数。continue,c,fg三个命令都是一样的意思。
  • step
    单步跟踪,如果有函数调用,他会进入该函数。进入函数的前提是,此函数被编译有debug信息。很像VC等工具中的step in。后面可以加count也可以不加,不加表示一条条地执行,加表示执行后面的count条指令,然后再停住。
  • next
    同样单步跟踪,如果有函数调用,他不会进入该函数。很像VC等工具中的step over。后面可以加count也可以不加,不加表示一条条地执行,加表示执行后面的count条指令,然后再停住。
  • set step-mode on
    打开step-mode模式,于是,在进行单步跟踪时,程序不会因为没有debug信息而不停住。这个参数有很利于查看机器码。
  • set step-mod off
    关闭step-mode模式。
  • finish
    运行程序,直到当前函数完成返回。并打印函数返回时的堆栈地址和返回值及参数值等信息。
  • until 或 u
    当你厌倦了在一个循环体内单步跟踪时,这个命令可以运行程序直到退出循环体。
  • stepi 或 si,nexti 或 ni
    以上两条都是单步跟踪一条机器指令!一条程序代码有可能由数条机器指令完成,stepi和nexti可以单步执行机器指令。与之一样有相同功能的命令是“display/i $pc” ,当运行完这个命令后,单步跟踪会在打出程序代码的同时打出机器指令(也就是汇编代码)
一个小lab

很好奇next的跳过函数是什么(现在发现这个问题好蠢),next的跳过函数只是把这个函数的运行当作一条语句来处理,实际上还是进入了这个函数。

1
2
3
4
5
6
7
...
...
int sum = 0;
sum = func(10);
printf("result[1-100] = %d \n", result);
printf("result[1-250] = %d \n", func(250));
}
1
2
3
4
5
6
7
8
9
10
11
12
13
(gdb) break 29
Breakpoint 1 at 0x1210: file tst.c, line 30.
(gdb) r
Starting program: /home/ubuntu/learn_gdb/tst

Breakpoint 1, main (argc=1, argv=0x7fffffffe148) at tst.c:30
30 int sum = 0;
(gdb) n
31 sum = func(10);
(gdb) n
32 printf("result[1-100] = %d \n", result);
(gdb) print sum
$1 = 45

6.8 信号

6.9 线程

7. 观察点相关

设置观察点

  • watch
    为表达式(变量)expr设置一个观察点。一量表达式值有变化时,马上停住程序。
  • rwatch
    当表达式(变量)expr被读时,停住程序。
  • awatch
    当表达式(变量)的值被读或被写时,停住程序。

查看观察点

  • info watchpoints
    列出当前所设置了的所有观察点。

观察点的实验

不知道为什么设置观察点以后continue,程序确实暂停了但是不会跳出gdb命令行让你继续输入命令,在我输入ctrl+z之后才会弹出来(就是其中的^Z之后)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
(gdb) break 24
Breakpoint 1 at 0x11ec: file tst.c, line 24.
(gdb) r
Starting program: /home/ubuntu/learn_gdb/tst

Breakpoint 1, main (argc=1, argv=0x7fffffffe148) at tst.c:24
24 long result = 0;
(gdb) watch i=3
Watchpoint 2: i=3
(gdb) info watchpoints
Num Type Disp Enb Address What
2 watchpoint keep y i=3
(gdb) c
Continuing.

^Z
Program received signal SIGTSTP, Stopped (user).
main (argc=1, argv=0x7fffffffe148) at tst.c:27
27 result += i;
(gdb) p i
$1 = 3

8. 设置捕捉点

  • catch
    当event发生时,停住程序。
  • tcatch
    只设置一次捕捉点,当程序停住以后,应点被自动删除。
  • event是什么?
    1、throw 一个C++抛出的异常。(throw为关键字)
    2、catch 一个C++捕捉到的异常。(catch为关键字)
    3、exec 调用系统调用exec时。(exec为关键字,目前此功能只在HP-UX下有用)
    4、fork 调用系统调用fork时。(fork为关键字,目前此功能只在HP-UX下有用)
    5、vfork 调用系统调用vfork时。(vfork为关键字,目前此功能只在HP-UX下有用)
    6、load 或 load 载入共享库(动态链接库)时。(load为关键字,目前此功能只在HP-UX下有用)
    7、unload 或 unload 卸载共享库(动态链接库)时。(unload为关键字,目前此功能只在HP-UX下有用)
  • 本文标题:gdb入门系列2
  • 本文作者:mufiye
  • 创建时间:2021-11-22 12:58:45
  • 本文链接:http://mufiye.github.io/2021/11/22/gdb入门系列2/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论