Set Breakpoint in C or C++ Code Programmatically for Gdb on Linux

Set breakpoint in C or C++ code programmatically for gdb on Linux

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.

Set GDB breakpoint in C file

Not as such, but you can insert some helpful function calls:

One option is to create a function:

void break_here ()
{
/* do nothing */
}

then call it wherever you want, but be careful it doesn't get inlined (put it in a different file, or add a "noinline" attribute).

Then, in GDB, just set a breakpoint on break_here, and you're done. If you find it tedious to set that breakpoint every time, you can create a file named .gdbinit in your home directory or in the current working directory that contains the breakpoint command.

Another option that works on Linux is to use a signal:

raise (SIGUSR1);

You could use any signal you like, but it's better to use one that doesn't kill your program (although you can configure GDB to not pass them onto your program, if you choose).

How to set a breakpoint programmatically in Fortran / Raise a SIGINT in Fortran

Just call the same C system function as in the linked answer

  use iso_c_binding, only: c_int

implicit none

interface
function raise(sig) bind(C, name="raise")
use iso_c_binding, only: c_int
integer(c_int) :: raise
integer(c_int), value :: sig
end function
end interface

integer(c_int), parameter :: SIGINT = 2


print *, raise(SIGINT)

end

It is probably not easy to avoid entering the SIGINT integer value manually. Consult your signal.h or man raise. The value 2 is for POSIX. On POSIX systems you can also use SIGTRAP = 5.

GDB moves breakpoint to different line

If you compile with optimization, several "strange" things might happen, see your compiler's documentation. This might lead to statements being removed or re-arranged, and when debugging, surprising behaviour.

To debug a program "by the line", compile without optimization.

Or live with the surprises; it's a source of delight, in any case.

How can I set breakpoint in GDB for open(2) syscall returning -1

Is it possible to set breakpoint in GDB in such way that it stops after open(2) syscall returns -1?

It's hard to do better than n.m.s answer for this narrow question, but I would argue that the question is posed incorrectly.

Of course, I can grep through the source code and find all open(2) invocations

That is part of your confusion: when you call open in a C program, you are not in fact executing open(2) system call. Rather, you are invoking an open(3) "stub" from your libc, and that stub will execute the open(2) system call for you.

And if you want to set a breakpoint when the stub is about to return -1, that is very easy.

Example:

/* t.c */
#include <sys/stat.h>
#include <fcntl.h>

int main()
{
int fd = open("/no/such/file", O_RDONLY);
return fd == -1 ? 0 : 1;
}

$ gcc -g t.c; gdb -q ./a.out
(gdb) start
Temporary breakpoint 1 at 0x4004fc: file t.c, line 6.
Starting program: /tmp/a.out

Temporary breakpoint 1, main () at t.c:6
6 int fd = open("/no/such/file", O_RDONLY);
(gdb) s
open64 () at ../sysdeps/unix/syscall-template.S:82
82 ../sysdeps/unix/syscall-template.S: No such file or directory.

Here we've reached the glibc system call stub. Let's disassemble it:

(gdb) disas
Dump of assembler code for function open64:
=> 0x00007ffff7b01d00 <+0>: cmpl $0x0,0x2d74ad(%rip) # 0x7ffff7dd91b4 <__libc_multiple_threads>
0x00007ffff7b01d07 <+7>: jne 0x7ffff7b01d19 <open64+25>
0x00007ffff7b01d09 <+0>: mov $0x2,%eax
0x00007ffff7b01d0e <+5>: syscall
0x00007ffff7b01d10 <+7>: cmp $0xfffffffffffff001,%rax
0x00007ffff7b01d16 <+13>: jae 0x7ffff7b01d49 <open64+73>
0x00007ffff7b01d18 <+15>: retq
0x00007ffff7b01d19 <+25>: sub $0x8,%rsp
0x00007ffff7b01d1d <+29>: callq 0x7ffff7b1d050 <__libc_enable_asynccancel>
0x00007ffff7b01d22 <+34>: mov %rax,(%rsp)
0x00007ffff7b01d26 <+38>: mov $0x2,%eax
0x00007ffff7b01d2b <+43>: syscall
0x00007ffff7b01d2d <+45>: mov (%rsp),%rdi
0x00007ffff7b01d31 <+49>: mov %rax,%rdx
0x00007ffff7b01d34 <+52>: callq 0x7ffff7b1d0b0 <__libc_disable_asynccancel>
0x00007ffff7b01d39 <+57>: mov %rdx,%rax
0x00007ffff7b01d3c <+60>: add $0x8,%rsp
0x00007ffff7b01d40 <+64>: cmp $0xfffffffffffff001,%rax
0x00007ffff7b01d46 <+70>: jae 0x7ffff7b01d49 <open64+73>
0x00007ffff7b01d48 <+72>: retq
0x00007ffff7b01d49 <+73>: mov 0x2d10d0(%rip),%rcx # 0x7ffff7dd2e20
0x00007ffff7b01d50 <+80>: xor %edx,%edx
0x00007ffff7b01d52 <+82>: sub %rax,%rdx
0x00007ffff7b01d55 <+85>: mov %edx,%fs:(%rcx)
0x00007ffff7b01d58 <+88>: or $0xffffffffffffffff,%rax
0x00007ffff7b01d5c <+92>: jmp 0x7ffff7b01d48 <open64+72>
End of assembler dump.

Here you can see that the stub behaves differently depending on whether the program has multiple threads or not. This has to do with asynchronous cancellation.

There are two syscall instructions, and in the general case we'd need to set a breakpoint after each one (but see below).

But this example is single-threaded, so I can set a single conditional breakpoint:

(gdb) b *0x00007ffff7b01d10 if $rax < 0
Breakpoint 2 at 0x7ffff7b01d10: file ../sysdeps/unix/syscall-template.S, line 82.
(gdb) c
Continuing.

Breakpoint 2, 0x00007ffff7b01d10 in __open_nocancel () at ../sysdeps/unix/syscall-template.S:82
82 in ../sysdeps/unix/syscall-template.S
(gdb) p $rax
$1 = -2

Voila, the open(2) system call returned -2, which the stub will translate into setting errno to ENOENT (which is 2 on this system) and returning -1.

If the open(2) succeeded, the condition $rax < 0 would be false, and GDB will keep going.

That is precisely the behavior one usually wants from GDB when looking for one failing system call among many succeeding ones.

Update:

As Chris Dodd points out, there are two syscalls, but on error they both branch to the same error-handling code (the code that sets errno). Thus, we can set an un-conditional breakpoint on *0x00007ffff7b01d49, and that breakpoint will fire only on failure.

This is much better, because conditional breakpoints slow down execution quite a lot when the condition is false (GDB has to stop the inferior, evaluate the condition, and resume the inferior if the condition is false).

gtest: where to put gdb breakpoint

what is the established practice of doing the same with gtest?

Reading gtest.cc, the closest I see is --gunit_break_on_failure, which should cause the code to execute INT3 trap on x86/Linux, and to call DebugBreak on Windows.

Update: the flag appears to have been renamed to --gtest_break_on_failure in latest public releases.



Related Topics



Leave a reply



Submit