void UnwMemHashGC(UnwState * const state) { const Int32 minValidAddr = state->regData[13].v; MemData * const memData = &state->memData; Int16 t; for(t = 0; t < MEM_HASH_SIZE; t++) { if(M_IsIdxUsed(memData->used, t) && (memData->a[t] < minValidAddr)) { UnwPrintd3("MemHashGC: Free elem %d, addr 0x%08x\n", t, memData->a[t]); M_ClrIdxUsed(memData->used, t); } } }
/** 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)); }
UnwResult UnwStartThumb(UnwState * const state) { Boolean found = FALSE; Int16 t = UNW_MAX_INSTR_COUNT; do { Int16 instr; /* Attempt to read the instruction */ if(!state->cb->readH(state->regData[15].v & (~0x1), &instr)) { return UNWIND_IREAD_H_FAIL; } UnwPrintd4("T %x %x %04x:", state->regData[13].v, state->regData[15].v, instr); /* Check that the PC is still on Thumb alignment */ if(!(state->regData[15].v & 0x1)) { UnwPrintd1("\nError: PC misalignment\n"); return UNWIND_INCONSISTENT; } /* Check that the SP and PC have not been invalidated */ if(!M_IsOriginValid(state->regData[13].o) || !M_IsOriginValid(state->regData[15].o)) { UnwPrintd1("\nError: PC or SP invalidated\n"); return UNWIND_INCONSISTENT; } /* Format 1: Move shifted register * LSL Rd, Rs, #Offset5 * LSR Rd, Rs, #Offset5 * ASR Rd, Rs, #Offset5 */ if((instr & 0xe000) == 0x0000 && (instr & 0x1800) != 0x1800) { Boolean signExtend; Int8 op = (instr & 0x1800) >> 11; Int8 offset5 = (instr & 0x07c0) >> 6; Int8 rs = (instr & 0x0038) >> 3; Int8 rd = (instr & 0x0007); switch(op) { case 0: /* LSL */ UnwPrintd6("LSL r%d, r%d, #%d\t; r%d %s", rd, rs, offset5, rs, M_Origin2Str(state->regData[rs].o)); state->regData[rd].v = state->regData[rs].v << offset5; state->regData[rd].o = state->regData[rs].o; state->regData[rd].o |= REG_VAL_ARITHMETIC; break; case 1: /* LSR */ UnwPrintd6("LSR r%d, r%d, #%d\t; r%d %s", rd, rs, offset5, rs, M_Origin2Str(state->regData[rs].o)); state->regData[rd].v = state->regData[rs].v >> offset5; state->regData[rd].o = state->regData[rs].o; state->regData[rd].o |= REG_VAL_ARITHMETIC; break; case 2: /* ASR */ UnwPrintd6("ASL r%d, r%d, #%d\t; r%d %s", rd, rs, offset5, rs, M_Origin2Str(state->regData[rs].o)); signExtend = (state->regData[rs].v & 0x8000) ? TRUE : FALSE; state->regData[rd].v = state->regData[rs].v >> offset5; if(signExtend) { state->regData[rd].v |= 0xffffffff << (32 - offset5); } state->regData[rd].o = state->regData[rs].o; state->regData[rd].o |= REG_VAL_ARITHMETIC; break; } } /* Format 2: add/subtract * ADD Rd, Rs, Rn * ADD Rd, Rs, #Offset3 * SUB Rd, Rs, Rn * SUB Rd, Rs, #Offset3 */ else if((instr & 0xf800) == 0x1800) { Boolean I = (instr & 0x0400) ? TRUE : FALSE; Boolean op = (instr & 0x0200) ? TRUE : FALSE; Int8 rn = (instr & 0x01c0) >> 6; Int8 rs = (instr & 0x0038) >> 3; Int8 rd = (instr & 0x0007); /* Print decoding */ UnwPrintd6("%s r%d, r%d, %c%d\t;", op ? "SUB" : "ADD", rd, rs, I ? '#' : 'r', rn); UnwPrintd5("r%d %s, r%d %s", rd, M_Origin2Str(state->regData[rd].o), rs, M_Origin2Str(state->regData[rs].o)); if(!I) { UnwPrintd3(", r%d %s", rn, M_Origin2Str(state->regData[rn].o)); /* Perform calculation */ if(op) { state->regData[rd].v = state->regData[rs].v - state->regData[rn].v; } else { state->regData[rd].v = state->regData[rs].v + state->regData[rn].v; } /* Propagate the origin */ if(M_IsOriginValid(state->regData[rs].v) && M_IsOriginValid(state->regData[rn].v)) { state->regData[rd].o = state->regData[rs].o; state->regData[rd].o |= REG_VAL_ARITHMETIC; } else { state->regData[rd].o = REG_VAL_INVALID; } } else { /* Perform calculation */ if(op) { state->regData[rd].v = state->regData[rs].v - rn; } else { state->regData[rd].v = state->regData[rs].v + rn; } /* Propagate the origin */ state->regData[rd].o = state->regData[rs].o; state->regData[rd].o |= REG_VAL_ARITHMETIC; } }