FreeBSD/sys/arm/arm/unwind.c
/* Executes the next instruction on the list */
Executes the next instruction on the list
Executes the next instruction on the list
static int
unwind_exec_insn(struct unwind_state *state)
{
	unsigned int insn;
	uint32_t *vsp = (uint32_t *)state->registers[SP];
	int update_vsp = 0;
	if (state->entries == 0)
		return 1;
	insn = unwind_exec_read_byte(state);
	if ((insn & INSN_VSP_MASK) == INSN_VSP_INC) {
		state->registers[SP] += ((insn & INSN_VSP_SIZE_MASK) << 2) + 4;
	} else if ((insn & INSN_VSP_MASK) == INSN_VSP_DEC) {
		state->registers[SP] -= ((insn & INSN_VSP_SIZE_MASK) << 2) + 4;
	} else if ((insn & INSN_STD_MASK) == INSN_POP_MASKED) {
		unsigned int mask, reg;
		mask = unwind_exec_read_byte(state);
		mask |= (insn & INSN_STD_DATA_MASK) << 8;
		if (mask == 0)
			return 1;
		update_vsp = 1;
		for (reg = 4; mask && reg < 16; mask >>= 1, reg++) {
			if (mask & 1) {
				state->registers[reg] = *vsp++;
				state->update_mask |= 1 << reg;
				if (reg == SP)
					update_vsp = 0;
			}
		}
	} else if ((insn & INSN_STD_MASK) == INSN_VSP_REG &&
	    ((insn & INSN_STD_DATA_MASK) != 13) &&
	    ((insn & INSN_STD_DATA_MASK) != 15)) {
		state->registers[SP] =
		    state->registers[insn & INSN_STD_DATA_MASK];
	} else if ((insn & INSN_STD_MASK) == INSN_POP_COUNT) {
		unsigned int count, reg;
		count = insn & INSN_POP_COUNT_MASK;
		update_vsp = 1;
		for (reg = 4; reg <= 4 + count; reg++) {
			state->registers[reg] = *vsp++;
			state->update_mask |= 1 << reg;
		}
		if ((insn & INSN_POP_TYPE_MASK) != 0) {
			state->registers[14] = *vsp++;
		}
	} else if (insn == INSN_FINISH) {
		state->entries = 0;
	} else if (insn == INSN_POP_REGS) {
		unsigned int mask, reg;
		mask = unwind_exec_read_byte(state);
		if (mask == 0 || (mask & 0xf0) != 0)
			return 1;
		update_vsp = 1;
		for (reg = 0; mask && reg < 4; mask >>= 1, reg++) {
			if (mask & 1) {
				state->registers[reg] = *vsp++;
				state->update_mask |= 1 << reg;
			}
		}
	} else if ((insn & INSN_VSP_LARGE_INC_MASK) == INSN_VSP_LARGE_INC) {
		unsigned int uleb128;
		uleb128 = unwind_exec_read_byte(state);
		state->registers[SP] += 0x204 + (uleb128 << 2);
	} else {
#if 0
		db_printf("Unhandled instruction %.2x\n", insn);
#endif
		return 1;
	}
	if (update_vsp) {
		state->registers[SP] = (uint32_t)vsp;
	}
#if 0
	db_printf("fp = %08x, sp = %08x, lr = %08x, pc = %08x\n",
	    state->registers[FP], state->registers[SP], state->registers[LR],
	    state->registers[PC]);
#endif
	return 0;
}
static int unwind_exec_insn ( struct unwind_state * state ) { unsigned int insn ; uint32_t * vsp = ( uint32_t * ) state -> registers [ SP ] ; int update_vsp = 0 ; if ( state -> entries == 0 ) return 1 ; insn = unwind_exec_read_byte ( state ) ; if ( ( insn & INSN_VSP_MASK ) == INSN_VSP_INC ) { state -> registers [ SP ] += ( ( insn & INSN_VSP_SIZE_MASK ) << 2 ) + 4 ; } else if ( ( insn & INSN_VSP_MASK ) == INSN_VSP_DEC ) { state -> registers [ SP ] -= ( ( insn & INSN_VSP_SIZE_MASK ) << 2 ) + 4 ; } else if ( ( insn & INSN_STD_MASK ) == INSN_POP_MASKED ) { unsigned int mask , reg ; mask = unwind_exec_read_byte ( state ) ; mask |= ( insn & INSN_STD_DATA_MASK ) << 8 ; if ( mask == 0 ) return 1 ; update_vsp = 1 ; for ( reg = 4 ; mask && reg < 16 ; mask >>= 1 , reg ++ ) { if ( mask & 1 ) { state -> registers [ reg ] = * vsp ++ ; state -> update_mask |= 1 << reg ; if ( reg == SP ) update_vsp = 0 ; } } } else if ( ( insn & INSN_STD_MASK ) == INSN_VSP_REG && ( ( insn & INSN_STD_DATA_MASK ) != 13 ) && ( ( insn & INSN_STD_DATA_MASK ) != 15 ) ) { state -> registers [ SP ] = state -> registers [ insn & INSN_STD_DATA_MASK ] ; } else if ( ( insn & INSN_STD_MASK ) == INSN_POP_COUNT ) { unsigned int count , reg ; count = insn & INSN_POP_COUNT_MASK ; update_vsp = 1 ; for ( reg = 4 ; reg <= 4 + count ; reg ++ ) { state -> registers [ reg ] = * vsp ++ ; state -> update_mask |= 1 << reg ; } if ( ( insn & INSN_POP_TYPE_MASK ) != 0 ) { state -> registers [ 14 ] = * vsp ++ ; } } else if ( insn == INSN_FINISH ) { state -> entries = 0 ; } else if ( insn == INSN_POP_REGS ) { unsigned int mask , reg ; mask = unwind_exec_read_byte ( state ) ; if ( mask == 0 || ( mask & 0xf0 ) != 0 ) return 1 ; update_vsp = 1 ; for ( reg = 0 ; mask && reg < 4 ; mask >>= 1 , reg ++ ) { if ( mask & 1 ) { state -> registers [ reg ] = * vsp ++ ; state -> update_mask |= 1 << reg ; } } } else if ( ( insn & INSN_VSP_LARGE_INC_MASK ) == INSN_VSP_LARGE_INC ) { unsigned int uleb128 ; uleb128 = unwind_exec_read_byte ( state ) ; state -> registers [ SP ] += 0x204 + ( uleb128 << 2 ) ; } else { #if 0 db_printf ( " \n " , insn ) ; #endif return 1 ; } if ( update_vsp ) { state -> registers [ SP ] = ( uint32_t ) vsp ; } #if 0 db_printf ( " \n " , state -> registers [ FP ] , state -> registers [ SP ] , state -> registers [ LR ] , state -> registers [ PC ] ) ; #endif return 0 ; }
Executes the next instruction on the list
Executes the next instruction on the list
/* This should never happen */ /* Read the next instruction */ /* Load the mask */ /* We have a refuse to unwind instruction */ /* Update SP */ /* Load the registers */ /* If we have updated SP kep its value */ /* sp = register */ /* Read how many registers to load */ /* Update sp */ /* Pop the registers */ /* Check if we are in the pop r14 version */ /* Stop processing */ /* Update SP */ /* Load the registers */ /* Read the increment value */ /* We hit a new instruction that needs to be implemented */