00001 #ifndef CALLSTACK_TRACKER_IMPLEMENTATION_FILE
00002 #define CALLSTACK_TRACKER_IMPLEMENTATION_FILE
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018 #ifdef ENABLE_CALLSTACK_TRACKING
00019
00020
00021
00022
00023
00024
00025 #include "callstack_tracker.h"
00026
00027 #include <malloc.h>
00028 #include <stdio.h>
00029
00031
00032
00033 const int MAX_STACK_DEPTH = 2000;
00034
00035
00036 const int MAX_TEXT_FIELD = 1024;
00037
00038
00039 const char *emptiness_note = "Empty Stack\n";
00041
00043
00044 class callstack_records
00045 {
00046 public:
00047 frame_tracking_instance _records[MAX_STACK_DEPTH + 2];
00048 };
00049
00051
00052
00053
00054
00055
00056
00057
00058
00059 callstack_tracker::callstack_tracker()
00060 : _bt(new callstack_records),
00061 _depth(0),
00062 _frames_in(0),
00063 _frames_out(0),
00064 _highest(0),
00065 _unusable(false)
00066 {
00067
00068 }
00069
00070 callstack_tracker::~callstack_tracker()
00071 {
00072
00073 _unusable = true;
00074 WHACK(_bt);
00075
00076 }
00077
00078 bool callstack_tracker::push_frame(const char *class_name, const char *func,
00079 const char *file, int line)
00080 {
00081
00082 if (_unusable) return false;
00083 if (_depth >= MAX_STACK_DEPTH) {
00084
00085 printf("callstack_tracker::push_frame: past limit at class=%s func=%s "
00086 "file=%s line=%d\n", class_name, func, file, line);
00087 return false;
00088 }
00089 _depth++;
00090 if (_depth > _highest) _highest = _depth;
00091 _frames_in += 1;
00092 _bt->_records[_depth].assign(class_name, func, file, line);
00093
00094 return true;
00095 }
00096
00097 bool callstack_tracker::pop_frame()
00098 {
00099
00100 if (_unusable) return false;
00101 if (_depth <= 0) {
00102
00103 _depth = 0;
00104 printf("callstack_tracker::pop_frame stack underflow!\n");
00105 return false;
00106 }
00107 _bt->_records[_depth].clean();
00108 _depth--;
00109 _frames_out += 1;
00110
00111 return true;
00112 }
00113
00114 bool callstack_tracker::update_line(int line)
00115 {
00116 if (_unusable) return false;
00117 if (!_depth) return false;
00118 _bt->_records[_depth]._line = line;
00119 return true;
00120 }
00121
00122 char *callstack_tracker::full_trace() const
00123 {
00124 if (_unusable) return strdup("");
00125
00126 char *to_return = (char *)malloc(full_trace_size());
00127 to_return[0] = '\0';
00128 if (!_depth) {
00129 strcat(to_return, emptiness_note);
00130 return to_return;
00131 }
00132 const int initial_len = MAX_TEXT_FIELD + 8;
00133 char temp[initial_len];
00134 int allowed_len = initial_len;
00135
00136
00137 for (int i = _depth; i >= 1; i--) {
00138 strcat(to_return, "\t");
00139 temp[0] = '\0';
00140 int len_class = strlen(_bt->_records[i]._class);
00141 int len_func = strlen(_bt->_records[i]._func);
00142 if (allowed_len > len_class + len_func + 6) {
00143 allowed_len -= len_class + len_func + 6;
00144 sprintf(temp, "\"%s::%s\", ", _bt->_records[i]._class,
00145 _bt->_records[i]._func);
00146 strcat(to_return, temp);
00147 }
00148
00149 temp[0] = '\0';
00150 int len_file = strlen(_bt->_records[i]._file);
00151 if (allowed_len > len_file + 4) {
00152 allowed_len -= len_file + 4;
00153 sprintf(temp, "\"%s\", ", _bt->_records[i]._file);
00154 strcat(to_return, temp);
00155 }
00156
00157 temp[0] = '\0';
00158 sprintf(temp, "\"line=%d\"", _bt->_records[i]._line);
00159 int len_line = strlen(temp);
00160 if (allowed_len > len_line) {
00161 allowed_len -= len_line;
00162 strcat(to_return, temp);
00163 }
00164
00165 strcat(to_return, "\n");
00166 }
00167
00168
00169 return to_return;
00170 }
00171
00172 int callstack_tracker::full_trace_size() const
00173 {
00174 if (_unusable) return 0;
00175 if (!_depth) return strlen(emptiness_note) + 14;
00176 int to_return = 28;
00177 for (int i = _depth; i >= 1; i--) {
00178 int this_line = 0;
00179
00180
00181
00182 int len_class = strlen(_bt->_records[i]._class);
00183 int len_func = strlen(_bt->_records[i]._func);
00184 this_line += len_class + len_func + 6;
00185
00186 int len_file = strlen(_bt->_records[i]._file);
00187 this_line += len_file + 4;
00188
00189 this_line += 32;
00190
00191
00192 if (this_line < MAX_TEXT_FIELD + 8) to_return += this_line;
00193 else to_return += MAX_TEXT_FIELD + 8;
00194 }
00195 return to_return;
00196 }
00197
00199
00200 frame_tracking_instance::frame_tracking_instance(const char *class_name,
00201 const char *func, const char *file, int line, bool add_frame)
00202 : _frame_involved(add_frame),
00203 _class(class_name? strdup(class_name) : NIL),
00204 _func(func? strdup(func) : NIL),
00205 _file(file? strdup(file) : NIL),
00206 _line(line)
00207 {
00208 if (_frame_involved) {
00209
00210 program_wide_stack_trace().push_frame(class_name, func, file, line);
00211
00212 }
00213 }
00214
00215 frame_tracking_instance::frame_tracking_instance
00216 (const frame_tracking_instance &to_copy)
00217 : _frame_involved(false),
00218 _class(to_copy._class? strdup(to_copy._class) : NIL),
00219 _func(to_copy._func? strdup(to_copy._func) : NIL),
00220 _file(to_copy._file? strdup(to_copy._file) : NIL),
00221 _line(to_copy._line)
00222 {
00223 }
00224
00225 frame_tracking_instance::~frame_tracking_instance() { clean(); }
00226
00227 void frame_tracking_instance::clean()
00228 {
00229 if (_frame_involved) {
00230
00231 program_wide_stack_trace().pop_frame();
00232 }
00233 _frame_involved = false;
00234 free(_class); _class = NIL;
00235 free(_func); _func = NIL;
00236 free(_file); _file = NIL;
00237 _line = 0;
00238 }
00239
00240 frame_tracking_instance &frame_tracking_instance::operator =
00241 (const frame_tracking_instance &to_copy)
00242 {
00243
00244 if (this == &to_copy) return *this;
00245 assign(to_copy._class, to_copy._func, to_copy._file, to_copy._line);
00246
00247 return *this;
00248 }
00249
00250 void frame_tracking_instance::assign(const char *class_name, const char *func,
00251 const char *file, int line)
00252 {
00253 clean();
00254 _frame_involved = false;
00255 _class = class_name? strdup(class_name) : NIL;
00256 _func = func? strdup(func) : NIL;
00257 _file = file? strdup(file) : NIL;
00258 _line = line;
00259 }
00260
00261 void update_current_stack_frame_line_number(int line)
00262 {
00263
00264 program_wide_stack_trace().update_line(line);
00265
00266 }
00267
00268 #endif // ENABLE_CALLSTACK_TRACKING
00269
00270
00271 #endif //CALLSTACK_TRACKER_IMPLEMENTATION_FILE
00272