C++26: The New Debugging Header

(sandordargo.com)

51 points | by jandeboevrie 4 hours ago

1 comments

  • amluto 3 hours ago
    Sadly the PR gets a detail wrong:

    > Implementations are expected to optimize the code generated to be as minimal as possible for the platform. For example, on X86 it’s expected that this produces a single INT3 instruction. The goal in this expectation is to place the debugger as close as possible in the caller of breakpoint() to improve the debugging experience for users.

    This is the wrong design on x86 at least with many debuggers. x86’s int3 is a trap and reports the address of the next instruction in the saved register state [0]. Most debuggers are not very clever and just use the saved address to generate the offending line of code and the call stack. But if the trap sequence is just int3, then the saved address could be outside the offending basic block or even outside the function entirely. gdb is certainly in the class of debuggers that get this wrong.

    The easy workaround is to generate int3; nop for the breakpoint instead of just int3. The saved address will point to the nop and the debugger will be happy.

    [0] FRED also reports the instruction length, allowing one to deduce the trapping address.

    • tux3 50 minutes ago
      I don't see how this happens in a C++ function, since breakpoint() is not noreturn you'd have to be doing something very strange for the next instruction to be outside the function. It's possible some debuggers will show the next line, and even then that seems like a debugger QoL issue that's fixable pretty mechanically. A soft breakpoint can come from CD 3 or CC, even if you don't get the instruction length from the CPU there aren't that many possibilities. I'm sure we don't need everyone to start inserting extra NOPs to get the desired behavior.
    • Joker_vD 1 hour ago
      ...there is no bloody way debuggers don't just subtract 1 from the EIP on INT 3. Like... there is no way. Right?
      • Maxatar 14 minutes ago
        If every single SIGTRAP was caused by an INT3 instruction, then this would work, but SIGTRAP can also be generated by single stepping where subtracting 1 would be incorrect.

        GDB already compensates for breakpoints it inserts itself because it knows their locations, so it subtracts 1 as you suggest. It could also recognize embedded INT3 instructions but that requires distinguishing their traps from other causes of SIGTRAP which is much more complicated. So instead GDB generally leaves the instruction pointer unchanged for embedded INT3 instructions.

        Here's a discussion of precisely this issue from the GDB developers:

        https://sourceware.org/pipermail/gdb/2009-February/034621.ht...

    • dingaling911 1 hour ago
      Obscure knowledge. I wanted to see how well our LLM overlords would detect this circumstance but without proper prompting, it was happy with "just generate int3"