X-Git-Url: https://feistymeow.org/gitweb/?a=blobdiff_plain;f=nucleus%2Flibrary%2Fapplication%2Fcallstack_tracker.h;fp=nucleus%2Flibrary%2Fapplication%2Fcallstack_tracker.h;h=bb75adaafd1fe4652c86476a5a2e61900ea0233d;hb=457b128b77b5b4a0b7dd3094de543de2ce1477ad;hp=0000000000000000000000000000000000000000;hpb=32d7caf45d886d0d24e69eea00511c7815ac15d0;p=feisty_meow.git diff --git a/nucleus/library/application/callstack_tracker.h b/nucleus/library/application/callstack_tracker.h new file mode 100644 index 00000000..bb75adaa --- /dev/null +++ b/nucleus/library/application/callstack_tracker.h @@ -0,0 +1,156 @@ +#ifndef CALLSTACK_TRACKER_CLASS +#define CALLSTACK_TRACKER_CLASS + +/*****************************************************************************\ +* * +* Name : callstack_tracker * +* Author : Chris Koeritz * +* * +******************************************************************************* +* Copyright (c) 2007-$now By Author. This program is free software; you can * +* redistribute it and/or modify it under the terms of the GNU General Public * +* License as published by the Free Software Foundation; either version 2 of * +* the License or (at your option) any later version. This is online at: * +* http://www.fsf.org/copyleft/gpl.html * +* Please send any updates to: fred@gruntose.com * +\*****************************************************************************/ + +#include "definitions.h" + +#ifdef ENABLE_CALLSTACK_TRACKING + +#include "build_configuration.h" +#include "root_object.h" + +namespace application { + +// forward. +class callstack_records; +class callstack_tracker; + +////////////// + +callstack_tracker BASIS_EXTERN &program_wide_stack_trace(); + //!< a global object that can be used to track the runtime callstack. + +////////////// + +//! This object can provide a backtrace at runtime of the invoking methods. +/*! + The callstack tracking is hooked in through the FUNCDEF macros used to + set function names for logging. Thus it will only be visible if those + macros are used fairly carefully or if people invoke the stack frame addition + method themselves. +*/ + +class callstack_tracker +{ +public: + callstack_tracker(); + virtual ~callstack_tracker(); + + DEFINE_CLASS_NAME("callstack_tracker"); + + bool push_frame(const char *class_name, const char *func, const char *file, + int line); + //!< adds a new stack from for the "class_name" in "function" at the "line". + /*!< this function should be invoked when entering a new stack frame. the + "file" can be gotten from the __FILE__ macro and the "line" number can come + from __LINE__, but the "class_name" and "func" must be tracked some other + way. we recommend the FUNCDEF macro. this function might return false if + there is no longer any room for tracking more frames; that is a serious + issue that might indicate a runaway recursion or infinite loop. */ + + bool pop_frame(); + //!< removes the last callstack frame off from our tracking. + + bool update_line(int line); + //!< sets the line number within the current stack frame. + /*!< the current frame can reside across several line numbers, so this + allows the code to be more specific about the location of an invocation. */ + + char *full_trace() const; + //!< provides the current stack trace in a newly malloc'd string. + /*!< the user *must* free() the string returned. */ + + int full_trace_size() const; + //!< this returns the number of bytes needed for the above full_trace(). + + int depth() const { return _depth; } + //!< the current number of frames we know of. + + double frames_in() const { return _frames_in; } + //!< reports the number of call stack frames that were added, total. + + double frames_out() const { return _frames_out; } + //!< reports the number of call stack frames that were removed, total. + + double highest() const { return _highest; } + //!< reports the maximum stack depth seen during the runtime so far. + +private: + callstack_records *_bt; //!< the backtrace records for current program. + int _depth; //!< the current number of frames we know of. + double _frames_in; //!< number of frame additions. + double _frames_out; //!< number of frame removals. + double _highest; //!< the most number of frames in play at once. + bool _unusable; //!< object has already been destroyed. +}; + +////////////// + +//! a small object that represents a stack trace in progress. +/*! the object will automatically be destroyed when the containing scope +exits. this enables a users of the stack tracker to simply label their +function name and get the frame added. if they want finer grained tracking, +they should update the line number periodically through their function, +especially when memory is about to be allocated or where something might go +wrong. */ + +class frame_tracking_instance +{ +public: + // these are not encapsulated, but be careful with the contents. + bool _frame_involved; //!< has this object been added to the tracker? + char *_class, *_func, *_file; //!< newly allocated copies. + int _line; + + frame_tracking_instance(const char *class_name = "", const char *func = "", + const char *file = "", int line = 0, bool add_frame = false); + //!< as an automatic variable, this can hang onto frame information. + /*!< if "add_frame" is true, then this actually adds the stack frame in + question to the tracker. thus if you use this class at the top of your + function, such as via the FUNCDEF macro, then you can forget about having + to pop the frame later. */ + + frame_tracking_instance(const frame_tracking_instance &to_copy); + + ~frame_tracking_instance(); + //!< releases the information *and* this stack frame in the tracker. + + frame_tracking_instance &operator =(const frame_tracking_instance &to_copy); + + void assign(const char *class_name, const char *func, const char *file, + int line); + //!< similar to assignment operator but doesn't require an object. + + void clean(); + //!< throws out our accumulated memory and pops frame if applicable. +}; + +void update_current_stack_frame_line_number(int line); + //!< sets the line number for the current frame in the global stack trace. + +#else // ENABLE_CALLSTACK_TRACKING + // bogus replacements for most commonly used callstack tracking support. + #define frame_tracking_instance + #define __trail_of_function(p1, p2, p3, p4, p5) if (func) {} + // the above actually trades on the name of the object we'd normally + // define. it must match the object name in the FUNCDEF macro. + #define update_current_stack_frame_line_number(line) +#endif // ENABLE_CALLSTACK_TRACKING + +} //namespace. + +#endif // outer guard. +