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