菜鸟科技网

debug r命令

r 命令在不同的调试器中可能有细微差别,但其核心功能是运行或继续执行程序,它通常用于以下几种情况:

debug r命令-图1
(图片来源网络,侵删)
  1. 开始执行:当程序刚刚被加载到调试器中,尚未开始运行时,r 命令会启动程序并运行到第一个断点或程序结束。
  2. 继续执行:当程序因遇到断点或信号而暂停时,r 命令会让程序从当前暂停的位置继续向下运行,直到下一个断点或程序结束。
  3. 运行到结束:如果没有设置任何断点,r 命令会让程序一直运行直到正常退出。

下面我将分不同调试器来详细解释 r 命令的用法、输出和最佳实践。


GDB (GNU Debugger) - rrun

在 GDB 中,rrun 命令的缩写,这是启动和继续程序执行的最基本命令。

基本用法

# (gdb) r [arg1 arg2 ...]
  • r: 运行程序。
  • [arg1 arg2 ...]: 可选的命令行参数,如果你想给正在调试的程序传递参数,直接跟在 r 后面即可。

场景演示

假设我们有一个简单的 C 程序 test.c

// test.c
#include <stdio.h>
#include <stdlib.h>
int add(int a, int b) {
    printf("Inside add function: %d + %d\n", a, b);
    int result = a + b;
    return result;
}
int main(int argc, char *argv[]) {
    printf("Program started.\n");
    printf("Arguments received: %d\n", argc);
    int x = 10;
    int y = 20;
    int sum = add(x, y);
    printf("Sum is: %d\n", sum);
    printf("Program finished.\n");
    return 0;
}

编译时加上 -g 选项以包含调试信息:

debug r命令-图2
(图片来源网络,侵删)
gcc -g -o test test.c

调试过程:

gdb ./test

会话 1: 首次运行(无断点)

(gdb) r
Starting program: /path/to/test 
Program started.
Arguments received: 1
Inside add function: 10 + 20
Sum is: 30
Program finished.
[Inferior 1 (process 12345) exited normally]
(gdb) 
  • 解释:程序从头运行到尾,没有在任何地方暂停,因为没有任何断点。

会话 2: 设置断点后运行

(gdb) b add
Breakpoint 1 at 0x555555555129: file test.c, line 6.
(gdb) r
Starting program: /path/to/test 
Program started.
Arguments received: 1
Breakpoint 1, add (a=10, b=20) at test.c:6
6       printf("Inside add function: %d + %d\n", a, b);
(gdb) 
  • 解释
    1. b addadd 函数的入口处设置了一个断点。
    2. r 命令启动程序。
    3. 程序执行 main 函数中的打印语句。
    4. 当程序准备进入 add 函数时,它命中了断点1,执行暂停。
    5. GDB 打印出暂停位置:add 函数的第6行,并显示了当前局部变量的值。

会话 3: 继续执行

debug r命令-图3
(图片来源网络,侵删)
# 接着上面的会话,程序停在 add 函数
(gdb) n
7       int result = a + b;
(gdb) n
8       return result;
(gdb) n
main () at test.c:14
14      printf("Sum is: %d\n", sum);
(gdb) r
The program being debugged has been started already.
Start it from the beginning? (y or n) y
Starting program: /path/to/test 
Program started.
Arguments received: 1
Breakpoint 1, add (a=10, b=20) at test.c:6
6       printf("Inside add function: %d + %d\n", a, b);
(gdb) 
  • 解释
    1. 在程序暂停后,我们使用 n (next) 逐步执行。
    2. 当我们再次输入 r 时,GDB 询问是否要重新从头开始运行程序,这是因为程序已经在运行了,输入 y 表示是的,重新启动。
    3. 如果我们想从当前位置继续运行,应该使用 c (continue) 命令。

LLDB (LLVM Debugger) - runr

LLDB 是 macOS 和现代 BSD 系统上的默认调试器,其语法与 GDB 类似,但更现代化。

基本用法

# (lldb) run [arg1 arg2 ...]
# (lldb) r [arg1 arg2 ...]

用法与 GDB 完全相同。

场景演示

lldb ./test

会话 1: 设置断点后运行

(lldb) b add
Breakpoint 1: where = test`add(int, int), address = 0x0000000100003f69
(lldb) r
Process 12346 launched: '/path/to/test' (x86_64)
Process 12346 stopped
* thread #1, queue = 'com.apple.main-thread', stop reason = breakpoint 1.1
    frame #0: 0x0000000100003f69 test`add(int, int)(a=10, b=20) at test.c:6
   3   #include <stdlib.h>
   4   
   5   int add(int a, int b) {
-> 6     printf("Inside add function: %d + %d\n", a, b);
   7     int result = a + b;
   8     return result;
   9   }
(lldb)
  • 解释:输出信息格式不同,但核心功能一致,程序在 add 函数的断点处停止,并显示了当前的调用栈、寄存器、变量等信息。

继续执行

# 接着上面的会话
(lldb) c
Process 12346 resuming
Program started.
Arguments received: 1
Inside add function: 10 + 20
Sum is: 30
Program finished.
Process 12346 exited with status = 0 (0x00000000)
(lldb)
  • 解释:在 LLDB 中,ccontinue 的缩写,用于从当前位置继续运行,这与 GDB 中的 c 命令作用相同。r 命令在这里同样会询问是否要重新启动。

WinDbg / kd (Windows Debugger) - g (Go)

这是一个非常重要的区别,在 Windows 内核调试器 WinDbg 和用户模式调试器中,没有 r 命令来运行程序

  • r 命令在 WinDbg 中是 "Registers" 的缩写,用于显示和修改 CPU 寄存器。

要运行或继续执行程序,WinDbg 使用的是 g 命令(代表 "Go")。

基本用法

0:000> g [options]
  • g: 从当前指令位置继续执行程序,直到遇到断点、异常或程序结束。

场景演示

假设你已经在 WinDbg 中附加到了一个进程,或者已经加载了一个核心转储。

0:000> g
  • 解释
    • 如果这是第一次运行,程序将从入口点开始执行。
    • 如果程序之前因断点或异常而停止,g 命令会使其从停止点继续执行。
    • 当程序执行完毕或遇到下一个断点时,WinDbg 会再次获得控制权,并显示停止原因。

r (寄存器) 的区别

如果你错误地在 WinDbg 中输入 r,你会看到类似这样的输出:

0:000> r
rax=0000000000000000 rbx=0000000000000000 rcx=00000077d5e6b6d8
rdx=0000000000000000 rsi=0000000000000000 rdi=0000000000000000
rip=00007ff8a5b510e2 rsp=00000077d5e6b6d8 rbp=00000077d5e6b6f8
 r8=0000000000000000  r9=0000000000000000 r10=0000000000000000
r11=0000000000000246 r12=00000077d5e6b730 r13=00000077d5e6b760
r14=00000077d5e6b790 r15=00000077d5e6b7c0
 iopl=0         nv up ei ng nz na po nc
cs=0033  ss=002b  ds=002b  es=002b  fs=0053  gs=002b             efl=00000246
ntdll!LdrpInitialize+0x82:
00007ff8`a5b510e2 cc              int     3

这清晰地显示了所有 CPU 寄存器的当前值和下一条要执行的指令,与“运行”程序完全无关。


总结与对比

调试器 运行/继续命令 命令全称 重要说明
GDB r run 用于启动或重新启动程序,在程序暂停后,用 c (continue) 来继续。
LLDB r run 行为与 GDB 几乎完全一致。
WinDbg g Go 注意r 命令是查看寄存器,不是运行程序!

最佳实践

  1. 明确你的调试器:在使用任何命令前,首先要清楚你在使用哪个调试器,因为它们的命令集可能不同。
  2. r vs c
    • 当程序尚未启动时,使用 r (GDB/LLDB) 或 g (WinDbg)。
    • 当程序已经暂停(在断点处)时,使用 c (GDB/LLDB) 或 g (WinDbg) 来继续。
    • 在 GDB/LLDB 中,如果程序已暂停,你再次输入 r,调试器通常会询问你是否要重新启动。
  3. 传递参数:在 rg 命令后直接跟上命令行参数是调试带参数程序最方便的方式。

希望这个详细的解释能帮助你彻底理解 r 命令在不同调试环境下的作用和用法!

分享:
扫描分享到社交APP
上一篇
下一篇