131

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
  • 11,811
  • 9
  • 53
  • 82
  • 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
  • @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
  • 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

127

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
  • 22,173
  • 6
  • 59
  • 70
31

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,661
  • 3
  • 44
  • 75
J. Polfer
  • 11,811
  • 9
  • 53
  • 82
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
  • 39,955
  • 4
  • 59
  • 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
22

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

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
  • 143,113
  • 25
  • 227
  • 253
  • 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
  • 2
    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
  • 448
  • 3
  • 19