1 #ifndef CALLSTACK_TRACKER_CLASS
2 #define CALLSTACK_TRACKER_CLASS
4 /*****************************************************************************\
6 * Name : callstack_tracker *
7 * Author : Chris Koeritz *
9 *******************************************************************************
10 * Copyright (c) 2007-$now By Author. This program is free software; you can *
11 * redistribute it and/or modify it under the terms of the GNU General Public *
12 * License as published by the Free Software Foundation; either version 2 of *
13 * the License or (at your option) any later version. This is online at: *
14 * http://www.fsf.org/copyleft/gpl.html *
15 * Please send any updates to: fred@gruntose.com *
16 \*****************************************************************************/
18 #include "definitions.h"
20 #ifdef ENABLE_CALLSTACK_TRACKING
22 #include "build_configuration.h"
23 #include "root_object.h"
25 namespace application {
28 class callstack_records;
29 class callstack_tracker;
33 callstack_tracker BASIS_EXTERN &program_wide_stack_trace();
34 //!< a global object that can be used to track the runtime callstack.
38 //! This object can provide a backtrace at runtime of the invoking methods.
40 The callstack tracking is hooked in through the FUNCDEF macros used to
41 set function names for logging. Thus it will only be visible if those
42 macros are used fairly carefully or if people invoke the stack frame addition
46 class callstack_tracker
50 virtual ~callstack_tracker();
52 DEFINE_CLASS_NAME("callstack_tracker");
54 bool push_frame(const char *class_name, const char *func, const char *file,
56 //!< adds a new stack from for the "class_name" in "function" at the "line".
57 /*!< this function should be invoked when entering a new stack frame. the
58 "file" can be gotten from the __FILE__ macro and the "line" number can come
59 from __LINE__, but the "class_name" and "func" must be tracked some other
60 way. we recommend the FUNCDEF macro. this function might return false if
61 there is no longer any room for tracking more frames; that is a serious
62 issue that might indicate a runaway recursion or infinite loop. */
65 //!< removes the last callstack frame off from our tracking.
67 bool update_line(int line);
68 //!< sets the line number within the current stack frame.
69 /*!< the current frame can reside across several line numbers, so this
70 allows the code to be more specific about the location of an invocation. */
72 char *full_trace() const;
73 //!< provides the current stack trace in a newly malloc'd string.
74 /*!< the user *must* free() the string returned. */
76 int full_trace_size() const;
77 //!< this returns the number of bytes needed for the above full_trace().
79 int depth() const { return _depth; }
80 //!< the current number of frames we know of.
82 double frames_in() const { return _frames_in; }
83 //!< reports the number of call stack frames that were added, total.
85 double frames_out() const { return _frames_out; }
86 //!< reports the number of call stack frames that were removed, total.
88 double highest() const { return _highest; }
89 //!< reports the maximum stack depth seen during the runtime so far.
92 callstack_records *_bt; //!< the backtrace records for current program.
93 int _depth; //!< the current number of frames we know of.
94 double _frames_in; //!< number of frame additions.
95 double _frames_out; //!< number of frame removals.
96 double _highest; //!< the most number of frames in play at once.
97 bool _unusable; //!< object has already been destroyed.
102 //! a small object that represents a stack trace in progress.
103 /*! the object will automatically be destroyed when the containing scope
104 exits. this enables a users of the stack tracker to simply label their
105 function name and get the frame added. if they want finer grained tracking,
106 they should update the line number periodically through their function,
107 especially when memory is about to be allocated or where something might go
110 class frame_tracking_instance
113 // these are not encapsulated, but be careful with the contents.
114 bool _frame_involved; //!< has this object been added to the tracker?
115 char *_class, *_func, *_file; //!< newly allocated copies.
118 frame_tracking_instance(const char *class_name = "", const char *func = "",
119 const char *file = "", int line = 0, bool add_frame = false);
120 //!< as an automatic variable, this can hang onto frame information.
121 /*!< if "add_frame" is true, then this actually adds the stack frame in
122 question to the tracker. thus if you use this class at the top of your
123 function, such as via the FUNCDEF macro, then you can forget about having
124 to pop the frame later. */
126 frame_tracking_instance(const frame_tracking_instance &to_copy);
128 ~frame_tracking_instance();
129 //!< releases the information *and* this stack frame in the tracker.
131 frame_tracking_instance &operator =(const frame_tracking_instance &to_copy);
133 void assign(const char *class_name, const char *func, const char *file,
135 //!< similar to assignment operator but doesn't require an object.
138 //!< throws out our accumulated memory and pops frame if applicable.
141 void update_current_stack_frame_line_number(int line);
142 //!< sets the line number for the current frame in the global stack trace.
144 #else // ENABLE_CALLSTACK_TRACKING
145 // bogus replacements for most commonly used callstack tracking support.
146 #define frame_tracking_instance
147 #define __trail_of_function(p1, p2, p3, p4, p5) if (func) {}
148 // the above actually trades on the name of the object we'd normally
149 // define. it must match the object name in the FUNCDEF macro.
150 #define update_current_stack_frame_line_number(line)
151 #endif // ENABLE_CALLSTACK_TRACKING
155 #endif // outer guard.