boost::tuple<Instruction::Ptr, Instruction::Ptr, bool> IA_x86Details::findMaxSwitchInsn(Block *start) { std::set<Block *> visited; std::vector<Block *> WL; Block *curBlk; int depth = 0; bool foundMaxSwitch = false; bool foundCondBranch = false; WL.push_back(start); Instruction::Ptr compareInsn, condBranchInsn; bool compareOnTakenBranch = false; for(unsigned j=0;j < WL.size(); j++) { curBlk = WL[j]; visited.insert(curBlk); foundMaxSwitch = false; foundCondBranch = false; const unsigned char* buf = (const unsigned char*)(currentBlock->_isrc->getPtrToInstruction(curBlk->start())); if( buf == NULL ) { parsing_printf("%s[%d]: failed to get pointer to instruction by offset\n", FILE__, __LINE__); return boost::make_tuple(Instruction::Ptr(), Instruction::Ptr(), false); } InstructionDecoder dec(buf, curBlk->size(), currentBlock->_isrc->getArch()); Instruction::Ptr i; Address curAdr = curBlk->start(); while((i = dec.decode())) { if(i->getCategory() == c_CompareInsn) // check for cmp { parsing_printf("\tFound jmp table cmp instruction %s at 0x%lx\n", i->format().c_str(), curAdr); compareInsn = i; foundMaxSwitch = true; } if(i->getCategory() == c_BranchInsn && i->allowsFallThrough()) { parsing_printf("\tFound jmp table cond br instruction %s at 0x%lx\n", i->format().c_str(), curAdr); condBranchInsn = i; foundCondBranch = true; Block::edgelist::const_iterator tit = curBlk->targets().begin(); bool taken_hit = false; bool fallthrough_hit = false; for ( ; tit != curBlk->targets().end(); ++tit) { ParseAPI::Edge *t = *tit; if (t->type() == COND_TAKEN && (visited.find(t->trg()) != visited.end())) { taken_hit = true; } if ((t->type() == COND_NOT_TAKEN || t->type() == FALLTHROUGH) && (visited.find(t->trg()) != visited.end())) { fallthrough_hit = true; } } parsing_printf("\tfindMaxSwitchInsn: taken_hit: %d, fallthrough_hit: %d\n", taken_hit, fallthrough_hit); compareOnTakenBranch = taken_hit && !fallthrough_hit; break; } curAdr += i->size(); } if(foundMaxSwitch && foundCondBranch) break; // done // look further back Block::edgelist::const_iterator sit = curBlk->sources().begin(); depth++; // We've seen depth 2 in libc et al if(depth > 2) return boost::make_tuple(Instruction::Ptr(), Instruction::Ptr(), false); for( ; sit != curBlk->sources().end(); ++sit) { ParseAPI::Edge * s = *sit; // ignore return edges if(s->type() == RET) continue; if(s->type() == CALL) return boost::make_tuple(Instruction::Ptr(), Instruction::Ptr(), false); Block * src = s->src(); if( (visited.find( src ) == visited.end())) { WL.push_back(src); } } } WL.clear(); parsing_printf("\tfindMaxSwitchInsn: table on taken branch: %d, returning: %d\n", compareOnTakenBranch, foundMaxSwitch && foundCondBranch); return boost::make_tuple(compareInsn, condBranchInsn, compareOnTakenBranch); }
ReadWriteInfo LivenessAnalyzer::calcRWSets(Instruction::Ptr curInsn, Block* blk, Address a) { liveness_cerr << "calcRWSets for " << curInsn->format() << " @ " << hex << a << dec << endl; ReadWriteInfo ret; ret.read = abi->getBitArray(); ret.written = abi->getBitArray(); ret.insnSize = curInsn->size(); std::set<RegisterAST::Ptr> cur_read, cur_written; curInsn->getReadSet(cur_read); curInsn->getWriteSet(cur_written); liveness_printf("Read registers: \n"); for (std::set<RegisterAST::Ptr>::const_iterator i = cur_read.begin(); i != cur_read.end(); i++) { MachRegister cur = (*i)->getID(); if (cur.getArchitecture() == Arch_ppc64) cur = MachRegister((cur.val() & ~Arch_ppc64) | Arch_ppc32); liveness_printf("\t%s \n", cur.name().c_str()); MachRegister base = cur.getBaseRegister(); if (cur == x86::flags || cur == x86_64::flags){ if (width == 4){ ret.read[getIndex(x86::of)] = true; ret.read[getIndex(x86::cf)] = true; ret.read[getIndex(x86::pf)] = true; ret.read[getIndex(x86::af)] = true; ret.read[getIndex(x86::zf)] = true; ret.read[getIndex(x86::sf)] = true; ret.read[getIndex(x86::df)] = true; ret.read[getIndex(x86::tf)] = true; ret.read[getIndex(x86::nt_)] = true; } else { ret.read[getIndex(x86_64::of)] = true; ret.read[getIndex(x86_64::cf)] = true; ret.read[getIndex(x86_64::pf)] = true; ret.read[getIndex(x86_64::af)] = true; ret.read[getIndex(x86_64::zf)] = true; ret.read[getIndex(x86_64::sf)] = true; ret.read[getIndex(x86_64::df)] = true; ret.read[getIndex(x86_64::tf)] = true; ret.read[getIndex(x86_64::nt_)] = true; } } else{ base = changeIfMMX(base); ret.read[getIndex(base)] = true; } } liveness_printf("Write Registers: \n"); for (std::set<RegisterAST::Ptr>::const_iterator i = cur_written.begin(); i != cur_written.end(); i++) { MachRegister cur = (*i)->getID(); if (cur.getArchitecture() == Arch_ppc64) cur = MachRegister((cur.val() & ~Arch_ppc64) | Arch_ppc32); liveness_printf("\t%s \n", cur.name().c_str()); MachRegister base = cur.getBaseRegister(); if (cur == x86::flags || cur == x86_64::flags){ if (width == 4){ ret.written[getIndex(x86::of)] = true; ret.written[getIndex(x86::cf)] = true; ret.written[getIndex(x86::pf)] = true; ret.written[getIndex(x86::af)] = true; ret.written[getIndex(x86::zf)] = true; ret.written[getIndex(x86::sf)] = true; ret.written[getIndex(x86::df)] = true; ret.written[getIndex(x86::tf)] = true; ret.written[getIndex(x86::nt_)] = true; } else { ret.written[getIndex(x86_64::of)] = true; ret.written[getIndex(x86_64::cf)] = true; ret.written[getIndex(x86_64::pf)] = true; ret.written[getIndex(x86_64::af)] = true; ret.written[getIndex(x86_64::zf)] = true; ret.written[getIndex(x86_64::sf)] = true; ret.written[getIndex(x86_64::df)] = true; ret.written[getIndex(x86_64::tf)] = true; ret.written[getIndex(x86_64::nt_)] = true; } } else{ base = changeIfMMX(base); ret.written[getIndex(base)] = true; if ((cur != base && cur.size() < 4) || isMMX(base)) ret.read[getIndex(base)] = true; } } InsnCategory category = curInsn->getCategory(); switch(category) { case c_CallInsn: // Call instructions not at the end of a block are thunks, which are not ABI-compliant. // So make conservative assumptions about what they may read (ABI) but don't assume they write anything. ret.read |= (abi->getCallReadRegisters()); if(blk->lastInsnAddr() == a) { ret.written |= (abi->getCallWrittenRegisters()); } break; case c_ReturnInsn: ret.read |= (abi->getReturnReadRegisters()); // Nothing written implicitly by a return break; case c_BranchInsn: if(!curInsn->allowsFallThrough() && isExitBlock(blk)) { //Tail call, union of call and return ret.read |= ((abi->getCallReadRegisters()) | (abi->getReturnReadRegisters())); ret.written |= (abi->getCallWrittenRegisters()); } break; default: { bool isInterrupt = false; bool isSyscall = false; if ((curInsn->getOperation().getID() == e_int) || (curInsn->getOperation().getID() == e_int3)) { isInterrupt = true; } static RegisterAST::Ptr gs(new RegisterAST(x86::gs)); if (((curInsn->getOperation().getID() == e_call) && /*(curInsn()->getOperation().isRead(gs))) ||*/ (curInsn->getOperand(0).format(curInsn->getArch()) == "16")) || (curInsn->getOperation().getID() == e_syscall) || (curInsn->getOperation().getID() == e_int) || (curInsn->getOperation().getID() == power_op_sc)) { isSyscall = true; } if (curInsn->getOperation().getID() == power_op_svcs) { isSyscall = true; } if (isInterrupt || isSyscall) { ret.read |= (abi->getSyscallReadRegisters()); ret.written |= (abi->getSyscallWrittenRegisters()); } } break; } return ret; }