GB_ASSERT prints call stack

This commit is contained in:
gingerBill 2015-12-02 15:38:18 +00:00
parent 9c169017d1
commit 3addf42948
2 changed files with 176 additions and 71 deletions

View File

@ -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++

245
gb.hpp
View File

@ -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 <dbghelp.h>
#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<SYMBOL_INFO*>(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
*/