/** 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)); }
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; } }