summaryrefslogtreecommitdiff
path: root/lib/unwarminder/unwarm.c
diff options
context:
space:
mode:
authorMarcin Bukat <marcin.bukat@gmail.com>2012-01-25 09:57:59 +0100
committerMarcin Bukat <marcin.bukat@gmail.com>2012-02-22 08:33:26 +0100
commitb4eab599513324dcaffa4c5693345ae11f3f9725 (patch)
tree58d66298269d2cec58102724565b573f250b5153 /lib/unwarminder/unwarm.c
parent680c6fcde1eabb45dd12c59718d708b2cda61f6a (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.c183
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, &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 */