Git Product home page Git Product logo

debugbreak's Introduction

Debug Break

debugbreak.h allows you to put breakpoints in your C/C++ code with a call to debug_break():

#include <stdio.h>
#include "debugbreak.h"

int main()
{
	debug_break(); /* will break into debugger */
	printf("hello world\n");
	return 0;
}
  • Include one header file and insert calls to debug_break() in the code where you wish to break into the debugger.
  • Supports GCC, Clang and MSVC.
  • Works well on ARM, AArch64, i686, x86-64 and has a fallback code path for other architectures.
  • Works like the DebugBreak() fuction provided by Windows and QNX.

License: the very permissive 2-Clause BSD.

Implementation Notes

The requirements for the debug_break() function are:

  • Act as a compiler code motion barrier
  • Don't cause the compiler optimizers to think the code following it can be removed
  • Trigger a software breakpoint hit when executed (e.g. SIGTRAP on Linux)
  • GDB commands like continue, next, step, stepi must work after a debug_break() hit

Ideally, both GCC and Clang would provide a __builtin_debugger() built-in funciton that satisfies the above on all architectures and operating systems. Unfortunately, this kind of compiler support is not yet widely available. GCC's __builtin_trap() causes the optimizers to think the code follwing can be removed (test/trap.c):

#include <stdio.h>

int main()
{
	__builtin_trap();
	printf("hello world\n");
	return 0;
}
main
0x0000000000400390 <+0>:     0f 0b	ud2    

Notice how the call to printf() is not present in the assembly output.

Further, __builtin_trap() generates an ud2 instruction which triggers SIGILL instead of SIGTRAP on i386 / x86-64. This makes it necessary to change GDB's default behavior on SIGILL to not terminate the process being debugged:

(gdb) handle SIGILL stop nopass

Even after this, continuing execution in GDB doesn't work well on some GCC, GDB combinations.

On ARM, __builtin_trap() generates a call to abort(), making it even less suitable.

debug_break() generates an int3 instruction on i386 / x86-64 (test/break.c):

#include <stdio.h>
#include "debugbreak.h"
   
int main()
{
	debug_break();
	printf("hello world\n");
	return 0;
}
main
0x00000000004003d0 <+0>:     50	push   %rax
0x00000000004003d1 <+1>:     cc	int3   
0x00000000004003d2 <+2>:     bf a0 05 40 00	mov    $0x4005a0,%edi
0x00000000004003d7 <+7>:     e8 d4 ff ff ff	callq  0x4003b0 <puts@plt>
0x00000000004003dc <+12>:    31 c0	xor    %eax,%eax
0x00000000004003de <+14>:    5a	pop    %rdx
0x00000000004003df <+15>:    c3	retq   

which correctly trigges SIGTRAP and single-stepping in GDB after a debug_break() hit works well. Clang / LLVM also has a __builtin_trap() that generates ud2 but further provides __builtin_debugger() that generates int3 on i386 / x86-64.

On ARM, debug_break() generates .inst 0xe7f001f0 in ARM mode and .inst 0xde01 in Thumb mode which correctly triggers SIGTRAP on Linux. Unfortunately, stepping in GDB after a debug_break() hit doesn't work and requires a workaround like:

(gdb) set $l = 2
(gdb) tbreak *($pc + $l)
(gdb) jump   *($pc + $l)
(gdb) # Change $l from 2 to 4 for ARM mode

to jump over the instruction. A new GDB command, debugbreak-step, is defined in debugbreak-gdb.py to automate the above.

$ arm-none-linux-gnueabi-gdb -x debugbreak-gdb.py test/break-c++
<...>
(gdb) run
Program received signal SIGTRAP, Trace/breakpoint trap.
main () at test/break-c++.cc:6
6		debug_break();

(gdb) debugbreak-step

7		std::cout << "hello, world\n";

On AArch64, debug_break() generates .inst 0xd4200000.

On other architectures, debug_break() generates a call to raise(SIGTRAP).

Behavior on Different Architectures

Architecture debug_break()
x86/x86-64 int3
ARM mode, 32-bit .inst 0xe7f001f0
Thumb mode, 32-bit .inst 0xde01
AArch64, ARMv8 .inst 0xd4200000
MSVC compiler __debugbreak
Otherwise raise(SIGTRAP)

debugbreak's People

Contributors

scottt avatar inolen avatar dismine avatar

Watchers

James Cloos avatar pq avatar

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    ๐Ÿ–– Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. ๐Ÿ“Š๐Ÿ“ˆ๐ŸŽ‰

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google โค๏ธ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.