rockbox/lib/unwarminder/unwarm.c

184 lines
6.1 KiB
C
Raw Normal View History

/***************************************************************************
* 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, &reg->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, &reg->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 */