mirror of
https://github.com/scratchfoundation/bgfx.git
synced 2024-12-03 12:56:50 -05:00
217 lines
6.4 KiB
C
217 lines
6.4 KiB
C
|
// This code is in the public domain -- Ignacio Casta<74>o <castano@gmail.com>
|
|||
|
|
|||
|
#ifndef NV_CORE_DEBUG_H
|
|||
|
#define NV_CORE_DEBUG_H
|
|||
|
|
|||
|
#include "nvcore.h"
|
|||
|
|
|||
|
#include <stdarg.h> // va_list
|
|||
|
|
|||
|
|
|||
|
// Make sure we are using our assert.
|
|||
|
#undef assert
|
|||
|
|
|||
|
#define NV_ABORT_DEBUG 1
|
|||
|
#define NV_ABORT_IGNORE 2
|
|||
|
#define NV_ABORT_EXIT 3
|
|||
|
|
|||
|
#define nvNoAssert(exp) \
|
|||
|
NV_MULTI_LINE_MACRO_BEGIN \
|
|||
|
(void)sizeof(exp); \
|
|||
|
NV_MULTI_LINE_MACRO_END
|
|||
|
|
|||
|
#if NV_NO_ASSERT
|
|||
|
|
|||
|
# define nvAssert(exp) nvNoAssert(exp)
|
|||
|
# define nvCheck(exp) nvNoAssert(exp)
|
|||
|
# define nvDebugAssert(exp) nvNoAssert(exp)
|
|||
|
# define nvDebugCheck(exp) nvNoAssert(exp)
|
|||
|
# define nvDebugBreak() nvNoAssert(0)
|
|||
|
|
|||
|
#else // NV_NO_ASSERT
|
|||
|
|
|||
|
# if NV_CC_MSVC
|
|||
|
// @@ Does this work in msvc-6 and earlier?
|
|||
|
# define nvDebugBreak() __debugbreak()
|
|||
|
//# define nvDebugBreak() __asm { int 3 }
|
|||
|
# elif NV_OS_ORBIS
|
|||
|
# define nvDebugBreak() __debugbreak()
|
|||
|
# elif NV_CC_GNUC
|
|||
|
# define nvDebugBreak() __builtin_trap()
|
|||
|
# else
|
|||
|
# error "No nvDebugBreak()!"
|
|||
|
# endif
|
|||
|
|
|||
|
/*
|
|||
|
# elif NV_CC_GNUC || NV_CPU_PPC && NV_OS_DARWIN
|
|||
|
// @@ Use __builtin_trap() on GCC
|
|||
|
# define nvDebugBreak() __asm__ volatile ("trap")
|
|||
|
# elif (NV_CC_GNUC || NV_CPU_X86 || NV_CPU_X86_64) && NV_OS_DARWIN
|
|||
|
# define nvDebugBreak() __asm__ volatile ("int3")
|
|||
|
# elif NV_CC_GNUC || NV_CPU_X86 || NV_CPU_X86_64
|
|||
|
# define nvDebugBreak() __asm__ ( "int %0" : :"I"(3) )
|
|||
|
# else
|
|||
|
# include <signal.h>
|
|||
|
# define nvDebugBreak() raise(SIGTRAP)
|
|||
|
# endif
|
|||
|
*/
|
|||
|
|
|||
|
#define nvDebugBreakOnce() \
|
|||
|
NV_MULTI_LINE_MACRO_BEGIN \
|
|||
|
static bool firstTime = true; \
|
|||
|
if (firstTime) { firstTime = false; nvDebugBreak(); } \
|
|||
|
NV_MULTI_LINE_MACRO_END
|
|||
|
|
|||
|
#define nvAssertMacro(exp) \
|
|||
|
NV_MULTI_LINE_MACRO_BEGIN \
|
|||
|
if (!(exp)) { \
|
|||
|
if (nvAbort(#exp, __FILE__, __LINE__, __FUNC__) == NV_ABORT_DEBUG) { \
|
|||
|
nvDebugBreak(); \
|
|||
|
} \
|
|||
|
} \
|
|||
|
NV_MULTI_LINE_MACRO_END
|
|||
|
|
|||
|
// GCC, LLVM need "##" before the __VA_ARGS__, MSVC doesn't care
|
|||
|
#define nvAssertMacroWithIgnoreAll(exp,...) \
|
|||
|
NV_MULTI_LINE_MACRO_BEGIN \
|
|||
|
static bool ignoreAll = false; \
|
|||
|
if (!ignoreAll && !(exp)) { \
|
|||
|
int result = nvAbort(#exp, __FILE__, __LINE__, __FUNC__, ##__VA_ARGS__); \
|
|||
|
if (result == NV_ABORT_DEBUG) { \
|
|||
|
nvDebugBreak(); \
|
|||
|
} else if (result == NV_ABORT_IGNORE) { \
|
|||
|
ignoreAll = true; \
|
|||
|
} \
|
|||
|
} \
|
|||
|
NV_MULTI_LINE_MACRO_END
|
|||
|
|
|||
|
// Interesting assert macro from Insomniac:
|
|||
|
// http://www.gdcvault.com/play/1015319/Developing-Imperfect-Software-How-to
|
|||
|
// Used as follows:
|
|||
|
// if (nvCheck(i < count)) {
|
|||
|
// normal path
|
|||
|
// } else {
|
|||
|
// fixup code.
|
|||
|
// }
|
|||
|
// This style of macro could be combined with __builtin_expect to let the compiler know failure is unlikely.
|
|||
|
#define nvCheckMacro(exp) \
|
|||
|
(\
|
|||
|
(exp) ? true : ( \
|
|||
|
(nvAbort(#exp, __FILE__, __LINE__, __FUNC__) == NV_ABORT_DEBUG) ? (nvDebugBreak(), true) : ( false ) \
|
|||
|
) \
|
|||
|
)
|
|||
|
|
|||
|
|
|||
|
#define nvAssert(exp) nvAssertMacro(exp)
|
|||
|
#define nvCheck(exp) nvAssertMacro(exp)
|
|||
|
|
|||
|
#if defined(_DEBUG)
|
|||
|
# define nvDebugAssert(exp) nvAssertMacro(exp)
|
|||
|
# define nvDebugCheck(exp) nvAssertMacro(exp)
|
|||
|
#else // _DEBUG
|
|||
|
# define nvDebugAssert(exp) nvNoAssert(exp)
|
|||
|
# define nvDebugCheck(exp) nvNoAssert(exp)
|
|||
|
#endif // _DEBUG
|
|||
|
|
|||
|
#endif // NV_NO_ASSERT
|
|||
|
|
|||
|
// Use nvAssume for very simple expresions only: nvAssume(0), nvAssume(value == true), etc.
|
|||
|
/*#if !defined(_DEBUG)
|
|||
|
# if NV_CC_MSVC
|
|||
|
# define nvAssume(exp) __assume(exp)
|
|||
|
# else
|
|||
|
# define nvAssume(exp) nvCheck(exp)
|
|||
|
# endif
|
|||
|
#else
|
|||
|
# define nvAssume(exp) nvCheck(exp)
|
|||
|
#endif*/
|
|||
|
|
|||
|
#if defined(_DEBUG)
|
|||
|
# if NV_CC_MSVC
|
|||
|
# define nvUnreachable() nvAssert(0 && "unreachable"); __assume(0)
|
|||
|
# else
|
|||
|
# define nvUnreachable() nvAssert(0 && "unreachable"); __builtin_unreachable()
|
|||
|
# endif
|
|||
|
#else
|
|||
|
# if NV_CC_MSVC
|
|||
|
# define nvUnreachable() __assume(0)
|
|||
|
# else
|
|||
|
# define nvUnreachable() __builtin_unreachable()
|
|||
|
# endif
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
#define nvError(x) nvAbort(x, __FILE__, __LINE__, __FUNC__)
|
|||
|
#define nvWarning(x) nvDebugPrint("*** Warning %s/%d: %s\n", __FILE__, __LINE__, (x))
|
|||
|
|
|||
|
#ifndef NV_DEBUG_PRINT
|
|||
|
#define NV_DEBUG_PRINT 1 //defined(_DEBUG)
|
|||
|
#endif
|
|||
|
|
|||
|
#if NV_DEBUG_PRINT
|
|||
|
#define nvDebug(...) nvDebugPrint(__VA_ARGS__)
|
|||
|
#else
|
|||
|
#if NV_CC_MSVC
|
|||
|
#define nvDebug(...) __noop(__VA_ARGS__)
|
|||
|
#else
|
|||
|
#define nvDebug(...) ((void)0) // Non-msvc platforms do not evaluate arguments?
|
|||
|
#endif
|
|||
|
#endif
|
|||
|
|
|||
|
|
|||
|
NVCORE_API int nvAbort(const char *exp, const char *file, int line, const char * func = NULL, const char * msg = NULL, ...) __attribute__((format (printf, 5, 6)));
|
|||
|
NVCORE_API void NV_CDECL nvDebugPrint( const char *msg, ... ) __attribute__((format (printf, 1, 2)));
|
|||
|
|
|||
|
namespace nv
|
|||
|
{
|
|||
|
inline bool isValidPtr(const void * ptr) {
|
|||
|
#if NV_CPU_X86_64
|
|||
|
if (ptr == NULL) return true;
|
|||
|
if (reinterpret_cast<uint64>(ptr) < 0x10000ULL) return false;
|
|||
|
if (reinterpret_cast<uint64>(ptr) >= 0x000007FFFFFEFFFFULL) return false;
|
|||
|
#else
|
|||
|
if (reinterpret_cast<uint32>(ptr) == 0xcccccccc) return false;
|
|||
|
if (reinterpret_cast<uint32>(ptr) == 0xcdcdcdcd) return false;
|
|||
|
if (reinterpret_cast<uint32>(ptr) == 0xdddddddd) return false;
|
|||
|
if (reinterpret_cast<uint32>(ptr) == 0xffffffff) return false;
|
|||
|
#endif
|
|||
|
return true;
|
|||
|
}
|
|||
|
|
|||
|
// Message handler interface.
|
|||
|
struct MessageHandler {
|
|||
|
virtual void log(const char * str, va_list arg) = 0;
|
|||
|
virtual ~MessageHandler() {}
|
|||
|
};
|
|||
|
|
|||
|
// Assert handler interface.
|
|||
|
struct AssertHandler {
|
|||
|
virtual int assertion(const char *exp, const char *file, int line, const char *func, const char *msg, va_list arg) = 0;
|
|||
|
virtual ~AssertHandler() {}
|
|||
|
};
|
|||
|
|
|||
|
|
|||
|
namespace debug
|
|||
|
{
|
|||
|
NVCORE_API void dumpInfo();
|
|||
|
NVCORE_API void dumpCallstack( MessageHandler *messageHandler, int callstackLevelsToSkip = 0 );
|
|||
|
|
|||
|
NVCORE_API void setMessageHandler( MessageHandler * messageHandler );
|
|||
|
NVCORE_API void resetMessageHandler();
|
|||
|
|
|||
|
NVCORE_API void setAssertHandler( AssertHandler * assertHanlder );
|
|||
|
NVCORE_API void resetAssertHandler();
|
|||
|
|
|||
|
NVCORE_API void enableSigHandler(bool interactive);
|
|||
|
NVCORE_API void disableSigHandler();
|
|||
|
|
|||
|
NVCORE_API bool isDebuggerPresent();
|
|||
|
NVCORE_API bool attachToDebugger();
|
|||
|
|
|||
|
NVCORE_API void terminate(int code);
|
|||
|
}
|
|||
|
|
|||
|
} // nv namespace
|
|||
|
|
|||
|
#endif // NV_CORE_DEBUG_H
|