/* * returns the basic block where code execution continues, or * NULL if the instruction always branches away * (The caller needs this to link the basic block) */ BasicBlock * translate_instr(cpu_t *cpu, addr_t pc, tag_t tag, BasicBlock *bb_target, /* target for branch/call/rey */ BasicBlock *bb_trap, /* target for trap */ BasicBlock *bb_next, /* non-taken for conditional */ BasicBlock *cur_bb) { BasicBlock *bb_cond = NULL; BasicBlock *bb_delay = NULL; /* create internal basic blocks if needed */ if (tag & TAG_CONDITIONAL) bb_cond = create_basicblock(cpu, pc, cpu->cur_func, BB_TYPE_COND); if ((tag & TAG_DELAY_SLOT) && (tag & TAG_CONDITIONAL)) bb_delay = create_basicblock(cpu, pc, cpu->cur_func, BB_TYPE_DELAY); /* special case: delay slot */ if (tag & TAG_DELAY_SLOT) { if (tag & TAG_CONDITIONAL) { addr_t delay_pc; // cur_bb: if (cond) goto b_cond; else goto bb_delay; Value *c = cpu->f.translate_cond(cpu, pc, cur_bb); BranchInst::Create(bb_cond, bb_delay, c, cur_bb); // bb_cond: instr; delay; goto bb_target; pc += cpu->f.translate_instr(cpu, pc, bb_cond); delay_pc = pc; cpu->f.translate_instr(cpu, pc, bb_cond); BranchInst::Create(bb_target, bb_cond); // bb_cond: delay; goto bb_next; cpu->f.translate_instr(cpu, delay_pc, bb_delay); BranchInst::Create(bb_next, bb_delay); } else { // cur_bb: instr; delay; goto bb_target; pc += cpu->f.translate_instr(cpu, pc, cur_bb); cpu->f.translate_instr(cpu, pc, cur_bb); BranchInst::Create(bb_target, cur_bb); } return NULL; /* don't link */ } /* no delay slot */ if (tag & TAG_CONDITIONAL) { // cur_bb: if (cond) goto b_cond; else goto bb_next; Value *c = cpu->f.translate_cond(cpu, pc, cur_bb); BranchInst::Create(bb_cond, bb_next, c, cur_bb); cur_bb = bb_cond; } cpu->f.translate_instr(cpu, pc, cur_bb); if (tag & (TAG_BRANCH | TAG_CALL | TAG_RET)) BranchInst::Create(bb_target, cur_bb); else if (tag & TAG_TRAP) BranchInst::Create(bb_trap, cur_bb); if (tag & TAG_CONTINUE) return cur_bb; else return NULL; }
BasicBlock * create_singlestep_return_basicblock(cpu_t *cpu, addr_t new_pc, BasicBlock *bb_ret) { BasicBlock *bb_branch = create_basicblock(cpu, new_pc, cpu->dyncom_engine->cur_func, BB_TYPE_NORMAL); emit_store_pc_return(cpu, bb_branch, new_pc, bb_ret); return bb_branch; }
BasicBlock * cpu_translate_singlestep_bb(cpu_t *cpu, BasicBlock *bb_ret, BasicBlock *bb_trap) { addr_t entry = cpu->f.get_pc(cpu, cpu->rf.grf); addr_t pc = entry; BasicBlock *cur_bb = create_basicblock(cpu, pc, cpu->cur_func, BB_TYPE_NORMAL); tag_t tag; BasicBlock *bb_target = NULL, *bb_next = NULL, *bb_cont = NULL; do { //printf("%s:%d\n", __func__, __LINE__); addr_t new_pc, next_pc; if (LOGGING) disasm_instr(cpu, pc); cpu->f.tag_instr(cpu, pc, &tag, &new_pc, &next_pc); /* get target basic block */ if (tag & TAG_RET) bb_target = bb_ret; if (tag & (TAG_CALL|TAG_BRANCH)) { if (new_pc == NEW_PC_NONE) { /* translate_instr() will set PC */ bb_target = bb_ret; } else { if (new_pc == entry) /* tight loop */ bb_target = cur_bb; else bb_target = create_singlestep_return_basicblock(cpu, new_pc, bb_ret); } } /* get not-taken basic block */ if (tag & TAG_CONDITIONAL) bb_next = create_singlestep_return_basicblock(cpu, next_pc, bb_ret); bb_cont = translate_instr(cpu, pc, tag, bb_target, bb_trap, bb_next, cur_bb); pc = next_pc; } while (is_inside_code_area(cpu, pc) && /* end of code section */ bb_cont); /* last intruction jumped away */ return cur_bb; }
BasicBlock * cpu_translate_all(cpu_t *cpu, BasicBlock *bb_ret, BasicBlock *bb_trap) { // find all instructions that need labels and create basic blocks for them int bbs = 0; addr_t pc; pc = cpu->code_start; while (pc < cpu->code_end) { // Do not create the basic block if it is already present in some other function. if (is_start_of_basicblock(cpu, pc) && !(get_tag(cpu, pc) & TAG_TRANSLATED)) { create_basicblock(cpu, pc, cpu->cur_func, BB_TYPE_NORMAL); bbs++; } pc++; } LOG("bbs: %d\n", bbs); // create dispatch basicblock BasicBlock* bb_dispatch = BasicBlock::Create(_CTX(), "dispatch", cpu->cur_func, 0); Value *v_pc = new LoadInst(cpu->ptr_PC, "", false, bb_dispatch); SwitchInst* sw = SwitchInst::Create(v_pc, bb_ret, bbs, bb_dispatch); // translate basic blocks bbaddr_map &bb_addr = cpu->func_bb[cpu->cur_func]; bbaddr_map::const_iterator it; for (it = bb_addr.begin(); it != bb_addr.end(); it++) { pc = it->first; BasicBlock *cur_bb = it->second; tag_t tag; BasicBlock *bb_target = NULL, *bb_next = NULL, *bb_cont = NULL; // Tag the function as translated. or_tag(cpu, pc, TAG_TRANSLATED); LOG("basicblock: L%08llx\n", (unsigned long long)pc); // Add dispatch switch case for basic block. ConstantInt* c = ConstantInt::get(getIntegerType(cpu->info.address_size), pc); sw->addCase(c, cur_bb); do { tag_t dummy1; if (LOGGING) disasm_instr(cpu, pc); tag = get_tag(cpu, pc); /* get address of the following instruction */ addr_t new_pc, next_pc; cpu->f.tag_instr(cpu, pc, &dummy1, &new_pc, &next_pc); /* get target basic block */ if (tag & TAG_RET) bb_target = bb_dispatch; if (tag & (TAG_CALL|TAG_BRANCH)) { if (new_pc == NEW_PC_NONE) /* translate_instr() will set PC */ bb_target = bb_dispatch; else bb_target = (BasicBlock*)lookup_basicblock(cpu, cpu->cur_func, new_pc, bb_ret, BB_TYPE_NORMAL); } /* get not-taken basic block */ if (tag & TAG_CONDITIONAL) bb_next = (BasicBlock*)lookup_basicblock(cpu, cpu->cur_func, next_pc, bb_ret, BB_TYPE_NORMAL); bb_cont = translate_instr(cpu, pc, tag, bb_target, bb_trap, bb_next, cur_bb); pc = next_pc; } while ( /* new basic block starts here (and we haven't translated it yet)*/ (!is_start_of_basicblock(cpu, pc)) && /* end of code section */ //XXX no: this is whether it's TAG_CODE is_code(cpu, pc) && /* last intruction jumped away */ bb_cont ); /* link with next basic block if there isn't a control flow instr. already */ if (bb_cont) { BasicBlock *target = (BasicBlock*)lookup_basicblock(cpu, cpu->cur_func, pc, bb_ret, BB_TYPE_NORMAL); LOG("info: linking continue $%04llx!\n", (unsigned long long)pc); BranchInst::Create(target, bb_cont); } } return bb_dispatch; }