142

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;
}
J. Polfer
  • 12,251
  • 10
  • 54
  • 83
  • 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`. – Stuart Golodetz Dec 01 '10 at 18:49
  • @Stuart - Fixed. Should have done that a while ago. – J. Polfer Jan 05 '11 at 17:10
  • 5
    @J.Polfer: The `return 0` is not necessary, though, and is just noise! – Lightness Races in Orbit Mar 06 '15 at 15:19
  • @LightnessRacesinOrbit the `return 0;` is 100% necessary. Besides the warning your compiler *should* throw at you, this can corrupt the stack on older/embedded systems, and as such should ALWAYS be done out of habit and correctness. Forget a return in other places in your code and you're guaranteed to pay for it on modern desktop systems, too. – Jimmio92 Dec 05 '21 at 05:20
  • [Is there a portable equivalent to DebugBreak()/__debugbreak?](https://stackoverflow.com/questions/173618/is-there-a-portable-equivalent-to-debugbreak-debugbreak) – handle Dec 12 '21 at 18:47
  • 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 ;-) – Jonathan Wakely Jan 04 '22 at 12:52
  • @JonathanWakely Maybe you meant that comment as helpful, but I took it the polar opposite. So let me address as calmly as I can muster. One, I mentioned your own code must return if you tell the compiler to expect it. Two, it *should* warn you. Just because the standard automatically fixes your mistakes because of a wrapper around `main` doesn't mean you should make them. Three, I use C++17 in clang. Four, I have literally encountered this as a bug in low level code. C/C++ can be used without the standard library and without an operating system. Take your "learn it again" attitude elsewhere. – Jimmio92 Jan 06 '22 at 01:40
  • 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**. – Jonathan Wakely Jan 06 '22 at 23:55

6 Answers6

132

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.

Håvard S
  • 23,244
  • 8
  • 61
  • 72
37

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).

  • Some platforms (e.g. Msys2), do not have `SIGTRAP` defined. – ergohack Feb 14 '21 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 Jul 18 '22 at 19:15
32

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.

Michael Kohne
  • 11,888
  • 3
  • 47
  • 79
J. Polfer
  • 12,251
  • 10
  • 54
  • 83
  • 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 Dec 01 '10 at 16:30
  • the question was about linux, so i guess we can assume that the gcc syntax will work for x86. – js. Dec 01 '10 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 Dec 01 '10 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 Mar 27 '14 at 17:49
  • 1
    In Linux, `int 3` raises a SIGTRAP. – Ciro Santilli OurBigBook.com Oct 18 '15 at 21:25
  • Nice and spooky. I like it. – Dellowar Nov 22 '17 at 00:13
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 .)

Jason Orendorff
  • 42,793
  • 6
  • 62
  • 96
  • 2
    As usual windows does not look like the others :) – mathk Apr 29 '11 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. – Jason Doucette Sep 20 '16 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`. – Jason Orendorff Sep 21 '16 at 00: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;
}
hek2mgl
  • 152,036
  • 28
  • 249
  • 266
  • 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 says reinstate Monica Jul 14 '16 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. – Benjamin Crawford Ctrl-Alt-Tut Nov 15 '19 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 Jul 21 '21 at 07:53
  • 2
    @Ralph `int $3` is only "what goes behind it" on x86 systems, which the question doesn't specify... – Benjamin Crawford Ctrl-Alt-Tut Sep 09 '21 at 22:11
0

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

dacap
  • 478
  • 3
  • 19