148

How can I set a breakpoint in C or C++ code programatically that will work for gdb on Linux?

I.e.:

int main(int argc, char** argv)
{
    /* set breakpoint here! */
    int a = 3;
    a++;  /*  In gdb> print a;  expect result to be 3 */
    return 0;
}
8
  • 9
    Very much a side note (sorry to nitpick), but if you're worried about portability then you're probably also worried about correctness - hence int main rather than void main. Commented Dec 1, 2010 at 18:49
  • @Stuart - Fixed. Should have done that a while ago.
    – J. Polfer
    Commented Jan 5, 2011 at 17:10
  • 5
    @J.Polfer: The return 0 is not necessary, though, and is just noise! Commented Mar 6, 2015 at 15:19
  • 1
    @Jimmio92 No, main is special in all versions of C++ and also in C since C99. Reaching the final } of main without returning is equivalent to return 0; so the compiler should not warn, and it cannot corrupt anything. In C89 it's undefined, but that's the exception to the rule, not the general case as you imply by "100% necessary". C++98 and C99 are not new, time to update your knowledge ;-) Commented Jan 4, 2022 at 12:52
  • 1
    It's not a mistake though. The standard guarantees the behaviour, relying on that is not a mistake. You said "100% necessary" and that's just wrong. Commented Jan 6, 2022 at 23:55

8 Answers 8

133

One way is to signal an interrupt:

#include <csignal>

// Generate an interrupt
std::raise(SIGINT);

In C:

#include <signal.h>
raise(SIGINT);

UPDATE: Microsoft Docs says that Windows doesn't really support SIGINT, so if portability is a concern, you're probably better off using SIGABRT.

SIGINT is not supported for any Win32 application. When a CTRL+C interrupt occurs, Win32 operating systems generate a new thread to specifically handle that interrupt. This can cause a single-thread application, such as one in UNIX, to become multithreaded and cause unexpected behavior.

6
  • Yes, this should work across operating systems/compilers/debuggers.
    – Håvard S
    Commented Dec 1, 2010 at 16:24
  • 1
    I don't know other debuggers, but gdb is pretty flexible about signal handling.
    – Cascabel
    Commented Dec 1, 2010 at 16:25
  • 9
    We found SIGTRAP better on some Unices Commented Jul 8, 2012 at 9:24
  • 1
    in Windows, MSVC you can use __debug_break, DebugBreak or _asm {int 3}. Commented Jan 27, 2015 at 1:11
  • 3
    @FernandoGonzalezSanchez: actually the function name is __debugbreak() and NOT __debug_break(), as you can see here
    – Morix Dev
    Commented May 27, 2015 at 7:08
52

Disappointing to see so many answers not using the dedicated signal for software breakpoints, SIGTRAP:

#include <signal.h>

raise(SIGTRAP); // At the location of the BP.

On MSVC/MinGW, you should use DebugBreak, or the __debugbreak intrinsic. A simple #ifdef can handle both cases (POSIX and Win32).

2
  • Some platforms (e.g. Msys2), do not have SIGTRAP defined.
    – ergohack
    Commented Feb 14, 2021 at 23:31
  • 1
    For whatever reason, my debugger didn't always respect the signal, but if I issued it twice in row (like raise(SIGTRAP); raise(SIGTRAP);) , that seemed to work reliably!
    – BuvinJ
    Commented Jul 18, 2022 at 19:15
33

By looking here, I found the following way:

void main(int argc, char** argv)
{
    asm("int $3");
    int a = 3;
    a++;  //  In gdb> print a;  expect result to be 3
}

This seems a touch hackish to me. And I think this only works on x86 architecture.

6
  • 3
    And only with compilers supporting the AT&T assembly syntax. In particular, Microsoft's compiler (cl.exe) does not support this syntax, but uses a different syntax.
    – Håvard S
    Commented Dec 1, 2010 at 16:30
  • the question was about linux, so i guess we can assume that the gcc syntax will work for x86.
    – js.
    Commented Dec 1, 2010 at 16:55
  • BTW - I did try the above on my x86 machine and it did work. I was curious if there was a better way of doing it. Looks like there is.
    – J. Polfer
    Commented Dec 1, 2010 at 17:02
  • 2
    I am using mingw on windows so the other suggestions can't help me. Raising SIGINT signal just terminates the application, SIGTRAP is not defined in mingw headers... Using int instruction actually sends SIGTRAP and gdb breaks nicely on the appropriate line.
    – Machta
    Commented Mar 27, 2014 at 17:49
  • 1
    In Linux, int 3 raises a SIGTRAP. Commented Oct 18, 2015 at 21:25
29

In a project I work on, we do this:

raise(SIGABRT);  /* To continue from here in GDB: "signal 0". */

(In our case we wanted to crash hard if this happened outside the debugger, generating a crash report if possible. That's one reason we used SIGABRT. Doing this portably across Windows, Mac, and Linux took several attempts. We ended up with a few #ifdefs, helpfully commented here: http://hg.mozilla.org/mozilla-central/file/98fa9c0cff7a/js/src/jsutil.cpp#l66 .)

3
  • 2
    As usual windows does not look like the others :)
    – mathk
    Commented Apr 29, 2011 at 22:58
  • Is it possible to issue "signal 0" to continue program the program in a paused state? It would be nice to be able to use 'n' or 's' from this point, without a 'c' being issued. Commented Sep 20, 2016 at 21:18
  • 2
    @JasonDoucette If you really just want the program to pause, you might want to add a breakpoint() function in your program (it can be empty or just contain a print statement) and add break breakpoint to your ~/.gdbinit. Commented Sep 21, 2016 at 0:00
13

__asm__("int $3"); should work:

int main(int argc, char** argv)
{
    /* set breakpoint here! */
    int a = 3;
    __asm__("int $3");
    a++;  /*  In gdb> print a;  expect result to be 3 */
    return 0;
}
4
  • 1
    I like to #define this, so that I don't have toi remember the syntax. I have it sprinkled throughout my code, sometimes in place of assert(), since stopping the debiugger let's me examine all variables & the stack. And, of course, like assert, I don't have to remove it for production code
    – Mawg
    Commented Jul 14, 2016 at 14:40
  • 3
    Interesting that this has 10 upvotes when the question constraints of "Linux" and "GDB" give plenty of options outside of resorting to assembly, which should always be a last resort for portability's sake if nothing else. Please see some of the other answers. Commented Nov 15, 2019 at 20:52
  • @BenjaminCrawfordCtrl-Alt-Tut In this specific case conceptually raising a SIGTRAP signal is a good idea. Of course the answer could be improved by specifying to do raise() instead, but it is valuable to see what goes behind it.
    – Ralph
    Commented Jul 21, 2021 at 7:53
  • 2
    @Ralph int $3 is only "what goes behind it" on x86 systems, which the question doesn't specify... Commented Sep 9, 2021 at 22:11
0

On OS X you can just call std::abort() (it might be the same on Linux)

2
  • Which library ?
    – Alex
    Commented Jul 12, 2017 at 15:31
  • 1
    This is part of the standard C++ library and is cross-platform where C++11-compliant compilers exist. This however, raises SIGABRT, which is not really an appropriate signal to raise in this instance. Commented Oct 9, 2019 at 20:27
0

<debugging> will be available in C++26: std::breakpoint, std::breakpoint_if_debugging and std::is_debugger_present.

The cppreference documentations for std::breakpoint and std::is_debugger_present also mention some of the current solutions.

0

for ARM there is asm("BKPT");

https://developer.arm.com/documentation/dui0473/m/arm-and-thumb-instructions/bkpt

Not the answer you're looking for? Browse other questions tagged or ask your own question.