//===------------- Disassembler for in-memory function --------------------===// // // Modified for use in The Julia Language from code in the llvm-mc project: // llvm-mc.cpp and Disassembler.cpp // // Original copyright: // // The LLVM Compiler Infrastructure // // This file is distributed under the University of Illinois Open Source // License. See LICENSE.TXT for details. // //===----------------------------------------------------------------------===// // // This class implements a disassembler of a memory block, given a function // pointer and size. // //===----------------------------------------------------------------------===// #include #include #include #include #include #include #include #include #include "llvm-version.h" #include #if JL_LLVM_VERSION >= 50000 #include #include #else #include #include #endif #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "llvm/Support/TargetSelect.h" #include #include "llvm/Support/FormattedStream.h" #include #include #include #include "llvm/DebugInfo/DWARF/DWARFContext.h" #include #include #include #include #include "llvm/IR/AssemblyAnnotationWriter.h" #include "julia.h" #include "julia_internal.h" #include "processor.h" using namespace llvm; #include "debuginfo.h" #include "julia_assert.h" // helper class for tracking inlining context while printing debug info class DILineInfoPrinter { std::vector context; char LineStart; bool bracket_outer; public: DILineInfoPrinter(char LineStart, bool bracket_outer) : LineStart(LineStart), bracket_outer(bracket_outer) {}; void emit_finish(raw_ostream &Out); void emit_lineinfo(raw_ostream &Out, std::vector &DI); template void emit_lineinfo(std::string &Out, T &DI) { raw_string_ostream OS(Out); emit_lineinfo(OS, DI); } void emit_lineinfo(raw_ostream &Out, DILineInfo &DI) { std::vector DIvec(1); DIvec[0] = DI; emit_lineinfo(Out, DIvec); } void emit_lineinfo(raw_ostream &Out, DIInliningInfo &DI) { uint32_t nframes = DI.getNumberOfFrames(); std::vector DIvec(nframes); for (uint32_t i = 0; i < DI.getNumberOfFrames(); i++) { DIvec[i] = DI.getFrame(i); } emit_lineinfo(Out, DIvec); } void emit_finish(std::string &Out) { raw_string_ostream OS(Out); emit_finish(OS); } }; void DILineInfoPrinter::emit_finish(raw_ostream &Out) { uint32_t npops = context.size(); if (!bracket_outer && npops > 0) npops--; if (npops) { Out << LineStart; while (npops--) Out << '}'; Out << '\n'; } context.clear(); } void DILineInfoPrinter::emit_lineinfo(raw_ostream &Out, std::vector &DI) { bool update_line_only = false; uint32_t nctx = context.size(); uint32_t nframes = DI.size(); if (nframes == 0) return; // just skip over lines with no debug info at all if (nctx > nframes) context.resize(nframes); for (uint32_t i = 0; i < nctx && i < nframes; i++) { const DILineInfo &CtxLine = context.at(i); const DILineInfo &FrameLine = DI.at(nframes - 1 - i); if (CtxLine != FrameLine) { if (CtxLine.FileName == FrameLine.FileName && CtxLine.FunctionName == FrameLine.FunctionName) { update_line_only = true; } context.resize(i); break; } } uint32_t npops = nctx - context.size() - update_line_only; if (npops) { Out << LineStart; while (npops--) Out << '}'; Out << '\n'; } if (update_line_only) { DILineInfo frame = DI.at(nframes - 1 - context.size()); if (frame.Line != UINT_MAX && frame.Line != 0) Out << LineStart << " Location: " << frame.FileName << ":" << frame.Line << '\n'; context.push_back(frame); } for (uint32_t i = context.size(); i < nframes; i++) { DILineInfo frame = DI.at(nframes - 1 - i); context.push_back(frame); Out << LineStart << " Function " << frame.FunctionName; if (bracket_outer || i != 0) Out << " {"; Out << "\n" << LineStart << " Location: " << frame.FileName; if (frame.Line != UINT_MAX && frame.Line != 0) Out << ":" << frame.Line; Out << "\n"; } } // adaptor class for printing line numbers before llvm IR lines class LineNumberAnnotatedWriter : public AssemblyAnnotationWriter { DILocation *InstrLoc = nullptr; DILineInfoPrinter LinePrinter{';', false}; DenseMap DebugLoc; DenseMap Subprogram; public: LineNumberAnnotatedWriter() {} virtual void emitFunctionAnnot(const Function *, formatted_raw_ostream &); virtual void emitInstructionAnnot(const Instruction *, formatted_raw_ostream &); virtual void emitBasicBlockEndAnnot(const BasicBlock *, formatted_raw_ostream &); // virtual void printInfoComment(const Value &, formatted_raw_ostream &) {} void addSubprogram(const Function *F, DISubprogram *SP) { Subprogram[F] = SP; } void addDebugLoc(const Instruction *I, DILocation *Loc) { DebugLoc[I] = Loc; } }; void LineNumberAnnotatedWriter::emitFunctionAnnot( const Function *F, formatted_raw_ostream &Out) { InstrLoc = nullptr; DISubprogram *FuncLoc = F->getSubprogram(); if (!FuncLoc) { auto SP = Subprogram.find(F); if (SP != Subprogram.end()) FuncLoc = SP->second; } if (!FuncLoc) return; std::vector DIvec(1); DILineInfo &DI = DIvec.back(); DI.FunctionName = FuncLoc->getName(); DI.FileName = FuncLoc->getFilename(); DI.Line = FuncLoc->getLine(); LinePrinter.emit_lineinfo(Out, DIvec); } void LineNumberAnnotatedWriter::emitInstructionAnnot( const Instruction *I, formatted_raw_ostream &Out) { DILocation *NewInstrLoc = I->getDebugLoc(); if (!NewInstrLoc) { auto Loc = DebugLoc.find(I); if (Loc != DebugLoc.end()) NewInstrLoc = Loc->second; } if (!NewInstrLoc || NewInstrLoc == InstrLoc) return; InstrLoc = NewInstrLoc; std::vector DIvec; do { DIvec.emplace_back(); DILineInfo &DI = DIvec.back(); DIScope *scope = NewInstrLoc->getScope(); if (scope) DI.FunctionName = scope->getName(); DI.FileName = NewInstrLoc->getFilename(); DI.Line = NewInstrLoc->getLine(); NewInstrLoc = NewInstrLoc->getInlinedAt(); } while (NewInstrLoc); LinePrinter.emit_lineinfo(Out, DIvec); } void LineNumberAnnotatedWriter::emitBasicBlockEndAnnot( const BasicBlock *BB, formatted_raw_ostream &Out) { if (BB == &BB->getParent()->back()) LinePrinter.emit_finish(Out); } // print an llvm IR acquired from jl_get_llvmf // warning: this takes ownership of, and destroys, f->getParent() extern "C" JL_DLLEXPORT jl_value_t *jl_dump_function_ir(void *f, bool strip_ir_metadata, bool dump_module) { std::string code; llvm::raw_string_ostream stream(code); Function *llvmf = dyn_cast_or_null((Function*)f); if (!llvmf || (!llvmf->isDeclaration() && !llvmf->getParent())) jl_error("jl_dump_function_ir: Expected Function* in a temporary Module"); JL_LOCK(&codegen_lock); // Might GC LineNumberAnnotatedWriter AAW; if (!llvmf->getParent()) { // print the function declaration as-is llvmf->print(stream, &AAW); delete llvmf; } else { Module *m = llvmf->getParent(); if (strip_ir_metadata) { // strip metadata from all instructions in all functions in the module Instruction *deletelast = nullptr; // can't actually delete until the iterator advances for (Function &f2 : m->functions()) { AAW.addSubprogram(&f2, f2.getSubprogram()); for (BasicBlock &f2_bb : f2) { for (Instruction &inst : f2_bb) { if (deletelast) { deletelast->eraseFromParent(); deletelast = nullptr; } // remove dbg.declare and dbg.value calls if (isa(inst) || isa(inst)) { deletelast = &inst; continue; } // iterate over all metadata kinds and set to NULL to remove SmallVector, 4> MDForInst; inst.getAllMetadataOtherThanDebugLoc(MDForInst); for (const auto &md_iter : MDForInst) { inst.setMetadata(md_iter.first, NULL); } // record debug location before erasing it AAW.addDebugLoc(&inst, inst.getDebugLoc()); inst.setDebugLoc(DebugLoc()); } if (deletelast) { deletelast->eraseFromParent(); deletelast = nullptr; } } } for (GlobalObject &g2 : m->global_objects()) { g2.clearMetadata(); } } if (dump_module) { m->print(stream, &AAW); } else { llvmf->print(stream, &AAW); } delete m; } JL_UNLOCK(&codegen_lock); // Might GC return jl_pchar_to_string(stream.str().data(), stream.str().size()); } static void jl_dump_asm_internal( uintptr_t Fptr, size_t Fsize, int64_t slide, const object::ObjectFile *object, DIContext *di_ctx, raw_ostream &rstream, const char* asm_variant); // This isn't particularly fast, but neither is printing assembly, and they're only used for interactive mode static uint64_t compute_obj_symsize(const object::ObjectFile *obj, uint64_t offset) { // Scan the object file for the closest symbols above and below offset in the .text section uint64_t lo = 0; uint64_t hi = 0; bool setlo = false; for (const object::SectionRef &Section : obj->sections()) { uint64_t SAddr, SSize; if (!Section.isText()) continue; SAddr = Section.getAddress(); SSize = Section.getSize(); if (offset < SAddr || offset >= SAddr + SSize) continue; assert(hi == 0); // test for lower and upper symbol bounds relative to other symbols hi = SAddr + SSize; object::section_iterator ESection = obj->section_end(); for (const object::SymbolRef &Sym : obj->symbols()) { uint64_t Addr; object::section_iterator Sect = ESection; auto SectOrError = Sym.getSection(); assert(SectOrError); Sect = SectOrError.get(); if (Sect == ESection) continue; if (Sect != Section) continue; auto AddrOrError = Sym.getAddress(); assert(AddrOrError); Addr = AddrOrError.get(); if (Addr <= offset && Addr >= lo) { // test for lower bound on symbol lo = Addr; setlo = true; } if (Addr > offset && Addr < hi) { // test for upper bound on symbol hi = Addr; } } } if (setlo) return hi - lo; return 0; } // print a native disassembly for the function starting at fptr extern "C" JL_DLLEXPORT jl_value_t *jl_dump_fptr_asm(uint64_t fptr, int raw_mc, const char* asm_variant) { assert(fptr != 0); jl_ptls_t ptls = jl_get_ptls_states(); std::string code; llvm::raw_string_ostream stream(code); // Find debug info (line numbers) to print alongside uint64_t symsize = 0; int64_t slide = 0, section_slide = 0; llvm::DIContext *context = NULL; const object::ObjectFile *object = NULL; if (!jl_DI_for_fptr(fptr, &symsize, &slide, §ion_slide, &object, &context)) { if (!jl_dylib_DI_for_fptr(fptr, &object, &context, &slide, §ion_slide, false, NULL, NULL, NULL, NULL)) { jl_printf(JL_STDERR, "WARNING: Unable to find function pointer\n"); return jl_pchar_to_string("", 0); } } if (symsize == 0 && object != NULL) symsize = compute_obj_symsize(object, fptr + slide + section_slide); if (symsize == 0) { jl_printf(JL_STDERR, "WARNING: Could not determine size of symbol\n"); return jl_pchar_to_string("", 0); } if (raw_mc) { return (jl_value_t*)jl_pchar_to_array((char*)fptr, symsize); } // Dump assembly code int8_t gc_state = jl_gc_safe_enter(ptls); jl_dump_asm_internal( fptr, symsize, slide, object, context, stream, asm_variant); jl_gc_safe_leave(ptls, gc_state); return jl_pchar_to_string(stream.str().data(), stream.str().size()); } namespace { #define FuncMCView ArrayRef // Look up a symbol, and return a const char* to its name when the // address matches. We currently just use "L
" as name for the // symbol. We could easily get more fancy, e.g. numbering symbols // sequentially or encoding the line number, but that doesn't seem // necessary. class SymbolTable { typedef std::map TableType; TableType Table; MCContext& Ctx; const FuncMCView &MemObj; int Pass; const object::ObjectFile *object; uint64_t ip; // virtual instruction pointer of the current instruction int64_t slide; public: SymbolTable(MCContext &Ctx, const object::ObjectFile *object, int64_t slide, const FuncMCView &MemObj): Ctx(Ctx), MemObj(MemObj), object(object), ip(0), slide(slide) {} const FuncMCView &getMemoryObject() const { return MemObj; } void setPass(int Pass) { this->Pass = Pass; } int getPass() const { return Pass; } void insertAddress(uint64_t addr); // void createSymbol(const char *name, uint64_t addr); void createSymbols(); const char *lookupSymbolName(uint64_t addr); MCSymbol *lookupSymbol(uint64_t addr); StringRef getSymbolNameAt(uint64_t offset) const; const char *lookupLocalPC(size_t addr); void setIP(uint64_t addr); uint64_t getIP() const; }; void SymbolTable::setIP(uint64_t addr) { ip = addr; } uint64_t SymbolTable::getIP() const { return ip; } const char *SymbolTable::lookupLocalPC(size_t addr) { jl_frame_t *frame = NULL; jl_getFunctionInfo(&frame, addr, /*skipC*/0, /*noInline*/1/* the entry pointer shouldn't have inlining */); char *name = frame->func_name; // TODO: free me free(frame->file_name); free(frame); return name; } StringRef SymbolTable::getSymbolNameAt(uint64_t offset) const { if (object == NULL) return StringRef(); object::section_iterator ESection = object->section_end(); for (const object::SymbolRef &Sym : object->symbols()) { uint64_t Addr, SAddr; object::section_iterator Sect = ESection; auto SectOrError = Sym.getSection(); assert(SectOrError); Sect = SectOrError.get(); if (Sect == ESection) continue; SAddr = Sect->getAddress(); if (SAddr == 0) continue; auto AddrOrError = Sym.getAddress(); assert(AddrOrError); Addr = AddrOrError.get(); if (Addr == offset) { auto sNameOrError = Sym.getName(); if (sNameOrError) return sNameOrError.get(); } } return StringRef(); } // Insert an address void SymbolTable::insertAddress(uint64_t addr) { Table[addr] = ""; } // Create symbols for all addresses void SymbolTable::createSymbols() { uintptr_t Fptr = (uintptr_t)MemObj.data(); uintptr_t Fsize = MemObj.size(); for (TableType::iterator isymb = Table.begin(), esymb = Table.end(); isymb != esymb; ++isymb) { uintptr_t rel = isymb->first - ip; uintptr_t addr = isymb->first; if (Fptr <= addr && addr < Fptr + Fsize) { std::ostringstream name; name << "L" << rel; isymb->second = name.str(); } else { const char *global = lookupLocalPC(addr); if (global) isymb->second = global; } } } const char *SymbolTable::lookupSymbolName(uint64_t addr) { TableType::iterator Sym; bool insertion; std::tie(Sym, insertion) = Table.insert(std::make_pair(addr, std::string())); if (insertion) { // First time we've seen addr: try to look it up StringRef local_name = getSymbolNameAt(addr + slide); if (local_name.empty()) { const char *global = lookupLocalPC(addr); if (global) { //std::ostringstream name; //name << global << "@0x" << std::hex // << std::setfill('0') << std::setw(2 * sizeof(void*)) // << addr; //Sym->second = name.str(); Sym->second = global; } } else { Sym->second = local_name; } } return Sym->second.empty() ? NULL : Sym->second.c_str(); } MCSymbol *SymbolTable::lookupSymbol(uint64_t addr) { TableType::iterator Sym = Table.find(addr); if (Sym == Table.end() || Sym->second.empty()) return NULL; MCSymbol *symb = Ctx.getOrCreateSymbol(Sym->second); assert(symb->isUndefined()); return symb; } static const char *SymbolLookup(void *DisInfo, uint64_t ReferenceValue, uint64_t *ReferenceType, uint64_t ReferencePC, const char **ReferenceName) { uint64_t RTypeIn = *ReferenceType; SymbolTable *SymTab = (SymbolTable*)DisInfo; *ReferenceType = LLVMDisassembler_ReferenceType_InOut_None; *ReferenceName = NULL; if (SymTab->getPass() != 0) { if (RTypeIn == LLVMDisassembler_ReferenceType_In_Branch) { uint64_t addr = ReferenceValue + SymTab->getIP(); // probably pc-rel const char *symbolName = SymTab->lookupSymbolName(addr); return symbolName; } else if (RTypeIn == LLVMDisassembler_ReferenceType_In_PCrel_Load) { uint64_t addr = ReferenceValue + SymTab->getIP(); const char *symbolName = SymTab->lookupSymbolName(addr); if (symbolName) { *ReferenceType = LLVMDisassembler_ReferenceType_Out_LitPool_SymAddr; *ReferenceName = symbolName; } } else if (RTypeIn == LLVMDisassembler_ReferenceType_InOut_None) { uint64_t addr = ReferenceValue; // probably not pc-rel const char *symbolName = SymTab->lookupSymbolName(addr); return symbolName; } } return NULL; } static int OpInfoLookup(void *DisInfo, uint64_t PC, uint64_t Offset, uint64_t Size, int TagType, void *TagBuf) { SymbolTable *SymTab = (SymbolTable*)DisInfo; LLVMOpInfo1 *info = (LLVMOpInfo1*)TagBuf; memset(info, 0, sizeof(*info)); if (TagType != 1) return 0; // Unknown data format PC += SymTab->getIP() - (uint64_t)(uintptr_t)SymTab->getMemoryObject().data(); // add offset from MemoryObject base // TODO: see if we knew of a relocation applied at PC // info->AddSymbol.Present = 1; // info->AddSymbol.Name = name; // info->AddSymbol.Value = pointer; // unused by LLVM // info->Value = 0; // offset // return 1; // Success return 0; } } // namespace static void jl_dump_asm_internal( uintptr_t Fptr, size_t Fsize, int64_t slide, const object::ObjectFile *object, DIContext *di_ctx, raw_ostream &rstream, const char* asm_variant) { // GC safe // Get the host information std::string TripleName = sys::getDefaultTargetTriple(); Triple TheTriple(Triple::normalize(TripleName)); const auto &target = jl_get_llvm_disasm_target(); const auto &cpu = target.first; const auto &features = target.second; std::string err; const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, err); // Set up required helpers and streamer std::unique_ptr Streamer; SourceMgr SrcMgr; std::unique_ptr MAI(TheTarget->createMCAsmInfo(*TheTarget->createMCRegInfo(TripleName),TripleName)); assert(MAI && "Unable to create target asm info!"); std::unique_ptr MRI(TheTarget->createMCRegInfo(TripleName)); assert(MRI && "Unable to create target register info!"); std::unique_ptr MOFI(new MCObjectFileInfo()); MCContext Ctx(MAI.get(), MRI.get(), MOFI.get(), &SrcMgr); #if JL_LLVM_VERSION >= 60000 MOFI->InitMCObjectFileInfo(TheTriple, /* PIC */ false, Ctx); #else MOFI->InitMCObjectFileInfo(TheTriple, /* PIC */ false, CodeModel::Default, Ctx); #endif // Set up Subtarget and Disassembler std::unique_ptr STI(TheTarget->createMCSubtargetInfo(TripleName, cpu, features)); std::unique_ptr DisAsm(TheTarget->createMCDisassembler(*STI, Ctx)); if (!DisAsm) { jl_printf(JL_STDERR, "ERROR: no disassembler for target %s\n", TripleName.c_str()); return; } unsigned OutputAsmVariant = 0; // ATT or Intel-style assembly if (strcmp(asm_variant, "intel")==0) { OutputAsmVariant = 1; } bool ShowEncoding = false; std::unique_ptr MCII(TheTarget->createMCInstrInfo()); std::unique_ptr MCIA(TheTarget->createMCInstrAnalysis(MCII.get())); MCInstPrinter *IP = TheTarget->createMCInstPrinter(TheTriple, OutputAsmVariant, *MAI, *MCII, *MRI); //IP->setPrintImmHex(true); // prefer hex or decimal immediates MCCodeEmitter *CE = 0; MCAsmBackend *MAB = 0; if (ShowEncoding) { CE = TheTarget->createMCCodeEmitter(*MCII, *MRI, Ctx); #if JL_LLVM_VERSION >= 60000 MCTargetOptions Options; MAB = TheTarget->createMCAsmBackend(*STI, *MRI, Options); #elif JL_LLVM_VERSION >= 40000 MCTargetOptions Options; MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, cpu, Options); #else MAB = TheTarget->createMCAsmBackend(*MRI, TripleName, cpu); #endif } // createAsmStreamer expects a unique_ptr to a formatted stream, which means // it will destruct the stream when it is done. We cannot have this, so we // start out with a raw stream, and create formatted stream from it here. // LLVM will desctruct the formatted stream, and we keep the raw stream. auto ustream = llvm::make_unique(rstream); Streamer.reset(TheTarget->createAsmStreamer(Ctx, std::move(ustream), /*asmverbose*/true, /*useDwarfDirectory*/ true, IP, CE, MAB, /*ShowInst*/ false)); Streamer->InitSections(true); // Make the MemoryObject wrapper ArrayRef memoryObject(const_cast((const uint8_t*)Fptr),Fsize); SymbolTable DisInfo(Ctx, object, slide, memoryObject); DILineInfoTable di_lineinfo; if (di_ctx) di_lineinfo = di_ctx->getLineInfoForAddressRange(Fptr+slide, Fsize); if (!di_lineinfo.empty()) { auto cur_addr = di_lineinfo[0].first; auto nlineinfo = di_lineinfo.size(); // filter out line infos that doesn't contain any instructions unsigned j = 0; for (unsigned i = 1; i < nlineinfo; i++) { auto &info = di_lineinfo[i]; if (info.first != cur_addr) j++; cur_addr = info.first; if (i != j) { di_lineinfo[j] = std::move(info); } } if (j + 1 < nlineinfo) { di_lineinfo.resize(j + 1); } } // Take two passes: In the first pass we record all branch labels, // in the second we actually perform the output for (int pass = 0; pass < 2; ++ pass) { DisInfo.setPass(pass); if (pass != 0) { // Switch to symbolic disassembly. We cannot do this // before the first pass, because this changes branch // targets from immediate values (constants) to // expressions, which are not handled correctly by // MCIA->evaluateBranch. (It should be possible to rewrite // this routine to handle this case correctly as well.) // Could add OpInfoLookup here DisAsm->setSymbolizer(std::unique_ptr(new MCExternalSymbolizer( Ctx, std::unique_ptr(new MCRelocationInfo(Ctx)), OpInfoLookup, SymbolLookup, &DisInfo))); } uint64_t nextLineAddr = -1; DILineInfoTable::iterator di_lineIter = di_lineinfo.begin(); DILineInfoTable::iterator di_lineEnd = di_lineinfo.end(); DILineInfoPrinter dbgctx{';', true}; if (pass != 0) { if (di_ctx && di_lineIter != di_lineEnd) { // Set up the line info nextLineAddr = di_lineIter->first; if (nextLineAddr != (uint64_t)(Fptr + slide)) { std::string buf; dbgctx.emit_lineinfo(buf, di_lineIter->second); if (!buf.empty()) { Streamer->EmitRawText(buf); } } } } uint64_t Index = 0; uint64_t insSize = 0; // Do the disassembly for (Index = 0; Index < Fsize; Index += insSize) { if (pass != 0 && nextLineAddr != (uint64_t)-1 && Index + Fptr + slide == nextLineAddr) { if (di_ctx) { std::string buf; DILineInfoSpecifier infoSpec(DILineInfoSpecifier::FileLineInfoKind::Default, DILineInfoSpecifier::FunctionNameKind::ShortName); DIInliningInfo dbg = di_ctx->getInliningInfoForAddress(Index + Fptr + slide, infoSpec); if (dbg.getNumberOfFrames()) { dbgctx.emit_lineinfo(buf, dbg); } else { dbgctx.emit_lineinfo(buf, di_lineIter->second); } if (!buf.empty()) Streamer->EmitRawText(buf); nextLineAddr = (++di_lineIter)->first; } } DisInfo.setIP(Fptr+Index); if (pass != 0) { // Uncomment this to output addresses for all instructions // stream << Index << ": "; MCSymbol *symbol = DisInfo.lookupSymbol(Fptr+Index); if (symbol) Streamer->EmitLabel(symbol); } MCInst Inst; MCDisassembler::DecodeStatus S; FuncMCView view = memoryObject.slice(Index); S = DisAsm->getInstruction(Inst, insSize, view, 0, /*VStream*/ nulls(), /*CStream*/ pass != 0 ? Streamer->GetCommentOS() : nulls()); if (pass != 0 && Streamer->GetCommentOS().tell() > 0) Streamer->GetCommentOS() << '\n'; switch (S) { case MCDisassembler::Fail: if (insSize == 0) // skip illegible bytes #if defined(_CPU_PPC_) || defined(_CPU_PPC64_) || defined(_CPU_ARM_) || defined(_CPU_AARCH64_) insSize = 4; // instructions are always 4 bytes #else insSize = 1; // attempt to slide 1 byte forward #endif if (pass != 0) { std::ostringstream buf; if (insSize == 4) buf << "\t.long\t0x" << std::hex << std::setfill('0') << std::setw(8) << *(uint32_t*)(Fptr+Index); else for (uint64_t i=0; iEmitRawText(StringRef(buf.str())); } break; case MCDisassembler::SoftFail: if (pass != 0) Streamer->EmitRawText(StringRef("potentially undefined instruction encoding:")); // Fall through case MCDisassembler::Success: if (pass == 0) { // Pass 0: Record all branch target references if (MCIA) { const MCInstrDesc &opcode = MCII->get(Inst.getOpcode()); if (opcode.isBranch() || opcode.isCall()) { uint64_t addr; if (MCIA->evaluateBranch(Inst, Fptr + Index, insSize, addr)) DisInfo.insertAddress(addr); } } } else { // Pass 1: Output instruction if (pass != 0) { // attempt to symbolicate any immediate operands const MCInstrDesc &opinfo = MCII->get(Inst.getOpcode()); for (unsigned Op = 0; Op < opinfo.NumOperands; Op++) { const MCOperand &OpI = Inst.getOperand(Op); if (OpI.isImm()) { int64_t imm = OpI.getImm(); if (opinfo.OpInfo[Op].OperandType == MCOI::OPERAND_PCREL) imm += Fptr + Index; const char *name = DisInfo.lookupSymbolName(imm); if (name) Streamer->AddComment(name); } } } Streamer->EmitInstruction(Inst, *STI); } break; } } DisInfo.setIP(Fptr); if (pass == 0) DisInfo.createSymbols(); if (pass != 0 && di_ctx) { std::string buf; dbgctx.emit_finish(buf); if (!buf.empty()) { Streamer->EmitRawText(buf); } } } } extern "C" JL_DLLEXPORT LLVMDisasmContextRef jl_LLVMCreateDisasm( const char *TripleName, void *DisInfo, int TagType, LLVMOpInfoCallback GetOpInfo, LLVMSymbolLookupCallback SymbolLookUp) { return LLVMCreateDisasm(TripleName, DisInfo, TagType, GetOpInfo, SymbolLookUp); } extern "C" JL_DLLEXPORT JL_DLLEXPORT size_t jl_LLVMDisasmInstruction( LLVMDisasmContextRef DC, uint8_t *Bytes, uint64_t BytesSize, uint64_t PC, char *OutString, size_t OutStringSize) { return LLVMDisasmInstruction(DC, Bytes, BytesSize, PC, OutString, OutStringSize); }