/* --------------------------------------------------------------------------- * * (c) The GHC Team, 2014-2015 * * Producing DWARF-based stacktraces with libdw. * * --------------------------------------------------------------------------*/ #pragma once // for FILE #include // Chunk capacity // This is rather arbitrary #define BACKTRACE_CHUNK_SZ 256 /* * Note [Chunked stack representation] * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ * * Consider the stack, * main calls (bottom of stack) * func1 which in turn calls * func2 which calls * func3 which calls * func4 which calls * func5 which calls * func6 which calls * func7 which requests a backtrace (top of stack) * * This would produce the Backtrace (using a smaller chunk size of three for * illustrative purposes), * * Backtrace /----> Chunk /----> Chunk /----> Chunk * last --------/ next --------/ next --------/ next * n_frames=8 n_frames=2 n_frames=3 n_frames=3 * ~~~~~~~~~~ ~~~~~~~~~~ ~~~~~~~~~~ * func1 func4 func7 * main func3 func6 * func2 func5 * */ /* A chunk of code addresses from an execution stack * * The first address in this list corresponds to the stack frame * nearest to the "top" of the stack. */ typedef struct BacktraceChunk_ { StgWord n_frames; // number of frames in this chunk struct BacktraceChunk_ *next; // the chunk following this one StgPtr frames[BACKTRACE_CHUNK_SZ]; // the code addresses from the // frames } __attribute__((packed)) BacktraceChunk; /* A chunked list of code addresses from an execution stack * * This structure is optimized for append operations since we append O(stack * depth) times yet typically only traverse the stack trace once. Consequently, * the "top" stack frame (that is, the one where we started unwinding) can be * found in the last chunk. Yes, this is a bit inconsistent with the ordering * within a chunk. See Note [Chunked stack representation] for a depiction. */ typedef struct Backtrace_ { StgWord n_frames; // Total number of frames in the backtrace BacktraceChunk *last; // The first chunk of frames (corresponding to the // bottom of the stack) } Backtrace; /* Various information describing the location of an address */ typedef struct Location_ { const char *object_file; const char *function; // lineno and colno are only valid if source_file /= NULL const char *source_file; StgWord32 lineno; StgWord32 colno; } __attribute__((packed)) Location; struct LibdwSession_; typedef struct LibdwSession_ LibdwSession; /* Free a backtrace */ void backtraceFree(Backtrace *bt); /* Request a backtrace of the current stack state. * May return NULL if a backtrace can't be acquired. */ Backtrace *libdwGetBacktrace(LibdwSession *session); /* Lookup Location information for the given address. * Returns 0 if successful, 1 if address could not be found. */ int libdwLookupLocation(LibdwSession *session, Location *loc, StgPtr pc); /* Pretty-print a backtrace to the given FILE */ void libdwPrintBacktrace(LibdwSession *session, FILE *file, Backtrace *bt);