callstack_tracker.cpp

Go to the documentation of this file.
00001 #ifndef CALLSTACK_TRACKER_IMPLEMENTATION_FILE
00002 #define CALLSTACK_TRACKER_IMPLEMENTATION_FILE
00003 
00004 /*****************************************************************************\
00005 *                                                                             *
00006 *  Name   : callstack_tracker                                                 *
00007 *  Author : Chris Koeritz                                                     *
00008 *                                                                             *
00009 *******************************************************************************
00010 * Copyright (c) 2007-$now By Author.  This program is free software; you can  *
00011 * redistribute it and/or modify it under the terms of the GNU General Public  *
00012 * License as published by the Free Software Foundation; either version 2 of   *
00013 * the License or (at your option) any later version.  This is online at:      *
00014 *     http://www.fsf.org/copyleft/gpl.html                                    *
00015 * Please send any updates to: fred@gruntose.com                               *
00016 \*****************************************************************************/
00017 
00018 #ifdef ENABLE_CALLSTACK_TRACKING
00019 
00020 // note: this object cannot be constructed when the memory_checker is still
00021 // tracking memory leaks.  it must be disabled so that this object can
00022 // construct without being tracked, which causes an infinite loop.  the code
00023 // in the basis extern support takes care of that for us.
00024 
00025 #include "callstack_tracker.h"
00026 
00027 #include <malloc.h>
00028 #include <stdio.h>
00029 
00031 //is this right way to clean that out.
00032 
00033 const int MAX_STACK_DEPTH = 2000;
00034   // beyond that many stack frames, we will simply refuse to add any more.
00035 
00036 const int MAX_TEXT_FIELD = 1024;
00037   // the most space we allow the class, function, and file to take up.
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];  // fudging room.
00048 };
00049 
00051 
00052 // our current depth gives us our position in the array.  we define our
00053 // stack as starting at element zero, which is a null stack entry and
00054 // corresponds to a depth of zero also.  then, when the stack depth is one,
00055 // we actually have an element in place and it resides at index 1.  this
00056 // scheme allows us to have an update to the line number just do nothing when
00057 // there is no current stack.
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 //printf("callstack ctor\n");
00068 }
00069 
00070 callstack_tracker::~callstack_tracker()
00071 {
00072 //printf("!!!!!!!!!!!!!!!!!!   callstack dtor in\n");
00073   _unusable = true;
00074   WHACK(_bt);
00075 //printf("!!!!!!!!!!!!!!!!!!   callstack dtor out\n");
00076 }
00077 
00078 bool callstack_tracker::push_frame(const char *class_name, const char *func,
00079     const char *file, int line)
00080 {
00081 //printf("callstack pushframe depth=%d in\n", _depth);
00082   if (_unusable) return false;
00083   if (_depth >= MAX_STACK_DEPTH) {
00084     // too many frames already.
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 //printf("callstack pushframe depth=%d out\n", _depth);
00094   return true;
00095 }
00096 
00097 bool callstack_tracker::pop_frame()
00098 {
00099 //printf("callstack popframe depth=%d in\n", _depth);
00100   if (_unusable) return false;
00101   if (_depth <= 0) {
00102     // how inappropriate of them; we have no frames.
00103     _depth = 0;  // we don't lose anything useful by forcing it to be zero.
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 //printf("callstack popframe depth=%d out\n", _depth);
00111   return true;
00112 }
00113 
00114 bool callstack_tracker::update_line(int line)
00115 {
00116   if (_unusable) return false;
00117   if (!_depth) return false;  // not as serious, but pretty weird.
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 //printf("fulltrace in\n");
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     // space provided for one text line.
00136   // start at top most active frame and go down towards bottom most.
00137   for (int i = _depth; i >= 1; i--) {
00138     strcat(to_return, "\t");  // we left space for this and \n at end.
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");  // we left space for this already.
00166   }
00167 
00168 //printf("fulltrace out\n");
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;  // liberal allocation.
00176   int to_return = 28;  // another hollywood style excess.
00177   for (int i = _depth; i >= 1; i--) {
00178     int this_line = 0;  // add up parts for just this item.
00179 
00180     // all of these additions are completely dependent on how it's done above.
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;  // extra space for line number and such.
00190 
00191     // limit it like we did above; we will use the lesser size value.
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 //printf("frametrackinst ctor in class=%s func=%s\n", class_name, func);
00210     program_wide_stack_trace().push_frame(class_name, func, file, line);
00211 //printf("frametrackinst ctor out\n");
00212   }
00213 }
00214 
00215 frame_tracking_instance::frame_tracking_instance
00216     (const frame_tracking_instance &to_copy)
00217 : _frame_involved(false),  // copies don't get a right to this.
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 //printf("frametrackinst clean\n");
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 //printf("frametrackinst tor = in\n");
00244   if (this == &to_copy) return *this;
00245   assign(to_copy._class, to_copy._func, to_copy._file, to_copy._line);
00246 //printf("frametrackinst tor = out\n");
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;  // copies don't get a right to this.
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 //printf("frametrackinst updatelinenum in\n");
00264   program_wide_stack_trace().update_line(line);
00265 //printf("frametrackinst updatelinenum out\n");
00266 }
00267 
00268 #endif // ENABLE_CALLSTACK_TRACKING
00269 
00270 
00271 #endif //CALLSTACK_TRACKER_IMPLEMENTATION_FILE
00272 

Generated on Wed Nov 19 04:28:43 2008 for HOOPLE Libraries by  doxygen 1.5.1