void ARM64InstPrinter::printAMIndexed(const MCInst *MI, unsigned OpNum, unsigned Scale, raw_ostream &O) { const MCOperand MO1 = MI->getOperand(OpNum + 1); O << '[' << getRegisterName(MI->getOperand(OpNum).getReg()); if (MO1.isImm()) { if (MO1.getImm() != 0) O << ", #" << (MO1.getImm() * Scale); } else { assert (MO1.isExpr() && "Unexpected operand type!"); O << ", " << *MO1.getExpr(); } O << ']'; }
// assume the immediate references code if: // * we are dealing with a fully linked ELF // * The immediate is in the range of a valid code or data section static bool setHeuristicRef(ExecutableContainer *c, InstPtr I, int opnum, stack<VA> &funcs, raw_ostream &out, const std::string whichInst) { MCOperand op; std::string imp_name; ElfTarget *elft = dynamic_cast<ElfTarget*>(c); op = I->get_inst().getOperand(opnum); LASSERT(op.isImm(), "No immediate operand for " + whichInst); VA imm = op.getImm(); if(elft && elft->isLinked()) { if (elft->is_in_code(imm)) { // this instruction references code I->set_call_tgt(imm); // make sure we disassemble at this new address funcs.push(imm); out << "Found new function entry from " << whichInst << ": " << to_string<VA>(imm, hex) << "\n"; return true; } else if (elft->is_in_data(imm)) { out << "Adding local data ref to: " << to_string<VA>(imm, hex) << "\n"; I->set_data_offset(imm); } else if (c->find_import_name(imm, imp_name)) { out << "Import name is: " << imp_name << "\n"; } } return false; }
static InstTransResult doSubRI(InstPtr ip, BasicBlock *&b, const MCOperand &dst, const MCOperand &src1, const MCOperand &src2) { NASSERT(src1.isReg()); NASSERT(src2.isImm()); NASSERT(dst.isReg()); // Read from src1. Value *srcReg = R_READ<dstWidth>(b, src1.getReg()); // Create the constant value. Value *c = CONST_V<srcWidth>(b, src2.getImm()); CastInst *cInst = CastInst::CreateIntegerCast(c, srcReg->getType(), true, "", b); // Do the operation. Value *subRes = doSubVV<dstWidth>(ip, b, srcReg, cInst); // Store the result in dst. R_WRITE<dstWidth>(b, dst.getReg(), subRes); return ContinueBlock; }
unsigned SparcMCCodeEmitter:: getMachineOpValue(const MCInst &MI, const MCOperand &MO, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { if (MO.isReg()) return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg()); if (MO.isImm()) return MO.getImm(); assert(MO.isExpr()); const MCExpr *Expr = MO.getExpr(); if (const SparcMCExpr *SExpr = dyn_cast<SparcMCExpr>(Expr)) { MCFixupKind Kind = (MCFixupKind)SExpr->getFixupKind(); Fixups.push_back(MCFixup::create(0, Expr, Kind)); return 0; } int64_t Res; if (Expr->evaluateAsAbsolute(Res)) return Res; llvm_unreachable("Unhandled expression!"); return 0; }
uint64_t R600MCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { if (MO.isReg()) { if (HAS_NATIVE_OPERANDS(MCII.get(MI.getOpcode()).TSFlags)) return MRI.getEncodingValue(MO.getReg()); return getHWReg(MO.getReg()); } if (MO.isExpr()) { const MCSymbolRefExpr *Expr = cast<MCSymbolRefExpr>(MO.getExpr()); // We put rodata at the end of code section, then map the entire // code secetion as vtx buf. Thus the section relative address is the // correct one. // Each R600 literal instruction has two operands // We can't easily get the order of the current one, so compare against // the first one and adjust offset. const unsigned offset = (&MO == &MI.getOperand(0)) ? 0 : 4; Fixups.push_back(MCFixup::create(offset, Expr, FK_SecRel_4, MI.getLoc())); return 0; } assert(MO.isImm()); return MO.getImm(); }
static InstTransResult doPSLLri(BasicBlock *&b, const MCOperand &dst, const MCOperand &src) { NASSERT(src.isImm()); Value *shift_count = CONST_V<128>(b, src.getImm()); return doNewShift<width, Instruction::Shl>(b, dst, shift_count, CONST_V<128>(b, 0)); }
void SystemZInstPrinter::printOperand(const MCOperand &MO, raw_ostream &O) { if (MO.isReg()) O << '%' << getRegisterName(MO.getReg()); else if (MO.isImm()) O << MO.getImm(); else if (MO.isExpr()) O << *MO.getExpr(); else llvm_unreachable("Invalid operand"); }
/// getMachineOpValue - Return binary encoding of operand. If the machine /// operand requires relocation, record the relocation and return zero. unsigned AArch64MCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { if (MO.isReg()) return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg()); assert(MO.isImm() && "did not expect relocated expression"); return static_cast<unsigned>(MO.getImm()); }
static InstTransResult doMIMov(InstPtr ip, BasicBlock *&b, Value *dstAddr, const MCOperand &src) { //MOV <m>, <imm> //store the constant in src into dstAddr NASSERT(dstAddr != NULL); NASSERT(src.isImm()); return doMIMovV<width>(ip, b, dstAddr, CONST_V<width>(b, src.getImm())); }
static InstTransResult doPEXTRWmr(InstPtr ip, BasicBlock *&b, Value *memAddr, const MCOperand &src, const MCOperand &order) { NASSERT(src.isReg()); NASSERT(order.isImm()); Value *vec = R_READ<128>(b, src.getReg()); Value *item = doExtraction<128,16>(b, vec, order.getImm()); M_WRITE<16>(ip, b, memAddr, item); return ContinueBlock; }
static InstTransResult doRIMov(InstPtr ip, BasicBlock *&b, const MCOperand &src, const MCOperand &dst) { //MOV <r>, <imm> NASSERT(src.isImm()); NASSERT(dst.isReg()); //write the constant into the supplied register R_WRITE<width>(b, dst.getReg(), CONST_V<width>(b, src.getImm())); return ContinueBlock; }
static InstTransResult doPSHUFDri(BasicBlock *&b, const MCOperand &dst, const MCOperand &src, const MCOperand &order) { NASSERT(dst.isReg()); NASSERT(src.isReg()); NASSERT(order.isImm()); Value *input = R_READ<128>(b, src.getReg()); Value *shuffled = doShuffle<128,32>(b, input, order.getImm()); R_WRITE<128>(b, dst.getReg(), shuffled); return ContinueBlock; }
static InstTransResult doPSHUFDmi(InstPtr ip, BasicBlock *&b, const MCOperand &dst, Value *mem_addr, const MCOperand &order) { NASSERT(dst.isReg()); NASSERT(order.isImm()); Value *input = M_READ<128>(ip, b, mem_addr); Value *shuffled = doShuffle<128,32>(b, input, order.getImm()); R_WRITE<128>(b, dst.getReg(), shuffled); return ContinueBlock; }
unsigned RISCVMCCodeEmitter::getMachineOpValue(const MCInst &MI, const MCOperand &MO, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { if (MO.isReg()) return Ctx.getRegisterInfo()->getEncodingValue(MO.getReg()); if (MO.isImm()) return static_cast<unsigned>(MO.getImm()); llvm_unreachable("Unhandled expression!"); return 0; }
static InstTransResult doPINSRWrmi(InstPtr ip, BasicBlock *&b, const MCOperand &dst, Value *memAddr, const MCOperand &order) { NASSERT(dst.isReg()); NASSERT(order.isImm()); Value *vec = R_READ<128>(b, dst.getReg()); Value *elem = M_READ<16>(ip, b, memAddr); Value *new_vec = doInsertion<128,16>(b, vec, elem, order.getImm()); R_WRITE<128>(b, dst.getReg(), new_vec); return ContinueBlock; }
static InstTransResult doPINSRWrri(BasicBlock *&b, const MCOperand &dst, const MCOperand &src, const MCOperand &order) { NASSERT(dst.isReg()); NASSERT(src.isReg()); NASSERT(order.isImm()); Value *vec = R_READ<128>(b, dst.getReg()); Value *elem = R_READ<16>(b, src.getReg()); Value *new_vec = doInsertion<128,16>(b, vec, elem, order.getImm()); R_WRITE<128>(b, dst.getReg(), new_vec); return ContinueBlock; }
static InstTransResult doXorMI(InstPtr ip, BasicBlock *&b, Value *addr, const MCOperand &imm) { TASSERT(addr != NULL, ""); TASSERT(imm.isImm(), ""); Value *fromMem = M_READ<width>(ip, b, addr); Value *fromImm = CONST_V<width>(b, imm.getImm()); Value *res = doXorVV<width>(ip, b, fromMem, fromImm); M_WRITE<width>(ip, b, addr, res); return ContinueBlock; }
MCInst HexagonMCInstrInfo::deriveExtender(MCInstrInfo const &MCII, MCInst const &Inst, MCOperand const &MO) { assert(HexagonMCInstrInfo::isExtendable(MCII, Inst) || HexagonMCInstrInfo::isExtended(MCII, Inst)); MCInst XMI; XMI.setOpcode(Hexagon::A4_ext); if (MO.isImm()) XMI.addOperand(MCOperand::createImm(MO.getImm() & (~0x3f))); else if (MO.isExpr()) XMI.addOperand(MCOperand::createExpr(MO.getExpr())); else llvm_unreachable("invalid extendable operand"); return XMI; }
static InstTransResult doSubMI(InstPtr ip, BasicBlock *&b, Value *addr, const MCOperand &imm) { NASSERT(addr != NULL); NASSERT(imm.isImm()); Value *mem_v = M_READ<width>(ip, b, addr); Value *c = CONST_V<width>(b, imm.getImm()); Value *res = doSubVV<width>(ip, b, mem_v, c); M_WRITE<width>(ip, b, addr, res); return ContinueBlock; }
static InstTransResult doXorRI(InstPtr ip, BasicBlock *&b, const MCOperand &dst, const MCOperand &o1, const MCOperand &o2) { TASSERT(dst.isReg(), ""); TASSERT(o1.isReg(), ""); TASSERT(o2.isImm(), ""); Value *o1_v = R_READ<width>(b, o1.getReg()); Value *o2_v = CONST_V<width>(b, o2.getImm()); R_WRITE<width>(b, dst.getReg(), doXorVV<width>(ip, b, o1_v, o2_v)); return ContinueBlock; }
void llvm::LowerARMMachineInstrToMCInst(const MachineInstr *MI, MCInst &OutMI, ARMAsmPrinter &AP) { OutMI.setOpcode(MI->getOpcode()); // In the MC layer, we keep modified immediates in their encoded form bool EncodeImms = false; switch (MI->getOpcode()) { default: break; case ARM::MOVi: case ARM::MVNi: case ARM::CMPri: case ARM::CMNri: case ARM::TSTri: case ARM::TEQri: case ARM::MSRi: case ARM::ADCri: case ARM::ADDri: case ARM::ADDSri: case ARM::SBCri: case ARM::SUBri: case ARM::SUBSri: case ARM::ANDri: case ARM::ORRri: case ARM::EORri: case ARM::BICri: case ARM::RSBri: case ARM::RSBSri: case ARM::RSCri: EncodeImms = true; break; } for (unsigned i = 0, e = MI->getNumOperands(); i != e; ++i) { const MachineOperand &MO = MI->getOperand(i); MCOperand MCOp; if (AP.lowerOperand(MO, MCOp)) { if (MCOp.isImm() && EncodeImms) { int32_t Enc = ARM_AM::getSOImmVal(MCOp.getImm()); if (Enc != -1) MCOp.setImm(Enc); } OutMI.addOperand(MCOp); } } }
static InstTransResult doSbbRI(InstPtr ip, BasicBlock *&b, const MCOperand &o1, const MCOperand &o2, const MCOperand &dst) { NASSERT(o1.isReg()); NASSERT(o2.isImm()); NASSERT(dst.isReg()); Value *r1 = R_READ<width>(b, o1.getReg()); Value *c = CONST_V<width>(b, o2.getImm()); Value *res = doSbbVV<width>(ip, b, r1, c); R_WRITE<width>(b, dst.getReg(), res); return ContinueBlock; }
/// getMachineOpValue - Return binary encoding of operand. If the machine /// operand requires relocation, record the relocation and return zero. unsigned Cpu0MCCodeEmitter:: getMachineOpValue(const MCInst &MI, const MCOperand &MO, SmallVectorImpl<MCFixup> &Fixups, const MCSubtargetInfo &STI) const { if (MO.isReg()) { unsigned Reg = MO.getReg(); unsigned RegNo = Ctx.getRegisterInfo()->getEncodingValue(Reg); return RegNo; } else if (MO.isImm()) { return static_cast<unsigned>(MO.getImm()); } else if (MO.isFPImm()) { return static_cast<unsigned>(APFloat(MO.getFPImm()) .bitcastToAPInt().getHiBits(32).getLimitedValue()); } // MO must be an Expr. assert(MO.isExpr()); return getExprOpValue(MO.getExpr(),Fixups, STI); }
static InstTransResult doIMulRRI(InstPtr ip, BasicBlock *&b, const MCOperand &dst, const MCOperand &lhs, const MCOperand &rhs) { NASSERT(dst.isReg()); NASSERT(lhs.isReg()); NASSERT(rhs.isImm()); Value *res = doIMulVVV<width>(ip, b, R_READ<width>(b, lhs.getReg()), CONST_V<width>(b, rhs.getImm())); R_WRITE<width>(b, dst.getReg(), res); return ContinueBlock; }
void SparcAsmParser::expandSET(MCInst &Inst, SMLoc IDLoc, SmallVectorImpl<MCInst> &Instructions) { MCOperand MCRegOp = Inst.getOperand(0); MCOperand MCValOp = Inst.getOperand(1); assert(MCRegOp.isReg()); assert(MCValOp.isImm() || MCValOp.isExpr()); // the imm operand can be either an expression or an immediate. bool IsImm = Inst.getOperand(1).isImm(); uint64_t ImmValue = IsImm ? MCValOp.getImm() : 0; const MCExpr *ValExpr; if (IsImm) ValExpr = MCConstantExpr::Create(ImmValue, getContext()); else ValExpr = MCValOp.getExpr(); MCOperand PrevReg = MCOperand::createReg(Sparc::G0); if (!IsImm || (ImmValue & ~0x1fff)) { MCInst TmpInst; const MCExpr *Expr = SparcMCExpr::Create(SparcMCExpr::VK_Sparc_HI, ValExpr, getContext()); TmpInst.setLoc(IDLoc); TmpInst.setOpcode(SP::SETHIi); TmpInst.addOperand(MCRegOp); TmpInst.addOperand(MCOperand::createExpr(Expr)); Instructions.push_back(TmpInst); PrevReg = MCRegOp; } if (!IsImm || ((ImmValue & 0x1fff) != 0 || ImmValue == 0)) { MCInst TmpInst; const MCExpr *Expr = SparcMCExpr::Create(SparcMCExpr::VK_Sparc_LO, ValExpr, getContext()); TmpInst.setLoc(IDLoc); TmpInst.setOpcode(SP::ORri); TmpInst.addOperand(MCRegOp); TmpInst.addOperand(PrevReg); TmpInst.addOperand(MCOperand::createExpr(Expr)); Instructions.push_back(TmpInst); } }
static InstTransResult doPEXTRWri(BasicBlock *&b, const MCOperand &dst, const MCOperand &src, const MCOperand &order) { NASSERT(dst.isReg()); NASSERT(src.isReg()); NASSERT(order.isImm()); Value *vec = R_READ<128>(b, src.getReg()); Value *item = doExtraction<128,16>(b, vec, order.getImm()); // upper bits are set to zero Value *extItem = new ZExtInst( item, Type::getInt32Ty(b->getContext()), "", b); R_WRITE<32>(b, dst.getReg(), extItem); return ContinueBlock; }
static InstTransResult doIMulRRI8(InstPtr ip, BasicBlock *&b, const MCOperand &dst, const MCOperand &lhs, const MCOperand &rhs) { NASSERT(dst.isReg()); NASSERT(lhs.isReg()); NASSERT(rhs.isImm()); Value *vRhs = CONST_V<8>(b, rhs.getImm()); Type *sx = Type::getIntNTy(b->getContext(), width); Value *vRhs_x = new SExtInst(vRhs, sx, "", b); Value *res = doIMulVVV<width>(ip, b, R_READ<width>(b, lhs.getReg()), vRhs_x); R_WRITE<width>(b, dst.getReg(), res); return ContinueBlock; }
static InstTransResult doSubRI(InstPtr ip, BasicBlock *&b, const MCOperand &dst, const MCOperand &src1, const MCOperand &src2) { NASSERT(src1.isReg()); NASSERT(src2.isImm()); NASSERT(dst.isReg()); // Read from src1. Value *srcReg = R_READ<width>(b, src1.getReg()); // Create the constant value. Value *c = CONST_V<width>(b, src2.getImm()); // Do the operation. Value *subRes = doSubVV<width>(ip, b, srcReg, c); // Store the result in dst. R_WRITE<width>(b, dst.getReg(), subRes); return ContinueBlock; }
static InstTransResult doRetI(BasicBlock *&b, const MCOperand &o) { TASSERT(o.isImm(), "Operand not immediate"); Value *c = CONST_V<32>(b, o.getImm()); Value *rESP = R_READ<32>(b, X86::ESP); Value *fromStack = M_READ_0<32>(b, rESP); TASSERT(fromStack != NULL, "Could not read value from stack"); //add the immediate to ESP Value *rESP_1 = BinaryOperator::CreateAdd(rESP, c, "", b); //add pointer width to ESP Value *nESP = BinaryOperator::CreateAdd(rESP_1, CONST_V<32>(b, 4), "", b); //write back to ESP R_WRITE<32>(b, X86::ESP, nESP); //spill all locals into the structure writeLocalsToContext(b, 32, ABIRetStore); ReturnInst::Create(b->getContext(), b); return EndCFG; }
NativeBlockPtr decodeBlock( ExecutableContainer *c, ExternalFunctionMap &f, LLVMByteDecoder &d, stack<VA> &blockChildren, VA e, stack<VA> &funcs, raw_ostream &out) { NativeBlockPtr B = NativeBlockPtr(new NativeBlock(e, d.getPrinter())); VA curAddr = e; bool has_follow = true; out << "Processing block: " << B->get_name() << "\n"; do { InstPtr I = d.getInstFromBuff(curAddr, c); //I, if a terminator, will have true and false targets //filled in. I could be an indirect branch of some kind, //we will deal with that here. we will also deal with the //instruction if it is a data instruction with relocation out << to_string<VA>(I->get_loc(), hex) << ":"; out << I->printInst() << "\n"; if(I->get_tr() != 0) { B->add_follow(I->get_tr()); has_follow = false; out << "Adding block: " << to_string<VA>(I->get_tr(), hex) << "\n"; blockChildren.push(I->get_tr()); } if(I->get_fa() != 0) { B->add_follow(I->get_fa()); has_follow = false; out << "Adding block: " << to_string<VA>(I->get_fa(), hex) << "\n"; blockChildren.push(I->get_fa()); } if(I->terminator()) { has_follow = false; } //do we need to add a data reference to this instruction? //again, because there is no offset information in the //instruction decoder, for now we just ask if every addr //in the inst is relocated for(uint32_t i = 0; i < I->get_len(); i++) { VA addrInInst = curAddr+i; if(c->is_addr_relocated(addrInInst)) { VA addr = 0; std::string has_imp; // this instruction has a relocation // save the relocation offset for later I->set_reloc_offset(i); //get the offset for this address //add it as a data offset to the instruction if (c->find_import_name(addrInInst, has_imp) ) { if(f.is_data(has_imp)) { ExternalDataRefPtr data_p = makeExtDataRefFromString(has_imp, f); out << "Adding external data ref: " << has_imp << "\n"; I->set_ext_data_ref(data_p); } else { ExternalCodeRefPtr code_p = makeExtCodeRefFromString(has_imp, f); LASSERT(code_p, "Failed to get ext call from map for symbol: "+has_imp); //maybe, this call doesn't return, in which case, //we should kill the decoding of this flow if(code_p->getReturnType() == ExternalCodeRef::NoReturn) { has_follow = false; } out << "Adding external code ref: " << has_imp << "\n"; I->set_ext_call_target(code_p); } } else if(c->relocate_addr(addrInInst, addr)) { bool can_ref_code = canInstructionReferenceCode(I); bool is_reloc_code = isAddrOfType(c, addr, ExecutableContainer::CodeSection); bool is_reloc_data = isAddrOfType(c, addr, ExecutableContainer::DataSection); unsigned opc = I->get_inst().getOpcode(); if(isBranchViaMemory(I)) { out << "Detect branch via memory, relocation handled later\n"; } // this instruction can reference code and does // reference code // so we assume the code points to a function else if( can_ref_code && is_reloc_code ) { list<VA> new_funcs; if(dataInCodeHeuristic(c, I, addr, new_funcs)) { // add new functions to our functions list for(list<VA>::const_iterator nfi = new_funcs.begin(); nfi != new_funcs.end(); nfi++) { funcs.push(*nfi); } I->set_data_offset(addr); } else { I->set_call_tgt(addr); out << "Adding: 0x" << to_string<VA>(addr, hex) << " as target\n"; funcs.push(addr); } } // this instruction can't reference code and points to .text // or references data. Treat as data element // TODO: extract this from .text and shove into .data? else if(( !can_ref_code && is_reloc_code) || is_reloc_data ) { I->set_data_offset(addr); } else { out << "WARNING: relocation points to neither code nor data:" << to_string<VA>(addr, hex) << "\n"; } } else { out << "*NOT* Relocating relocatable addr:" << to_string<uint32_t>(addrInInst, hex) << "\n"; } break; } } //is this instruction an external call? //in a COFF binary, the pcrel call can refer to an //external symbol that has been relocated //so, get the string that corresponds, and //provide the translation using the function map MCOperand op; string imp; switch(I->get_inst().getOpcode()) { case X86::JMP32m: { string thunkSym; bool r = c->find_import_name(curAddr+2, thunkSym); if(r) { // this goes to an external API call out << "Adding external code ref via JMP: " << thunkSym << "\n"; ExternalCodeRefPtr p = makeExtCodeRefFromString(thunkSym, f); I->set_ext_call_target(p); has_follow = false; } else { // this is an internal jmp. probably a jump table. bool did_jmptable = handlePossibleJumpTable(c, B, I, curAddr, funcs, blockChildren, out); LASSERT(did_jmptable, "JMP32m processing aborted: couldn't parse jumptable"); } } break; case X86::CALLpcrel32: //this could be an external call in COFF, or not op = I->get_inst().getOperand(0); LASSERT(op.isImm(), "Nonsense for CALLpcrel32"); if(op.getImm() !=0) { VA callTgt = curAddr+op.getImm()+I->get_len(); bool foldFunc = false; //speculate about callTgt InstPtr spec = d.getInstFromBuff(callTgt, c); if(spec->terminator() && spec->get_inst().getOpcode() == X86::JMP32m) { string thunkSym; bool r = c->find_import_name(callTgt+2, thunkSym); LASSERT(r, "Need to find thunk import addr"); ExternalCodeRefPtr p = makeExtCodeRefFromString(thunkSym, f); I->set_ext_call_target(p); foldFunc = true; if(p->getReturnType() == ExternalCodeRef::NoReturn) { has_follow = false; } } if(foldFunc == false) { //add this to our list of funcs to search funcs.push(callTgt); } } else { //check to see if this is an external call... if(I->has_ext_call_target() == false) { // may be a local call VA addr=curAddr+1, relo_addr=0; out << "Symbol not found, maybe a local call\n"; if(c->relocate_addr(addr, relo_addr)){ out << "Found local call to: " << to_string<VA>(relo_addr, hex) << "\n"; I->set_call_tgt(relo_addr); out << "Adding: 0x" << to_string<VA>(relo_addr, hex) << " as target\n"; funcs.push(relo_addr); } else { out << "Could not relocate addr for local call at: "; out << to_string<VA>(curAddr, hex) << "\n"; } } else { out << "External call to: " << I->get_ext_call_target()->getSymbolName() << "\n"; } } break; case X86::CALL32m: //this should be a call to an external, or we have no idea //so we need to try and look up the symbol that we're calling at this address... if(c->find_import_name(curAddr+2, imp)) { ExternalCodeRefPtr p = makeExtCodeRefFromString(imp, f); LASSERT(p, "Failed to get ext call from map for symbol"+imp); out << "Calling symbol: " << p->getSymbolName() << "\n"; if(p->getReturnType() == ExternalCodeRef::NoReturn) { has_follow = false; } I->set_ext_call_target(p); } else { out << "Cannot find symbol at address "; out << to_string<VA>(curAddr, hex) << "\n"; } break; } B->add_inst(I); curAddr += I->get_len(); } while(has_follow); //we have built a basic block, it might contain //multiple calls, but it only has one terminator //which is either a ret or a branch return B; }