bool isNopInsn(Instruction::Ptr insn) { // TODO: add LEA no-ops if(insn->getOperation().getID() == e_nop) return true; if(insn->getOperation().getID() == e_lea) { std::set<Expression::Ptr> memReadAddr; insn->getMemoryReadOperands(memReadAddr); std::set<RegisterAST::Ptr> writtenRegs; insn->getWriteSet(writtenRegs); if(memReadAddr.size() == 1 && writtenRegs.size() == 1) { if(**(memReadAddr.begin()) == **(writtenRegs.begin())) { return true; } } // Check for zero displacement nopVisitor visitor; // We need to get the src operand insn->getOperand(1).getValue()->apply(&visitor); if (visitor.isNop) return true; } return false; }
/* This does a linear scan to find out which registers are used in the function, it then stores these registers so the scan only needs to be done once. It returns true or false based on whether the function is a leaf function, since if it is not the function could call out to another function that clobbers more registers so more analysis would be needed */ void parse_func::calcUsedRegs() { if (usedRegisters != NULL) return; else { usedRegisters = new parse_func_registers(); using namespace Dyninst::InstructionAPI; std::set<RegisterAST::Ptr> writtenRegs; Function::blocklist & bl = blocks(); Function::blocklist::iterator curBlock = bl.begin(); for( ; curBlock != bl.end(); ++curBlock) { InstructionDecoder d(getPtrToInstruction((*curBlock)->start()), (*curBlock)->size(), isrc()->getArch()); Instruction::Ptr i; while(i = d.decode()) { i->getWriteSet(writtenRegs); } } for(std::set<RegisterAST::Ptr>::const_iterator curReg = writtenRegs.begin(); curReg != writtenRegs.end(); ++curReg) { MachRegister r = (*curReg)->getID(); if((r & ppc32::GPR) && (r <= ppc32::r13)) { usedRegisters->generalPurposeRegisters.insert(r & 0xFFFF); } else if(((r & ppc32::FPR) && (r <= ppc32::fpr13)) || ((r & ppc32::FSR) && (r <= ppc32::fsr13))) { usedRegisters->floatingPointRegisters.insert(r & 0xFFFF); } } } return; }
void IndirectControlFlowAnalyzer::FindAllThunks() { // Enumuerate every block to find thunk for (auto bit = reachable.begin(); bit != reachable.end(); ++bit) { // We intentional treat a getting PC call as a special case that does not // end a basic block. So, we need to check every instruction to find all thunks ParseAPI::Block *b = *bit; const unsigned char* buf = (const unsigned char*)(b->obj()->cs()->getPtrToInstruction(b->start())); if( buf == NULL ) { parsing_printf("%s[%d]: failed to get pointer to instruction by offset\n",FILE__, __LINE__); return; } parsing_printf("Looking for thunk in block [%lx,%lx).", b->start(), b->end()); InstructionDecoder dec(buf, b->end() - b->start(), b->obj()->cs()->getArch()); InsnAdapter::IA_IAPI block(dec, b->start(), b->obj() , b->region(), b->obj()->cs(), b); while (block.getAddr() < b->end()) { if (block.getInstruction()->getCategory() == c_CallInsn && block.isThunk()) { bool valid; Address addr; boost::tie(valid, addr) = block.getCFT(); const unsigned char *target = (const unsigned char *) b->obj()->cs()->getPtrToInstruction(addr); InstructionDecoder targetChecker(target, InstructionDecoder::maxInstructionLength, b->obj()->cs()->getArch()); Instruction::Ptr thunkFirst = targetChecker.decode(); set<RegisterAST::Ptr> thunkTargetRegs; thunkFirst->getWriteSet(thunkTargetRegs); for (auto curReg = thunkTargetRegs.begin(); curReg != thunkTargetRegs.end(); ++curReg) { ThunkInfo t; t.reg = (*curReg)->getID(); t.value = block.getAddr() + block.getInstruction()->size(); t.value += ThunkAdjustment(t.value, t.reg, b); t.block = b; thunks.insert(make_pair(block.getAddr(), t)); parsing_printf("\tfind thunk at %lx, storing value %lx to %s\n", block.getAddr(), t.value , t.reg.name().c_str()); } } block.advance(); } } }
bool IA_x86Details::handleCall(IA_IAPI& block) { parsing_printf("\tchecking call at 0x%lx for thunk\n", block.getAddr()); if(!block.isRealCall()) { parsing_printf("\tthunk found at 0x%lx, checking for add\n", block.getAddr()); block.advance(); thunkInsn.addrFromInsn = block.getAddr(); Instruction::Ptr addInsn = block.getInstruction(); if(addInsn) parsing_printf("\tinsn after thunk: %s\n", addInsn->format().c_str()); else parsing_printf("\tNO INSN after thunk at 0x%lx\n", thunkInsn.addrFromInsn); if(addInsn) { std::set<RegisterAST::Ptr> boundRegs; if(addInsn->getOperation().getID() == e_pop) { addInsn->getWriteSet(boundRegs); block.advance(); addInsn = block.getInstruction(); } if(addInsn && ((addInsn->getOperation().getID() == e_add) || (addInsn->getOperation().getID() == e_lea))) { Expression::Ptr op0 = addInsn->getOperand(0).getValue(); Expression::Ptr op1 = addInsn->getOperand(1).getValue(); for(std::set<RegisterAST::Ptr>::const_iterator curReg = boundRegs.begin(); curReg != boundRegs.end(); ++curReg) { op0->bind(curReg->get(), Result(u64, 0)); op1->bind(curReg->get(), Result(u64, 0)); } Result imm = addInsn->getOperand(1).getValue()->eval(); Result imm2 = addInsn->getOperand(0).getValue()->eval(); if(imm.defined) { Address thunkDiff = imm.convert<Address>(); parsing_printf("\tsetting thunkInsn.addrFromInsn to 0x%lx (0x%lx + 0x%lx)\n", thunkInsn.addrFromInsn+thunkDiff, thunkInsn.addrFromInsn, thunkDiff); thunkInsn.addrOfInsn = block.getPrevAddr(); thunkInsn.addrFromInsn = thunkInsn.addrFromInsn + thunkDiff; return true; } else if(imm2.defined) { Address thunkDiff = imm2.convert<Address>(); parsing_printf("\tsetting thunkInsn.addrFromInsn to 0x%lx (0x%lx + 0x%lx)\n", thunkInsn.addrFromInsn+thunkDiff, thunkInsn.addrFromInsn, thunkDiff); thunkInsn.addrOfInsn = block.getPrevAddr(); thunkInsn.addrFromInsn = thunkInsn.addrFromInsn + thunkDiff; return true; } else { parsing_printf("\tadd insn %s found following thunk at 0x%lx, couldn't bind operands!\n", addInsn->format().c_str(), thunkInsn.addrFromInsn); } } } thunkInsn.addrFromInsn = 0; } thunkInsn.addrFromInsn = 0; thunkInsn.addrOfInsn = 0; thunkInsn.insn.reset(); return false; }
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; }