dprintf 与 break + 命令 + 继续有什么区别



例如:

dprintf main,"hellon"
run

生成与以下内容相同的输出:

break main
commands
  silent
  printf "hellon"
  continue
end
run

使用dprintfcommands有显着的优势,例如它要快得多(如果是这样,为什么?(,或者具有一些不同的功能?

我想 dprintf 在理论上可以更快,因为它理论上可以使用类似于 compile code GDB 命令的机制编译和注入代码。

还是主要是一个方便的命令?

在 7.9.1 源代码中,定义 dprintfbreakpoint.c:dprintf_command 调用create_breakpoint这也是break_command调用的内容,因此它们似乎都使用相同的底层机制。

主要区别在于dprintf传递dprintf_breakpoint_ops结构,该结构具有不同的回调并在initialize_breakpoint_ops处初始化。

dprintf存储命令字符串列表,与commands命令非常相似,具体取决于设置。它们是:

  • 设置为update_dprintf_command_list
  • 在内部进行type == bp_dprintf检查后被调用init_breakpoint_sal
  • create_breakpoint调用.

到达断点时:

  • bpstat_stop_status 被调用并调用到达的断点的b->ops->after_condition_true (bs);
  • dprintf after_condition_true dprintf_after_condition_true
  • bpstat_do_actions_1运行命令

快速基准测试

循环.c

#include <inttypes.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
int main(int argc, char **argv) {
    uintmax_t i, j, period, max;
    if (argc > 1) {
        max = strtoumax(argv[1], NULL, 10);
    } else {
        max = 10;
    }
    if (argc > 2) {
        period = strtoumax(argv[2], NULL, 10);
    } else {
        period = 1;
    }
    i = 0;
    j = 0;
    while (1) {
        if (period != 0 && i % period == 0) {
            printf("%jun", j);
            j++;
        }
        i++; /* line 25 */
        if (i == max)
            break;
    }
}

编译并运行:

gcc -ggdb3 -O0 -std=c99 -Wall -Wextra -pedantic -o loop.out loop.c

loop.gdb

b 25
commands
silent
printf "%dn", i
c
end

基准:

$ time gdb -n -q -batch -ex 'tb 39' -ex run -ex 'compile code printf("hello: %dn", i)' -ex c -args ./loop.out 10000 0

因此,我们看到dprintfcommands都大大减慢了速度,并且dprintf仅比同等commands略快。

我问过是否有办法使用 compile code 来加快速度:GDB 编译代码,执行后不要删除注入的代码

在 Ubuntu 22.10、GDB 12.1 上测试。

有两个主要区别。

首先,dprintf有一些额外的输出模式,可用于使其以其他方式工作。 有关详细信息,请参阅 help set dprintf-channel 或手册。 我认为这些模式是dprintf被添加为单独实体的原因;尽管同时它们相当专业,不太可能引起普遍的兴趣。

不过,更有用的是,dprintf不会干扰next。 如果你写一个断点并使用commands,然后next这样的断点,gdb 会忘记next,就像你键入了continue一样。 这是 gdb 脚本语言中一个长期存在的奇怪现象。 dprintf没有这个问题。 (如果您需要来自普通断点的类似功能,则可以从 Python 执行此操作。

最新更新