动态翻译器执行时如果出现异常,可如何确定异常位置对应的目标位置呢?
首先,执行语句:
tb = tb_find_pc(pc);
其中pc表示异常出现时宿主PC值,如果返回的tb不为NULL,则说明异常发生在动态翻译代码执行时。
为了恢复目标CPU的状态,需要使用cpu_restore_state函数。它与函数cpu_gen_code类似,但两者生成中间码时调用函数分别是gen_intermediate_code与gen_intermediate_code_pc:
void gen_intermediate_code(CPUSPARCState * env, TranslationBlock * tb)
{
gen_intermediate_code_internal(tb, 0, env);
}
void gen_intermediate_code_pc(CPUSPARCState * env, TranslationBlock * tb)
{
gen_intermediate_code_internal(tb, 1, env);
}
gen_intermediate_code_pc函数在生成中间码时,多了下面的处理(sparc)
if (spc) {//spc=1
qemu_log("Search PC...\n");
j = gen_opc_ptr - gen_opc_buf;
if (lj < j) {//zhxc, 一条目标指令翻译后可能对应多个操作
lj++;
while (lj < j)
gen_opc_instr_start[lj++] = 0;
gen_opc_pc[lj] = dc->pc;
gen_opc_npc[lj] = dc->npc;
gen_opc_instr_start[lj] = 1;
gen_opc_icount[lj] = num_insns;
}
}
通过gen_opc_pc与gen_opc_npc可以知道TB中每条目标指令对应的PC与NPC值;
通过gen_opc_instr_start可以知道中间指令与目标指令的对应关系;
通过gen_opc_icount可以知道指令在TB中的位置;
如基本块中前两条指令时A、B,指令分别对应2和3条中间指令,则
gen_opc_pc[0] = PC0;
gen_opc_npc[0] = PC0+4;
gen_opc_instr_start[0] = 1;
gen_opc_icount[0] = 0;
gen_opc_instr_start[1] = 0;
gen_opc_pc[2] = PC0+4;
gen_opc_npc[2] = PC0+8;
gen_opc_instr_start[2] = 1;
gen_opc_icount[2] = 1;
gen_opc_instr_start[3] = 0;
gen_opc_instr_start[4] = 0;
假设执行第3条中间码生成的宿主指令时出错,则下面语句返回j=3:
j = tcg_gen_code_search_pc(s, (uint8_t *)tc_ptr, searched_pc - tc_ptr);
通过语句:
while (gen_opc_instr_start[j] == 0)
j--;
可以确定j=2,于是在gen_pc_load函数中可以确定发生出错时对应的目标码PC值。
void gen_pc_load(CPUState *env, TranslationBlock *tb,
unsigned long searched_pc, int pc_pos, void *puc)
{
target_ulong npc;
env->pc = gen_opc_pc[pc_pos];
npc = gen_opc_npc[pc_pos];
if (npc == 1) {
/* dynamic NPC: already stored */
} else if (npc == 2) {
/* jump PC: use 'cond' and the jump targets of the translation */
if (env->cond) {
env->npc = gen_opc_jump_pc[0];
} else {
env->npc = gen_opc_jump_pc[1];
}
} else {
env->npc = npc;
}
/* flush pending conditional evaluations before exposing cpu state */
if (CC_OP != CC_OP_FLAGS) {
helper_compute_psr();
}
}