bool EmulateInstructionMIPS::Emulate_LW (llvm::MCInst& insn) { uint32_t src, base; src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); if (base == gcc_dwarf_sp_mips64 && nonvolatile_reg_p (src)) { RegisterValue data_src; RegisterInfo reg_info_src; if (!GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + src, reg_info_src)) return false; Context context; context.type = eContextRegisterLoad; if (!WriteRegister (context, ®_info_src, data_src)) return false; return true; } return false; }
bool EmulateInstructionMIPS::Emulate_ADDiu (llvm::MCInst& insn) { bool success = false; const uint32_t imm16 = insn.getOperand(2).getImm(); uint32_t imm = SignedBits(imm16, 15, 0); uint64_t result; uint32_t src, dst; dst = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); src = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); /* Check if this is addiu sp,<src>,imm16 */ if (dst == gcc_dwarf_sp_mips64) { /* read <src> register */ uint64_t src_opd_val = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + src, 0, &success); if (!success) return false; result = src_opd_val + imm; Context context; RegisterInfo reg_info_sp; if (GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_sp_mips64, reg_info_sp)) context.SetRegisterPlusOffset (reg_info_sp, imm); /* We are allocating bytes on stack */ context.type = eContextAdjustStackPointer; WriteRegisterUnsigned (context, eRegisterKindDWARF, gcc_dwarf_sp_mips64, result); } return true; }
static std::string getLocalName(const llvm::MCInst& inst, unsigned iop) { const llvm::MCOperand& op = inst.getOperand(iop); if (op.isReg() && strcmp(MRI->getName(op.getReg()), "RBP") == 0) { char buf[128]; snprintf(buf, 128, "local_%x", -inst.getOperand(iop + 3).getImm()); return std::string(buf); } else { return std::string("UNK"); } }
bool EmulateInstructionMIPS::Emulate_SW (llvm::MCInst& insn) { bool success = false; uint32_t imm16 = insn.getOperand(2).getImm(); uint32_t imm = SignedBits(imm16, 15, 0); uint32_t src, base; src = m_reg_info->getEncodingValue (insn.getOperand(0).getReg()); base = m_reg_info->getEncodingValue (insn.getOperand(1).getReg()); /* We look for sp based non-volatile register stores */ if (base == gcc_dwarf_sp_mips64 && nonvolatile_reg_p (src)) { uint32_t address; RegisterInfo reg_info_base; RegisterInfo reg_info_src; if (!GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + base, reg_info_base) || !GetRegisterInfo (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + src, reg_info_src)) return false; /* read SP */ address = ReadRegisterUnsigned (eRegisterKindDWARF, gcc_dwarf_zero_mips64 + base, 0, &success); if (!success) return false; /* destination address */ address = address + imm; Context context; RegisterValue data_src; context.type = eContextPushRegisterOnStack; context.SetRegisterToRegisterPlusOffset (reg_info_src, reg_info_base, 0); uint8_t buffer [RegisterValue::kMaxRegisterByteSize]; Error error; if (!ReadRegister (®_info_base, data_src)) return false; if (data_src.GetAsMemoryData (®_info_src, buffer, reg_info_src.byte_size, eByteOrderLittle, error) == 0) return false; if (!WriteMemory (context, address, buffer, reg_info_src.byte_size)) return false; return true; } return false; }
static void printInst(const llvm::MCInst& inst) { const llvm::MCInstrDesc& id = MII->get(inst.getOpcode()); llvm::outs() << MII->getName(inst.getOpcode()) << " (" << inst.getNumOperands() << ") "; for (int iop = 0; iop < inst.getNumOperands(); ++iop) { const llvm::MCOperand& op = inst.getOperand(iop); if (op.isReg()) { unsigned reg = op.getReg(); const char* rcName; char clsn[128]; if (id.OpInfo[iop].RegClass < MRI->getNumRegClasses()) { const llvm::MCRegisterClass& rc = MRI->getRegClass(id.OpInfo[iop].RegClass); rcName = rc.getName(); } else { snprintf(clsn, sizeof(clsn), "CLS%d", id.OpInfo[iop].RegClass); rcName = clsn; } llvm::outs() << MRI->getName(reg) << "(" << rcName << ", " << (uint64_t)id.OpInfo[iop].OperandType << ")"; } else if (op.isImm()) { llvm::outs() << op.getImm() << "(" << (uint64_t)id.OpInfo[iop].OperandType << ")"; } else { llvm::outs() << "<UNK>"; } llvm::outs() << ", "; } llvm::outs() << "\n"; }
// Convert the given assembly instruction into an inline ASM operation in lieu // of decompiling it. The output instruction will look something like this // (although note that i128 doesn't work properly with LLVM codegen for the // inline ASM instructions, necessitating a vector instead). // %151 = load i128, i128* %XMM0_read // %152 = bitcast i128 %151 to <16 x i8> // %153 = load i128, i128* %XMM1_read // %154 = bitcast i128 %153 to <16 x i8> // %AESDECrr = call <16 x i8> asm "\09aesdec\09%xmm1, %xmm0", "={XMM0},{XMM0},{XMM1}"(<16 x i8> %152, <16 x i8> %154) // %155 = bitcast <16 x i8> %AESDECrr to i128 // store volatile i128 %155, i128* %XMM0_write void ArchBuildInlineAsm(llvm::MCInst &inst, llvm::BasicBlock *block) { auto opcode = inst.getOpcode(); // Use the printer to build the ASM string. We'll need to escape the $ in // register names with $$. std::stringstream asmString; { std::string outS; llvm::raw_string_ostream strOut(outS); gIP->printInst(&inst, strOut, "", *gSTI); for (char c : strOut.str()) { if (c == '$') asmString << "$$"; else asmString << c; } } // Next, find all the registers being used as definitions or uses in the // inline ASM. This will write up the constraints for us, as well as // provide us with a list of types (for the inline ASM output) and a list of // values to pass into the string. llvm::SmallVector<llvm::Value *, 3> operands; llvm::SmallVector<llvm::Type *, 3> resultTypes; std::stringstream constraints; for (unsigned i = 0; i < inst.getNumOperands(); i++) { llvm::MCOperand &op = inst.getOperand(i); if (op.isReg()) { unsigned regSize = ArchRegisterSize(op.getReg()); if (constraints.tellp() > 0) constraints << ","; if (i < gMII->get(opcode).getNumDefs()) { constraints << "="; if (regSize > 64) { // LLVM can't handle register constraints of i128, so we // need to map this to <16 x i8>. resultTypes.push_back(llvm::VectorType::get( llvm::Type::getInt8Ty(block->getContext()), regSize / 8)); } else { resultTypes.push_back(llvm::IntegerType::get(block->getContext(), regSize)); } } else { auto readReg = GENERIC_MC_READREG(block, op.getReg(), regSize); if (regSize > 64) { // LLVM can't handle register constraints of i128, so we // need to map this to <16 x i8>. readReg = llvm::CastInst::Create(llvm::Instruction::BitCast, readReg, llvm::VectorType::get(llvm::Type::getInt8Ty(block->getContext()), regSize / 8), "", block); } operands.push_back(readReg); } constraints << "{" << gMRI->getName(op.getReg()) << "}"; } } // With all of these pieces, piece together the actual call to the inline ASM // string. llvm::SmallVector<llvm::Type *, 3> argTypes; for (auto val : operands) argTypes.push_back(val->getType()); llvm::Type *returnTy; if (resultTypes.empty()) returnTy = llvm::Type::getVoidTy(block->getContext()); else if (resultTypes.size() == 1) returnTy = resultTypes[0]; else returnTy = llvm::StructType::get(block->getContext(), resultTypes); auto asmTy = llvm::FunctionType::get(returnTy, argTypes, false); auto callee = llvm::InlineAsm::get(asmTy, asmString.str(), constraints.str(), false); llvm::Value *resultPack = llvm::CallInst::Create(callee, operands, "", block); // Unpack the called registers into the LLVM values. for (unsigned i = 0; i < resultTypes.size(); i++) { llvm::Value *result = resultTypes.size() == 1 ? resultPack : llvm::ExtractValueInst::Create(resultPack, i, "", block); llvm::Type *ty = resultTypes[i]; // Cast vector outputs to iXYZ for R_WRITE. if (ty->isVectorTy()) { ty = llvm::Type::getIntNTy(block->getContext(), ty->getVectorNumElements() * 8); result = llvm::CastInst::Create(llvm::Instruction::BitCast, result, ty, "", block); } unsigned regNo = inst.getOperand(i).getReg(); GENERIC_MC_WRITEREG(block, regNo, result); } }