diff --git a/src/libs/vmisc/debugbreak.h b/src/libs/vmisc/debugbreak.h new file mode 100644 index 000000000..9a1926bbd --- /dev/null +++ b/src/libs/vmisc/debugbreak.h @@ -0,0 +1,128 @@ +/* Copyright (c) 2011-2015, Scott Tsai + * + * All rights reserved. + * + * Redistribution and use in source and binary forms, with or without + * modification, are permitted provided that the following conditions are met: + * + * 1. Redistributions of source code must retain the above copyright notice, + * this list of conditions and the following disclaimer. + * 2. Redistributions in binary form must reproduce the above copyright notice, + * this list of conditions and the following disclaimer in the documentation + * and/or other materials provided with the distribution. + * + * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" + * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE + * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE + * ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE + * LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR + * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF + * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS + * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN + * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE + * POSSIBILITY OF SUCH DAMAGE. + */ + +#ifndef DEBUG_BREAK_H +#define DEBUG_BREAK_H + +#ifdef _MSC_VER + +#define debug_break __debugbreak + +#else + +#include + +#ifdef __cplusplus +extern "C" { +#endif + +enum { + /* gcc optimizers consider code after __builtin_trap() dead. + * Making __builtin_trap() unsuitable for breaking into the debugger */ + DEBUG_BREAK_PREFER_BUILTIN_TRAP_TO_SIGTRAP = 0, +}; + +#if defined(__i386__) || defined(__x86_64__) +enum { HAVE_TRAP_INSTRUCTION = 1, }; +__attribute__((gnu_inline, always_inline)) +static void __inline__ trap_instruction(void) +{ + __asm__ volatile("int $0x03"); +} +#elif defined(__thumb__) +enum { HAVE_TRAP_INSTRUCTION = 1, }; +/* FIXME: handle __THUMB_INTERWORK__ */ +__attribute__((gnu_inline, always_inline)) +static void __inline__ trap_instruction(void) +{ + /* See 'arm-linux-tdep.c' in GDB source. + * Both instruction sequences below work. */ +#if 1 + /* 'eabi_linux_thumb_le_breakpoint' */ + __asm__ volatile(".inst 0xde01"); +#else + /* 'eabi_linux_thumb2_le_breakpoint' */ + __asm__ volatile(".inst.w 0xf7f0a000"); +#endif + + /* Known problem: + * After a breakpoint hit, can't stepi, step, or continue in GDB. + * 'step' stuck on the same instruction. + * + * Workaround: a new GDB command, + * 'debugbreak-step' is defined in debugbreak-gdb.py + * that does: + * (gdb) set $instruction_len = 2 + * (gdb) tbreak *($pc + $instruction_len) + * (gdb) jump *($pc + $instruction_len) + */ +} +#elif defined(__arm__) && !defined(__thumb__) +enum { HAVE_TRAP_INSTRUCTION = 1, }; +__attribute__((gnu_inline, always_inline)) +static void __inline__ trap_instruction(void) +{ + /* See 'arm-linux-tdep.c' in GDB source, + * 'eabi_linux_arm_le_breakpoint' */ + __asm__ volatile(".inst 0xe7f001f0"); + /* Has same known problem and workaround + * as Thumb mode */ +} +#elif defined(__aarch64__) +enum { HAVE_TRAP_INSTRUCTION = 1, }; +__attribute__((gnu_inline, always_inline)) +static void __inline__ trap_instruction(void) +{ + /* See 'aarch64-tdep.c' in GDB source, + * 'aarch64_default_breakpoint' */ + __asm__ volatile(".inst 0xd4200000"); +} +#else +enum { HAVE_TRAP_INSTRUCTION = 0, }; +#endif + +__attribute__((gnu_inline, always_inline)) +static void __inline__ debug_break(void) +{ + if (HAVE_TRAP_INSTRUCTION) { + trap_instruction(); + } else if (DEBUG_BREAK_PREFER_BUILTIN_TRAP_TO_SIGTRAP) { + /* raises SIGILL on Linux x86{,-64}, to continue in gdb: + * (gdb) handle SIGILL stop nopass + * */ + __builtin_trap(); + } else { + raise(SIGTRAP); + } +} + +#ifdef __cplusplus +} +#endif + +#endif + +#endif diff --git a/src/libs/vmisc/def.h b/src/libs/vmisc/def.h index 80b3ab5cd..2d4b4b016 100644 --- a/src/libs/vmisc/def.h +++ b/src/libs/vmisc/def.h @@ -36,6 +36,8 @@ #include #endif /* Q_OS_WIN */ +#include "debugbreak.h" + #define SceneSize 50000 #define DefPointRadius 1.5//mm @@ -160,7 +162,6 @@ enum class GSizes : unsigned char { ALL, * https://stackoverflow.com/questions/1721543/continue-to-debug-after-failed-assertion-on-linux-c-c */ #ifndef V_NO_ASSERT -#ifdef Q_OS_WIN32 #ifdef Q_CC_MSVC #define SCASSERT(cond) \ { \ @@ -168,11 +169,11 @@ enum class GSizes : unsigned char { ALL, { \ qDebug("ASSERT: %s in %s (%s:%u)", \ #cond, __FUNCSIG__, __FILE__, __LINE__); \ - DebugBreak(); \ + debug_break(); \ } \ } \ -#else // GCC (Windows) +#else // GCC/Clang #define SCASSERT(cond) \ { \ @@ -180,23 +181,12 @@ enum class GSizes : unsigned char { ALL, { \ qDebug("ASSERT: %s in %s (%s:%u)", \ #cond, __PRETTY_FUNCTION__, __FILE__, __LINE__);\ - DebugBreak(); \ + debug_break(); \ } \ } \ #endif /*Q_CC_MSVC*/ -#else // UNIX -#define SCASSERT(cond) \ -{ \ - if (!(cond)) \ - { \ - qDebug("ASSERT: %s in %s (%s:%u)", \ - #cond, __PRETTY_FUNCTION__, __FILE__, __LINE__);\ - std::raise(SIGTRAP); \ - } \ -} \ -#endif /* Q_OS_WIN32 */ #else // define but disable this function if debugging is not set #define SCASSERT(cond) qt_noop(); #endif /* V_NO_ASSERT */ diff --git a/src/libs/vmisc/vmisc.pri b/src/libs/vmisc/vmisc.pri index 4d29598c7..3f7187d56 100644 --- a/src/libs/vmisc/vmisc.pri +++ b/src/libs/vmisc/vmisc.pri @@ -25,4 +25,5 @@ HEADERS += \ $$PWD/vabstractapplication.h \ $$PWD/projectversion.h \ $$PWD/vcommonsettings.h \ - $$PWD/vtapesettings.h + $$PWD/vtapesettings.h \ + debugbreak.h