From 3addf429486eb886769a6d00d0538b675724f086 Mon Sep 17 00:00:00 2001 From: gingerBill Date: Wed, 2 Dec 2015 15:38:18 +0000 Subject: [PATCH] GB_ASSERT prints call stack --- README.md | 2 +- gb.hpp | 245 ++++++++++++++++++++++++++++++++++++++---------------- 2 files changed, 176 insertions(+), 71 deletions(-) diff --git a/README.md b/README.md index 167a82c..76b5070 100644 --- a/README.md +++ b/README.md @@ -5,7 +5,7 @@ gb single-file public domain libraries for C & C++ library | latest version | category | languages | description ----------------|----------------|----------|-----------|------------- **gb_string.h** | 0.93 | strings | C, C++ | A better string library for C & C++ -**gb.hpp** | 0.28 | misc | C++11 | (Experimental) A C++11 helper library without STL geared towards game development +**gb.hpp** | 0.29 | misc | C++11 | (Experimental) A C++11 helper library without STL geared towards game development **gb_math.hpp** | 0.03a | math | C++11 | A C++11 math library geared towards game development **gb_ini.h** | 0.91a | misc | C, C++ | A simple ini file loader library for C & C++ diff --git a/gb.hpp b/gb.hpp index 2f3967a..4804cc3 100644 --- a/gb.hpp +++ b/gb.hpp @@ -1,4 +1,4 @@ -// gb.hpp - v0.27 - public domain C++11 helper library - no warranty implied; use at your own risk +// gb.hpp - v0.29 - public domain C++11 helper library - no warranty implied; use at your own risk // (Experimental) A C++11 helper library without STL geared towards game development /* @@ -37,6 +37,50 @@ CONTENTS: - Hash Functions */ +/* +Version History: + 0.29 - GB_ASSERT prints call stack + 0.28 - Pool Allocator + 0.27 - Dealloc to Free & More Hashing Functions + 0.26a - Heap_Allocator Fix + 0.26 - Better Allocation system + 0.25a - Array bug fix + 0.25 - Faster Heap_Allocator for Windows using HeapAlloc + 0.24b - Even More Hash_Table Bug Fixes + 0.24a - Hash_Table Bug Fixes + 0.24 - More documentation and bug fixes + 0.23 - Move Semantics for Array and Hash_Table + 0.22 - Code rearrangment into namespaces + 0.21d - Fix array::free + 0.21c - Fix Another Typo causing unresolved external symbol + 0.21b - Typo fixes + 0.21a - Better `static` keywords + 0.21 - Separate Math Library + 0.20a - #ifndef for many macros + 0.20 - Angle + 0.19 - Cache friendly Transform and String fixes + 0.18 - Hash_Table bug fixes + 0.17 - Death to OOP + 0.16 - All References are const convention + 0.15 - Namespaced Types + 0.14 - Casts and Quaternion Look At + 0.13a - Fix Todos + 0.13 - Basic Type Traits + 0.12 - Random + 0.11 - Complex + 0.10 - Atomics + 0.09 - Bug Fixes + 0.08 - Matrix(2,3) + 0.07 - Bug Fixes + 0.06 - Os spec ideas + 0.05 - Transform Type and Quaternion Functions + 0.04 - String + 0.03 - Hash Functions + 0.02 - Hash Table + 0.01 - Initial Version +*/ + + #ifndef GB_INCLUDE_GB_HPP #define GB_INCLUDE_GB_HPP @@ -146,7 +190,7 @@ CONTENTS: #endif #endif -// TODO(bill): Check if this KEPLER_ENVIRONMENT works on clang +// TODO(bill): Check if this works on clang #if defined(__GNUC__) #if defined(__x86_64__) || defined(__ppc64__) #ifndef GB_ARCH_64_BIT @@ -239,40 +283,18 @@ CONTENTS: Type& operator=(Type&&) = delete #endif + + #if !defined(GB_ASSERT) #if !defined(NDEBUG) #define GB_ASSERT(x, ...) ((void)(::gb__assert_handler((x), #x, __FILE__, __LINE__, ##__VA_ARGS__))) // Helper function used as a better alternative to assert which allows for // optional printf style error messages - extern "C" inline void + extern "C" void gb__assert_handler(bool condition, const char* condition_str, const char* filename, size_t line, - const char* error_text = nullptr, ...) - { - if (condition) - return; - - fprintf(stderr, "ASSERT! %s(%lu): %s", filename, line, condition_str); - if (error_text) - { - fprintf(stderr, " - "); - - va_list args; - va_start(args, error_text); - vfprintf(stderr, error_text, args); - va_end(args); - } - fprintf(stderr, "\n"); - - #if defined(GB_COMPILER_MSVC) - __debugbreak(); - #elif defined(GB_COMPILER_GNU_GCC) - __builtin_trap(); - #else - #error Implement aborting function - #endif - } + const char* error_text = nullptr, ...); #else #define GB_ASSERT(x, ...) ((void)sizeof(x)) @@ -2231,8 +2253,133 @@ __GB_NAMESPACE_END // Implemenation // // // //////////////////////////////// + #if defined(GB_IMPLEMENTATION) __GB_NAMESPACE_START + + + +#if defined(GB_SYSTEM_WINDOWS) + + #include + #pragma comment(lib, "dbghelp.lib") + + internal_linkage void + gb__print_call_stack(FILE* out_stream) + { + SymInitialize(GetCurrentProcess(), nullptr, true); + SymSetOptions(SYMOPT_LOAD_LINES | SYMOPT_UNDNAME); + + DWORD mtype = {}; + CONTEXT ctx = {}; + ctx.ContextFlags = CONTEXT_CONTROL; + + RtlCaptureContext(&ctx); + + STACKFRAME64 stack = {}; + + #if defined(_M_IX86) + mtype = IMAGE_FILE_MACHINE_I386; + stack.AddrPC.Offset = ctx.Eip; + stack.AddrPC.Mode = AddrModeFlat; + stack.AddrFrame.Offset = ctx.Ebp; + stack.AddrFrame.Mode = AddrModeFlat; + stack.AddrStack.Offset = ctx.Esp; + stack.AddrStack.Mode = AddrModeFlat; + #elif defined(_M_X64) + mtype = IMAGE_FILE_MACHINE_AMD64; + stack.AddrPC.Offset = ctx.Rip; + stack.AddrPC.Mode = AddrModeFlat; + stack.AddrFrame.Offset = ctx.Rsp; + stack.AddrFrame.Mode = AddrModeFlat; + stack.AddrStack.Offset = ctx.Rsp; + stack.AddrStack.Mode = AddrModeFlat; + #endif + + DWORD ldsp = 0; + IMAGEHLP_LINE64 line = {}; + line.SizeOfStruct = sizeof(IMAGEHLP_LINE64); + + char buf[sizeof(SYMBOL_INFO) + (MAX_SYM_NAME * sizeof(TCHAR))]; + + SYMBOL_INFO* sym = reinterpret_cast(buf); + sym->SizeOfStruct = sizeof(SYMBOL_INFO); + sym->MaxNameLen = MAX_SYM_NAME; + + UINT layer_count = 0; + while (StackWalk64(mtype, + GetCurrentProcess(), GetCurrentThread(), + &stack, &ctx, nullptr, + SymFunctionTableAccess64, SymGetModuleBase64, nullptr)) + { + if (stack.AddrPC.Offset == 0) + break; + + BOOL result = SymGetLineFromAddr64(GetCurrentProcess(), stack.AddrPC.Offset, &ldsp, &line); + result = result && SymFromAddr(GetCurrentProcess(), stack.AddrPC.Offset, 0, sym); + + if (result) + { + fprintf(out_stream, + "\t[%u] `%s` (%s:%d)\n", + layer_count, sym->Name, line.FileName, line.LineNumber); + } + else + { + fprintf(out_stream, + "\t[%u] 0x%p\n", + layer_count, stack.AddrPC.Offset); + } + + layer_count++; + } + + SymCleanup(GetCurrentProcess()); + } +#else + #error gb__print_call_stack() not implemeneted + // TODO(bill): Implemenet gb__print_call_stack() +#endif + +// Helper function used as a better alternative to assert which allows for +// optional printf style error messages +inline void +gb__assert_handler(bool condition, const char* condition_str, + const char* filename, size_t line, + const char* error_text, ...) +{ + if (condition) + return; + + FILE* out_stream = stderr; + + fprintf(out_stream, "ASSERT! %s(%lu): %s", filename, line, condition_str); + if (error_text) + { + fprintf(out_stream, " - "); + + va_list args; + va_start(args, error_text); + vfprintf(out_stream, error_text, args); + va_end(args); + } + fprintf(out_stream, "\n"); + + fprintf(out_stream, "Stacktrack:\n"); + gb__print_call_stack(out_stream); + + + // TODO(bill): Are these decent breaking functions??? +#if defined(GB_COMPILER_MSVC) + __debugbreak(); +#elif defined(GB_COMPILER_GNU_GCC) + __builtin_trap(); +#else + #error Implement aborting function +#endif +} + + //////////////////////////////// // // // Memory // @@ -4143,45 +4290,3 @@ rdtsc() __GB_NAMESPACE_END #endif // GB_IMPLEMENTATION - -/* -Version History: - 0.28 - Pool Allocator - 0.27 - Dealloc to Free & More Hashing Functions - 0.26a - Heap_Allocator Fix - 0.26 - Better Allocation system - 0.25a - Array bug fix - 0.25 - Faster Heap_Allocator for Windows using HeapAlloc - 0.24b - Even More Hash_Table Bug Fixes - 0.24a - Hash_Table Bug Fixes - 0.24 - More documentation and bug fixes - 0.23 - Move Semantics for Array and Hash_Table - 0.22 - Code rearrangment into namespaces - 0.21d - Fix array::free - 0.21c - Fix Another Typo causing unresolved external symbol - 0.21b - Typo fixes - 0.21a - Better `static` keywords - 0.21 - Separate Math Library - 0.20a - #ifndef for many macros - 0.20 - Angle - 0.19 - Cache friendly Transform and String fixes - 0.18 - Hash_Table bug fixes - 0.17 - Death to OOP - 0.16 - All References are const convention - 0.15 - Namespaced Types - 0.14 - Casts and Quaternion Look At - 0.13a - Fix Todos - 0.13 - Basic Type Traits - 0.12 - Random - 0.11 - Complex - 0.10 - Atomics - 0.09 - Bug Fixes - 0.08 - Matrix(2,3) - 0.07 - Bug Fixes - 0.06 - Os spec ideas - 0.05 - Transform Type and Quaternion Functions - 0.04 - String - 0.03 - Hash Functions - 0.02 - Hash Table - 0.01 - Initial Version -*/