diff options
author | Marcin Bukat <marcin.bukat@gmail.com> | 2012-01-25 09:57:59 +0100 |
---|---|---|
committer | Marcin Bukat <marcin.bukat@gmail.com> | 2012-02-22 08:33:26 +0100 |
commit | b4eab599513324dcaffa4c5693345ae11f3f9725 (patch) | |
tree | 58d66298269d2cec58102724565b573f250b5153 /lib/unwarminder/unwarm.c | |
parent | 680c6fcde1eabb45dd12c59718d708b2cda61f6a (diff) |
Arm stack unwinder
Simplified stack unwinder for ARM. This is port of
http://www.mcternan.me.uk/ArmStackUnwinding/
backtrace() is called from UIE() on native targets
and from panicf() on both native and ARM RaaA.
Change-Id: I8e4b3c02490dd60b30aa372fe842d193b8929ce0
Diffstat (limited to 'lib/unwarminder/unwarm.c')
-rw-r--r-- | lib/unwarminder/unwarm.c | 183 |
1 files changed, 183 insertions, 0 deletions
diff --git a/lib/unwarminder/unwarm.c b/lib/unwarminder/unwarm.c new file mode 100644 index 0000000000..99f6a12ccb --- /dev/null +++ b/lib/unwarminder/unwarm.c @@ -0,0 +1,183 @@ +/*************************************************************************** + * ARM Stack Unwinder, Michael.McTernan.2001@cs.bris.ac.uk + * + * This program is PUBLIC DOMAIN. + * This means that there is no copyright and anyone is able to take a copy + * for free and use it as they wish, with or without modifications, and in + * any context, commercially or otherwise. The only limitation is that I + * don't guarantee that the software is fit for any purpose or accept any + * liability for it's use or misuse - this software is without warranty. + *************************************************************************** + * File Description: Utility functions and glue for ARM unwinding sub-modules. + **************************************************************************/ + +#define MODULE_NAME "UNWARM" + +/*************************************************************************** + * Include Files + **************************************************************************/ + +#include "types.h" +#include <stdio.h> +#include <stdarg.h> +#include <string.h> +#include "unwarm.h" +#include "unwarmmem.h" + +/*************************************************************************** + * Manifest Constants + **************************************************************************/ + + +/*************************************************************************** + * Type Definitions + **************************************************************************/ + + +/*************************************************************************** + * Variables + **************************************************************************/ + + +/*************************************************************************** + * Macros + **************************************************************************/ + + +/*************************************************************************** + * Local Functions + **************************************************************************/ + + +/*************************************************************************** + * Global Functions + **************************************************************************/ + +#if defined(UNW_DEBUG) +/** Printf wrapper. + * This is used such that alternative outputs for any output can be selected + * by modification of this wrapper function. + */ +void UnwPrintf(const char *format, ...) +{ + va_list args; + + va_start( args, format ); + vprintf(format, args ); +} +#endif + +/** Invalidate all general purpose registers. + */ +void UnwInvalidateRegisterFile(RegData *regFile) +{ + Int8 t = 0; + + do + { + regFile[t].o = REG_VAL_INVALID; + t++; + } + while(t < 13); + +} + + +/** Initialise the data used for unwinding. + */ +void UnwInitState(UnwState * const state, /**< Pointer to structure to fill. */ + const UnwindCallbacks *cb, /**< Callbacks. */ + void *rptData, /**< Data to pass to report function. */ + Int32 pcValue, /**< PC at which to start unwinding. */ + Int32 spValue) /**< SP at which to start unwinding. */ +{ + UnwInvalidateRegisterFile(state->regData); + + /* Store the pointer to the callbacks */ + state->cb = cb; + state->reportData = rptData; + + /* Setup the SP and PC */ + state->regData[13].v = spValue; + state->regData[13].o = REG_VAL_FROM_CONST; + state->regData[15].v = pcValue; + state->regData[15].o = REG_VAL_FROM_CONST; + + UnwPrintd3("\nInitial: PC=0x%08x SP=0x%08x\n", pcValue, spValue); + + /* Invalidate all memory addresses */ + memset(state->memData.used, 0, sizeof(state->memData.used)); +} + + +/** Call the report function to indicate some return address. + * This returns the value of the report function, which if TRUE + * indicates that unwinding may continue. + */ +Boolean UnwReportRetAddr(UnwState * const state, Int32 addr) +{ + /* Cast away const from reportData. + * The const is only to prevent the unw module modifying the data. + */ + return state->cb->report((void *)state->reportData, addr); +} + + +/** Write some register to memory. + * This will store some register and meta data onto the virtual stack. + * The address for the write + * \param state [in/out] The unwinding state. + * \param wAddr [in] The address at which to write the data. + * \param reg [in] The register to store. + * \return TRUE if the write was successful, FALSE otherwise. + */ +Boolean UnwMemWriteRegister(UnwState * const state, + const Int32 addr, + const RegData * const reg) +{ + return UnwMemHashWrite(&state->memData, + addr, + reg->v, + M_IsOriginValid(reg->o)); +} + +/** Read a register from memory. + * This will read a register from memory, and setup the meta data. + * If the register has been previously written to memory using + * UnwMemWriteRegister, the local hash will be used to return the + * value while respecting whether the data was valid or not. If the + * register was previously written and was invalid at that point, + * REG_VAL_INVALID will be returned in *reg. + * \param state [in] The unwinding state. + * \param addr [in] The address to read. + * \param reg [out] The result, containing the data value and the origin + * which will be REG_VAL_FROM_MEMORY, or REG_VAL_INVALID. + * \return TRUE if the address could be read and *reg has been filled in. + * FALSE is the data could not be read. + */ +Boolean UnwMemReadRegister(UnwState * const state, + const Int32 addr, + RegData * const reg) +{ + Boolean tracked; + + /* Check if the value can be found in the hash */ + if(UnwMemHashRead(&state->memData, addr, ®->v, &tracked)) + { + reg->o = tracked ? REG_VAL_FROM_MEMORY : REG_VAL_INVALID; + return TRUE; + } + /* Not in the hash, so read from real memory */ + else if(state->cb->readW(addr, ®->v)) + { + reg->o = REG_VAL_FROM_MEMORY; + return TRUE; + } + /* Not in the hash, and failed to read from memory */ + else + { + return FALSE; + } +} + +/* END OF FILE */ |