1 // Copyright (C) 2008 Davis E. King (davis@dlib.net) 2 // License: Boost Software License See LICENSE.txt for the full license. 3 #ifndef DLIB_STACK_TRACe_ 4 #define DLIB_STACK_TRACe_ 5 6 /*! 7 This file defines 3 things. Two of them are preprocessor macros that 8 enable you to tag functions with the dlib stack trace watcher. The 9 third thing is a function named get_stack_trace() which returns the 10 current stack trace in std::string form. 11 12 To enable the stack trace you must #define DLIB_ENABLE_STACK_TRACE. 13 When this #define isn't set then the 3 things described above 14 still exist but they don't do anything. 15 16 Also note that when the stack trace is enabled it changes the DLIB_ASSERT 17 and DLIB_CASSERT macros so that they print stack traces when 18 an assert fails. 19 20 See the following example program for details: 21 22 #include <iostream> 23 #include <dlib/stack_trace.h> 24 25 void funct2() 26 { 27 // put this macro at the top of each function you would 28 // like to appear in stack traces 29 DLIB_STACK_TRACE; 30 31 // you may print the current stack trace as follows. 32 std::cout << dlib::get_stack_trace() << endl; 33 } 34 35 void funct() 36 { 37 // This alternate form of DLIB_STACK_TRACE allows you to specify 38 // the string used to name the current function. The other form 39 // will usually output an appropriate function name automatically 40 // so this may not be needed. 41 DLIB_STACK_TRACE_NAMED("funct"); 42 funct2(); 43 } 44 45 int main() 46 { 47 funct(); 48 } 49 !*/ 50 51 52 #include <string> 53 #include "assert.h" 54 55 // only setup the stack trace stuff if the asserts are enabled (which happens in debug mode 56 // basically). Also, this stuff doesn't work if you use NO_MAKEFILE 57 #if defined(DLIB_ENABLE_STACK_TRACE) 58 #ifdef NO_MAKEFILE 59 #error "You can't use the dlib stack trace stuff and NO_MAKEFILE at the same time" 60 #endif 61 62 namespace dlib 63 { 64 const std::string get_stack_trace(); 65 } 66 67 // redefine the DLIB_CASSERT macro to include the stack trace 68 #undef DLIBM_CASSERT 69 #define DLIBM_CASSERT(_exp,_message) \ 70 {if ( !(_exp) ) \ 71 { \ 72 std::ostringstream dlib_o_out; \ 73 dlib_o_out << "\n\nError occurred at line " << __LINE__ << ".\n"; \ 74 dlib_o_out << "Error occurred in file " << __FILE__ << ".\n"; \ 75 dlib_o_out << "Error occurred in function " << DLIB_FUNCTION_NAME << ".\n\n"; \ 76 dlib_o_out << "Failing expression was " << #_exp << ".\n"; \ 77 dlib_o_out << _message << "\n\n"; \ 78 dlib_o_out << "Stack Trace: \n" << dlib::get_stack_trace() << "\n"; \ 79 dlib_assert_breakpoint(); \ 80 throw dlib::fatal_error(dlib::EBROKEN_ASSERT,dlib_o_out.str()); \ 81 }} 82 83 84 85 namespace dlib 86 { 87 88 class stack_tracer 89 { 90 public: 91 stack_tracer ( 92 const char* funct_name, 93 const char* file_name, 94 const int line_number 95 ); 96 97 ~stack_tracer(); 98 99 }; 100 } 101 102 #define DLIB_STACK_TRACE_NAMED(x) dlib::stack_tracer dlib_stack_tracer_object(x,__FILE__,__LINE__) 103 #define DLIB_STACK_TRACE dlib::stack_tracer dlib_stack_tracer_object(DLIB_FUNCTION_NAME,__FILE__,__LINE__) 104 105 #else // don't do anything if ENABLE_ASSERTS isn't defined 106 #define DLIB_STACK_TRACE_NAMED(x) 107 #define DLIB_STACK_TRACE 108 109 namespace dlib 110 { get_stack_trace()111 inline const std::string get_stack_trace() { return std::string("stack trace not enabled");} 112 } 113 114 #endif 115 116 117 #endif // DLIB_STACK_TRACe_ 118 119