2

GDB recently introduced the compile command to inject code at runtime, see this answer for requirements and a minimal example.

But I noticed that a few things do not work as if I had written them in the original source code at the current location:

  • compile code return; does not end the current function, only the injected code.

    Hypothesis: code runs in a new stack frame, but one in which local variables are still visible.

  • register modification fails, e.g.:

    compile code asm volatile ("mov $0x123, %rbp");
    p $rbp
    

    Output: not 0x123.

    Hypothesis: registers are all saved and restored on the function run.

Besides those, the documentation clearly explains that injected code symbols and types are not visible outside.

So what is the general theory / full list of those constructs that "do not work"?

The GNU Cauldron presentation of the feature contains an overview of the feature usage and internals: video, presentation

The feature is implemented on the compile/ subdirectory of the 7.9.1 GDB source code.

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

1 Answers1

3

The compile command works by emitting a new function, compiling it with gcc, and then invoking the function from gdb (an "inferior function call" in gdb lingo).

The code generator does have some special features to make it possible to access local variables. In particular it translates DWARF location expressions to C. References to registers are translated into references to fields in a special struct. gdb arranges to copy the relevant registers into an instance of this struct when performing the inferior call. After the call has completed, it copies the registers back out -- this allows writes to local variables.

This description should, I think, make it clearer what will work and what will not. I would expect return and other flow-of-control operations (break, continue, goto) not to work.

Writing to a register should work, but only for registers which are needed by some location expression. This could perhaps be fixed; though I believe right now only the necessary registers are passed in for performance reasons.

I don't know what would happen if your compiled code calls longjmp or throw (well, when C++ is implemented). Probably madness.

One thing worth knowing is that this code was designed so that a future patch could add compiled breakpoint conditions, perhaps in conjunction with something like dyninst.

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