winamp/Src/Plugins/DSP/sc_serv3/nmrCommon/stacktrace/StackTrace.h
2024-09-24 14:54:57 +02:00

136 lines
6 KiB
C++

#ifndef INCLUDED_StackTrace_h_
#define INCLUDED_StackTrace_h_
#ifdef __APPLE__
# include <AvailabilityMacros.h>
#endif
// Aperios and Mac OS X 10.4 and prior need the "manual" unroll; otherwise assume execinfo.h and backtrace() are available
#if !defined(PLATFORM_APERIOS) && (!defined(__APPLE__) || defined(MAC_OS_X_VERSION_10_5))
# define STACKTRACE_USE_BACKTRACE
#endif
#ifndef __cplusplus
# include <stddef.h>
#else
# include <cstddef>
//! Holds the C-style interface for the stack trace routines
namespace stacktrace {
extern "C" {
#endif /* __cplusplus */
typedef int machineInstruction; //!< typedef in case type needs to change on other platforms (i.e. long for 64 bit architectures?)
//! Stores information about a single stack frame
struct StackFrame {
#ifdef STACKTRACE_USE_BACKTRACE
//! pointer to array of return addresses, shared by all StackFrames in the list
void*** packedRA;
//! pointer to number of entries available at #packedRA
size_t* packedRAUsed;
//! pointer to size of array at #packedRA
size_t* packedRACap;
//! entry in #packedRA corresponding to this frame
size_t depth;
//! return address, points to instruction being executed within current frame
void* ra;
#else
//! stack pointer, points to end of stack frame
void * sp;
# if defined(__PIC__) && (defined(__MIPSEL__) || defined(__MIPS__))
//! return address, points to instruction being executed within current frame
/*! Note that this is the address that is being returned to by the @e sub-function,
* @e not the address that this frame itself is returning to.
* When executing position independent code (PIC), this is the address relative
* to #gp. In other words, subtract this from #gp to get current memory address,
* or subtract from the binary's _gp symbol to get link-time address (for looking up file/line) */
size_t ra;
//! global offset used in position independent code (PIC)
/*! subtract #ra from this to get the actual run-time memory address of the instruction */
size_t gp;
# else
//! return address, points to instruction being executed within current frame
/*! Note that this is the address that is being returned to by the @e sub-function,
* @e not the address that this frame itself is returning to. */
machineInstruction * ra;
# endif /* __PIC__ */
# ifdef DEBUG_STACKTRACE
//! if DEBUG_STACKTRACE is defined, this field is available which, if non-zero, will cause debugging info to be displayed on each unroll
int debug;
# endif
#endif
//! points to the caller's stack frame (stack frame of function which called this one), may be NULL or self-referential at end of list
/*! a self-referential value indicates the frame is not the last on the stack, but is the last recorded. */
struct StackFrame * caller;
};
//! stores information about the caller's stack frame into @a frame
void getCurrentStackFrame(struct StackFrame* frame);
//! stores information about the caller to @a curFrame into @a nextFrame
/*! @return 0 if error occurred (i.e. bottom of the stack), non-zero upon success
* @a nextFrame @e can be the same instance as @a curFrame, will update in place.
* @a curFrame->caller will be set to @a nextFrame. */
int unrollStackFrame(struct StackFrame* curFrame, struct StackFrame* nextFrame);
//! frees a list of StackFrames, such as is returned by recordStackTrace
void freeStackTrace(struct StackFrame* frame);
//! preallocates a stack trace of a particular size (doesn't actually perform a stack trace, merely allocates the linked list)
/*! this is a good idea if you want to do a stack trace within an exception handler, which might have been triggered by running out of heap */
struct StackFrame* allocateStackTrace(unsigned int size);
//! dumps stored stack trace to stderr
void displayStackTrace(const struct StackFrame* frame);
#ifndef __cplusplus
//! dumps current stack trace to stderr, up to @a limit depth and skipping the top @a skip frames
/*! pass -1U for limit to request unlimited trace, and 0 to start with the function calling recordStackTrace */
void displayCurrentStackTrace(unsigned int limit, unsigned int skip);
//! repeatedly calls unrollStackFrame() until the root frame is reached or @a limit is hit, skipping the top @a skip frames
/*! pass -1U for limit to request unlimited trace, and 0 to start with the function calling recordStackTrace */
struct StackFrame * recordStackTrace(unsigned int limit, unsigned int skip);
//! repeatedly calls unrollStackFrame() until the root frame is reached or end of @a frame list is hit, skipping the top @a skip frames
/*! This is handy for reusing previously allocated frames, returns the unused portion (if return value equals @a frame, none were used -- implies never cleared @a skip) */
struct StackFrame * recordOverStackTrace(struct StackFrame* frame, unsigned int skip);
#else /* __cplusplus */
//! dumps current stack trace to stderr, up to @a limit depth and skipping the top @a skip frames
/*! pass -1U for limit to request unlimited trace, and 0 to start with the function calling recordStackTrace */
void displayCurrentStackTrace(unsigned int limit=-1U, unsigned int skip=0);
//! repeatedly calls unrollStackFrame() until the root frame is reached or @a limit is hit, skipping the top @a skip frames
/*! pass -1U for limit to request unlimited trace, and 0 to start with the function calling recordStackTrace */
struct StackFrame * recordStackTrace(unsigned int limit=-1U, unsigned int skip=0);
//! repeatedly calls unrollStackFrame() until the root frame is reached or end of @a frame list is hit, skipping the top @a skip frames
/*! This is handy for reusing previously allocated frames, returns the unused portion (if return value equals @a frame, none were used -- implies never cleared @a skip) */
struct StackFrame * recordOverStackTrace(struct StackFrame* frame, unsigned int skip=0);
}
}
#endif /* __cplusplus */
/*! @file
* @brief Describes functionality for performing stack traces
* @author ejt (Creator)
*
* $Author: ejtttje $
* $Name: $
* $Revision: 1.2 $
* $State: Exp $
* $Date: 2009/11/20 00:50:23 $
*/
#endif