gdb入门系列5
mufiye 内核新手

GDB入门系列5

改变程序的执行

一旦使用GDB挂上被调试程序,当程序运行起来后,你可以根据自己的调试思路来动态地在GDB中更改当前被调试程序的运行线路或是其变量的值,这个强大的功能能够让你更好的调试你的程序,比如,你可以在程序的一次运行中走遍程序的所有分支。

一、修改变量值

  • whatis
    打印该变量的类型
  • set var =47
    设置该变量的值

Lab

增加的代码:

1
2
3
4
5
6
int val = 0;
if(val == 0){
printf("go in the val0 case\n");
}else if(val == 1){
printf("changed, go in the val1 case\n");
}

gdb调试:

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

Breakpoint 1, main (argc=1, argv=0x7fffffffe148) at tst.c:27
27 if(val == 0){
(gdb) whatis val
type = int
(gdb) set var val = 1
(gdb) c
Continuing.
changed, go in the val1 case
result[1-100] = 5050
result[1-250] = 31125
[Inferior 1 (process 3045980) exited normally]

二、跳转执行

  • jump

          指定下一条语句的运行点。<linespce>可以是文件的行号,可以是file:line格式,可以是+num这种偏移量格式。表式着下一条运行语句从哪里开始
    
  • jump

          这里的<address>是代码行的内存地址。
    
  • set $pc = 0x485
    熟悉汇编的人都知道,程序运行时,有一个寄存器用于保存当前代码所在的内存地址。所以,jump命令也就是改变了这个寄存器中的值。于是,你可以使用“set $pc”来更改跳转执行的地址。

Lab

1
2
3
4
5
6
7
8
9
10
11
12
13
14
(gdb) break 25
Breakpoint 1 at 0x1283: file tst.c, line 25.
(gdb) r
Starting program: /home/ubuntu/learn_gdb/tst

Breakpoint 1, main (argc=1, argv=0x7fffffffe148) at tst.c:25
25 j++;
(gdb) jump 27
Continuing at 0x55555555528b.
j is: 1
go in the val0 case
result[1-100] = 5050
result[1-250] = 31125
[Inferior 1 (process 3048823) exited normally]

三、产生信号量

  •     signal <singal>
        使用singal命令,可以产生一个信号量给被调试的程序。如:中断信号Ctrl+C。这非常方便于程序的调试,可以在程序运行的任意位置设置断点,并在该断点用GDB产生一个信号量,这种精确地在某处产生信号非常有利程序的调试。UNIX的系统信号量通常从1到15。所以<singal>取值也在这个范围。
    

四、强制函数返回

  • return
    如果你的调试断点在某个函数中,并还有语句没有执行完。你可以使用return命令强制函数忽略还没有执行的语句并返回。使用return命令取消当前函数的执行,并立即返回,如果指定了,那么该表达式的值会被认作函数的返回值。

Lab

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
(gdb) break func
Breakpoint 1 at 0x1189: file tst.c, line 4.
(gdb) r
Starting program: /home/ubuntu/learn_gdb/tst
go in the val0 case
result[1-100] = 5050

Breakpoint 1, func (n=32767) at tst.c:4
4 {
(gdb) s
5 int sum = 0, i;
(gdb) s
6 for (i = 0; i < n; i++)
(gdb) s
8 sum += i;
(gdb) s
6 for (i = 0; i < n; i++)
(gdb) s
8 sum += i;
(gdb) s
6 for (i = 0; i < n; i++)
(gdb) s
8 sum += i;
(gdb) s
6 for (i = 0; i < n; i++)
(gdb) return 11
Make func return now? (y or n) y
#0 0x0000555555555316 in main (argc=1, argv=0x7fffffffe148) at tst.c:44
44 printf("result[1-250] = %d \n", func(250));
(gdb) c
Continuing.
result[1-250] = 11
[Inferior 1 (process 3047076) exited normally]

五、强制调用函数

  •     call <expr>
        表达式中可以一是函数,以此达到强制调用函数的目的。并显示函数的返回值,如果函数返回值是void,那么就不显示。
        另一个相似的命令也可以完成这一功能——print,print后面可以跟表达式,所以也可以用他来调用函数,print和call的不同是,如果函数返回void,call则不显示,print则显示函数返回值,并把该值存入历史数据中。
    

What’s Next

  1. gdb官方文档
  2. gdb user manual
  3. gdb internals manual
  • 本文标题:gdb入门系列5
  • 本文作者:mufiye
  • 创建时间:2021-11-28 18:56:19
  • 本文链接:http://mufiye.github.io/2021/11/28/gdb入门系列5/
  • 版权声明:本博客所有文章除特别声明外,均采用 BY-NC-SA 许可协议。转载请注明出处!
 评论