/*************************************************************************** * 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 #include #include #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 */