3

For example:

dprintf main,"hello\n"
run

Generates the same output as:

break main
commands
  silent
  printf "hello\n"
  continue
end
run

Is there a significant advantage to using dprintf over commands, e.g. it is considerably faster (if so why?), or has some different functionality?

I imagine that dprintf could be in theory faster as it could in theory compile and inject code with a mechanism analogous to the compile code GDB command.

Or is it mostly a convenience command?

Source

In the 7.9.1 source, breakpoint.c:dprintf_command, which defines dprintf, calls create_breakpoint which is also what break_command calls, so they both seem to use the same underlying mechanism.

The main difference is that dprintf passes the dprintf_breakpoint_ops structure, which has different callbacks and gets initialized at initialize_breakpoint_ops.

dprintf stores list of command strings much like that of commands command, depending on the settings. They are:

  • set at update_dprintf_command_list
  • which gets called on after a type == bp_dprintf check inside init_breakpoint_sal
  • which gets called by create_breakpoint.

When a breakpoint is reached:

  • bpstat_stop_status gets called and invokes b->ops->after_condition_true (bs); for the breakpoint reached
  • after_condition_true for dprintf is dprintf_after_condition_true
  • bpstat_do_actions_1 runs the commands

Quick benchmark

loop.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("%ju\n", j);
            j++;
        }
        i++; /* line 25 */
        if (i == max)
            break;
    }
}

Compile and run:

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

loop.gdb

b 25
commands
silent
printf "%d\n", i
c
end

Benchmark:

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

So we see that both dprintf and commands slow things down massively, and that dprintf is only marginally faster than an equivalent commands.

I've asked if there's a way to use compile code to speed things up at: GDB compile code and don't remove injected code after execution

Tested on Ubuntu 22.10, GDB 12.1.

Ciro Santilli OurBigBook.com
  • 347,512
  • 102
  • 1,199
  • 985

1 Answers1

4

There are two main differences.

First, dprintf has some additional output modes that can be used to make it work in other ways. See help set dprintf-channel, or the manual, for more information. I think these modes are the reason that dprintf was added as a separate entity; though at the same time they are fairly specialized and unlikely to be of general interest.

More usefully, though, dprintf doesn't interfere with next. If you write a breakpoint and use commands, and then next over such a breakpoint, gdb will forget about the next and act as if you had typed continue. This is a longstanding oddity in the gdb scripting language. dprintf doesn't suffer from this problem. (If you need similar functionality from an ordinary breakpoint, you can do this from Python.)

Tom Tromey
  • 21,507
  • 2
  • 45
  • 63