|
|
|
@@ -28,40 +28,12 @@ |
|
|
|
#include <stddef.h> |
|
|
|
|
|
|
|
#include <llvm-c/Core.h> |
|
|
|
#include <llvm/Target/TargetMachine.h> |
|
|
|
#include <llvm/Target/TargetInstrInfo.h> |
|
|
|
#include <llvm-c/Disassembler.h> |
|
|
|
#include <llvm/Support/raw_ostream.h> |
|
|
|
#include <llvm/Support/Format.h> |
|
|
|
|
|
|
|
#if HAVE_LLVM >= 0x0306 |
|
|
|
#include <llvm/Target/TargetSubtargetInfo.h> |
|
|
|
#else |
|
|
|
#include <llvm/Support/MemoryObject.h> |
|
|
|
#endif |
|
|
|
|
|
|
|
#include <llvm/Support/TargetRegistry.h> |
|
|
|
#include <llvm/MC/MCSubtargetInfo.h> |
|
|
|
|
|
|
|
#include <llvm/Support/Host.h> |
|
|
|
|
|
|
|
#include <llvm/IR/Module.h> |
|
|
|
|
|
|
|
#include <llvm/MC/MCDisassembler.h> |
|
|
|
#include <llvm/MC/MCAsmInfo.h> |
|
|
|
#include <llvm/MC/MCInst.h> |
|
|
|
#include <llvm/MC/MCInstPrinter.h> |
|
|
|
#include <llvm/MC/MCRegisterInfo.h> |
|
|
|
|
|
|
|
#if HAVE_LLVM >= 0x0305 |
|
|
|
#define OwningPtr std::unique_ptr |
|
|
|
#else |
|
|
|
#include <llvm/ADT/OwningPtr.h> |
|
|
|
#endif |
|
|
|
|
|
|
|
#if HAVE_LLVM >= 0x0305 |
|
|
|
#include <llvm/MC/MCContext.h> |
|
|
|
#endif |
|
|
|
|
|
|
|
#include "util/u_math.h" |
|
|
|
#include "util/u_debug.h" |
|
|
|
|
|
|
|
@@ -133,7 +105,7 @@ lp_get_module_id(LLVMModuleRef module) |
|
|
|
extern "C" void |
|
|
|
lp_debug_dump_value(LLVMValueRef value) |
|
|
|
{ |
|
|
|
#if (defined(PIPE_OS_WINDOWS) && !defined(PIPE_CC_MSVC)) || defined(PIPE_OS_EMBDDED) |
|
|
|
#if (defined(PIPE_OS_WINDOWS) && !defined(PIPE_CC_MSVC)) || defined(PIPE_OS_EMBEDDED) |
|
|
|
raw_debug_ostream os; |
|
|
|
llvm::unwrap(value)->print(os); |
|
|
|
os.flush(); |
|
|
|
@@ -143,44 +115,16 @@ lp_debug_dump_value(LLVMValueRef value) |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#if HAVE_LLVM < 0x0306 |
|
|
|
|
|
|
|
/* |
|
|
|
* MemoryObject wrapper around a buffer of memory, to be used by MC |
|
|
|
* disassembler. |
|
|
|
*/ |
|
|
|
class BufferMemoryObject: |
|
|
|
public llvm::MemoryObject |
|
|
|
static const char * |
|
|
|
disassemblerSymbolLookupCB(void *DisInfo, |
|
|
|
uint64_t ReferenceValue, |
|
|
|
uint64_t *ReferenceType, |
|
|
|
uint64_t ReferencePC, |
|
|
|
const char **ReferenceName) |
|
|
|
{ |
|
|
|
private: |
|
|
|
const uint8_t *Bytes; |
|
|
|
uint64_t Length; |
|
|
|
public: |
|
|
|
BufferMemoryObject(const uint8_t *bytes, uint64_t length) : |
|
|
|
Bytes(bytes), Length(length) |
|
|
|
{ |
|
|
|
} |
|
|
|
|
|
|
|
uint64_t getBase() const |
|
|
|
{ |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
uint64_t getExtent() const |
|
|
|
{ |
|
|
|
return Length; |
|
|
|
} |
|
|
|
|
|
|
|
int readByte(uint64_t addr, uint8_t *byte) const |
|
|
|
{ |
|
|
|
if (addr > getExtent()) |
|
|
|
return -1; |
|
|
|
*byte = Bytes[addr]; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
#endif /* HAVE_LLVM < 0x0306 */ |
|
|
|
// TODO: Maybe this can be used to guess jumps |
|
|
|
return NULL; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
/* |
|
|
|
@@ -193,8 +137,6 @@ public: |
|
|
|
static size_t |
|
|
|
disassemble(const void* func, llvm::raw_ostream & Out) |
|
|
|
{ |
|
|
|
using namespace llvm; |
|
|
|
|
|
|
|
const uint8_t *bytes = (const uint8_t *)func; |
|
|
|
|
|
|
|
/* |
|
|
|
@@ -202,101 +144,23 @@ disassemble(const void* func, llvm::raw_ostream & Out) |
|
|
|
*/ |
|
|
|
const uint64_t extent = 96 * 1024; |
|
|
|
|
|
|
|
uint64_t max_pc = 0; |
|
|
|
|
|
|
|
/* |
|
|
|
* Initialize all used objects. |
|
|
|
*/ |
|
|
|
|
|
|
|
std::string Triple = sys::getDefaultTargetTriple(); |
|
|
|
|
|
|
|
std::string Error; |
|
|
|
const Target *T = TargetRegistry::lookupTarget(Triple, Error); |
|
|
|
|
|
|
|
#if HAVE_LLVM >= 0x0304 |
|
|
|
OwningPtr<const MCAsmInfo> AsmInfo(T->createMCAsmInfo(*T->createMCRegInfo(Triple), Triple)); |
|
|
|
#else |
|
|
|
OwningPtr<const MCAsmInfo> AsmInfo(T->createMCAsmInfo(Triple)); |
|
|
|
#endif |
|
|
|
|
|
|
|
if (!AsmInfo) { |
|
|
|
Out << "error: no assembly info for target " << Triple << "\n"; |
|
|
|
Out.flush(); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
unsigned int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); |
|
|
|
|
|
|
|
OwningPtr<const MCRegisterInfo> MRI(T->createMCRegInfo(Triple)); |
|
|
|
if (!MRI) { |
|
|
|
Out << "error: no register info for target " << Triple.c_str() << "\n"; |
|
|
|
Out.flush(); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
OwningPtr<const MCInstrInfo> MII(T->createMCInstrInfo()); |
|
|
|
if (!MII) { |
|
|
|
Out << "error: no instruction info for target " << Triple.c_str() << "\n"; |
|
|
|
Out.flush(); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
std::string Triple = llvm::sys::getProcessTriple(); |
|
|
|
LLVMDisasmContextRef D = LLVMCreateDisasm(Triple.c_str(), NULL, 0, NULL, &disassemblerSymbolLookupCB); |
|
|
|
char outline[1024]; |
|
|
|
|
|
|
|
#if HAVE_LLVM >= 0x0305 |
|
|
|
OwningPtr<const MCSubtargetInfo> STI(T->createMCSubtargetInfo(Triple, sys::getHostCPUName(), "")); |
|
|
|
OwningPtr<MCContext> MCCtx(new MCContext(AsmInfo.get(), MRI.get(), 0)); |
|
|
|
OwningPtr<const MCDisassembler> DisAsm(T->createMCDisassembler(*STI, *MCCtx)); |
|
|
|
#else |
|
|
|
OwningPtr<const MCSubtargetInfo> STI(T->createMCSubtargetInfo(Triple, sys::getHostCPUName(), "")); |
|
|
|
OwningPtr<const MCDisassembler> DisAsm(T->createMCDisassembler(*STI)); |
|
|
|
#endif |
|
|
|
if (!DisAsm) { |
|
|
|
Out << "error: no disassembler for target " << Triple << "\n"; |
|
|
|
Out.flush(); |
|
|
|
if (!D) { |
|
|
|
Out << "error: couldn't create disassembler for triple " << Triple << "\n"; |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
|
|
|
|
#if HAVE_LLVM >= 0x0307 |
|
|
|
OwningPtr<MCInstPrinter> Printer( |
|
|
|
T->createMCInstPrinter(llvm::Triple(Triple), AsmPrinterVariant, *AsmInfo, *MII, *MRI)); |
|
|
|
#else |
|
|
|
OwningPtr<MCInstPrinter> Printer( |
|
|
|
T->createMCInstPrinter(AsmPrinterVariant, *AsmInfo, *MII, *MRI, *STI)); |
|
|
|
#endif |
|
|
|
if (!Printer) { |
|
|
|
Out << "error: no instruction printer for target " << Triple.c_str() << "\n"; |
|
|
|
Out.flush(); |
|
|
|
return 0; |
|
|
|
} |
|
|
|
|
|
|
|
TargetOptions options; |
|
|
|
#if defined(DEBUG) && HAVE_LLVM < 0x0307 |
|
|
|
options.JITEmitDebugInfo = true; |
|
|
|
#endif |
|
|
|
#if defined(PIPE_ARCH_X86) |
|
|
|
options.StackAlignmentOverride = 4; |
|
|
|
#endif |
|
|
|
#if defined(DEBUG) || defined(PROFILE) |
|
|
|
#if HAVE_LLVM < 0x0307 |
|
|
|
options.NoFramePointerElim = true; |
|
|
|
#endif |
|
|
|
#endif |
|
|
|
OwningPtr<TargetMachine> TM(T->createTargetMachine(Triple, sys::getHostCPUName(), "", options)); |
|
|
|
|
|
|
|
/* |
|
|
|
* Wrap the data in a MemoryObject |
|
|
|
*/ |
|
|
|
#if HAVE_LLVM >= 0x0306 |
|
|
|
ArrayRef<uint8_t> memoryObject((const uint8_t *)bytes, extent); |
|
|
|
#else |
|
|
|
BufferMemoryObject memoryObject((const uint8_t *)bytes, extent); |
|
|
|
#endif |
|
|
|
|
|
|
|
uint64_t pc; |
|
|
|
pc = 0; |
|
|
|
while (true) { |
|
|
|
MCInst Inst; |
|
|
|
uint64_t Size; |
|
|
|
while (pc < extent) { |
|
|
|
size_t Size; |
|
|
|
|
|
|
|
/* |
|
|
|
* Print address. We use addresses relative to the start of the function, |
|
|
|
@@ -305,11 +169,13 @@ disassemble(const void* func, llvm::raw_ostream & Out) |
|
|
|
|
|
|
|
Out << llvm::format("%6lu:\t", (unsigned long)pc); |
|
|
|
|
|
|
|
if (!DisAsm->getInstruction(Inst, Size, memoryObject, |
|
|
|
pc, |
|
|
|
nulls(), nulls())) { |
|
|
|
Out << "invalid"; |
|
|
|
Size = LLVMDisasmInstruction(D, (uint8_t *)bytes + pc, extent - pc, 0, outline, |
|
|
|
sizeof outline); |
|
|
|
|
|
|
|
if (!Size) { |
|
|
|
Out << "invalid\n"; |
|
|
|
pc += 1; |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
@@ -319,7 +185,7 @@ disassemble(const void* func, llvm::raw_ostream & Out) |
|
|
|
if (0) { |
|
|
|
unsigned i; |
|
|
|
for (i = 0; i < Size; ++i) { |
|
|
|
Out << llvm::format("%02x ", ((const uint8_t*)bytes)[pc + i]); |
|
|
|
Out << llvm::format("%02x ", bytes[pc + i]); |
|
|
|
} |
|
|
|
for (; i < 16; ++i) { |
|
|
|
Out << " "; |
|
|
|
@@ -329,81 +195,27 @@ disassemble(const void* func, llvm::raw_ostream & Out) |
|
|
|
/* |
|
|
|
* Print the instruction. |
|
|
|
*/ |
|
|
|
#if HAVE_LLVM >= 0x0307 |
|
|
|
Printer->printInst(&Inst, Out, "", *STI); |
|
|
|
#else |
|
|
|
Printer->printInst(&Inst, Out, ""); |
|
|
|
#endif |
|
|
|
|
|
|
|
/* |
|
|
|
* Advance. |
|
|
|
*/ |
|
|
|
Out << outline; |
|
|
|
|
|
|
|
pc += Size; |
|
|
|
|
|
|
|
const MCInstrDesc &TID = MII->get(Inst.getOpcode()); |
|
|
|
Out << "\n"; |
|
|
|
|
|
|
|
/* |
|
|
|
* Keep track of forward jumps to a nearby address. |
|
|
|
* Stop disassembling on return statements, if there is no record of a |
|
|
|
* jump to a successive address. |
|
|
|
* |
|
|
|
* XXX: This currently assumes x86 |
|
|
|
*/ |
|
|
|
|
|
|
|
if (TID.isBranch()) { |
|
|
|
for (unsigned i = 0; i < Inst.getNumOperands(); ++i) { |
|
|
|
const MCOperand &operand = Inst.getOperand(i); |
|
|
|
if (operand.isImm()) { |
|
|
|
uint64_t jump; |
|
|
|
|
|
|
|
/* |
|
|
|
* FIXME: Handle both relative and absolute addresses correctly. |
|
|
|
* EDInstInfo actually has this info, but operandTypes and |
|
|
|
* operandFlags enums are not exposed in the public interface. |
|
|
|
*/ |
|
|
|
|
|
|
|
if (1) { |
|
|
|
/* |
|
|
|
* PC relative addr. |
|
|
|
*/ |
|
|
|
|
|
|
|
jump = pc + operand.getImm(); |
|
|
|
} else { |
|
|
|
/* |
|
|
|
* Absolute addr. |
|
|
|
*/ |
|
|
|
|
|
|
|
jump = (uint64_t)operand.getImm(); |
|
|
|
} |
|
|
|
|
|
|
|
/* |
|
|
|
* Output the address relative to the function start, given |
|
|
|
* that MC will print the addresses relative the current pc. |
|
|
|
*/ |
|
|
|
Out << "\t\t; " << jump; |
|
|
|
|
|
|
|
/* |
|
|
|
* Ignore far jumps given it could be actually a tail return to |
|
|
|
* a random address. |
|
|
|
*/ |
|
|
|
|
|
|
|
if (jump > max_pc && |
|
|
|
jump < extent) { |
|
|
|
max_pc = jump; |
|
|
|
} |
|
|
|
} |
|
|
|
} |
|
|
|
if (Size == 1 && bytes[pc] == 0xc3) { |
|
|
|
break; |
|
|
|
} |
|
|
|
|
|
|
|
Out << "\n"; |
|
|
|
|
|
|
|
/* |
|
|
|
* Stop disassembling on return statements, if there is no record of a |
|
|
|
* jump to a successive address. |
|
|
|
* Advance. |
|
|
|
*/ |
|
|
|
|
|
|
|
if (TID.isReturn()) { |
|
|
|
if (pc > max_pc) { |
|
|
|
break; |
|
|
|
} |
|
|
|
} |
|
|
|
pc += Size; |
|
|
|
|
|
|
|
if (pc >= extent) { |
|
|
|
Out << "disassembly larger than " << extent << "bytes, aborting\n"; |
|
|
|
@@ -414,6 +226,8 @@ disassemble(const void* func, llvm::raw_ostream & Out) |
|
|
|
Out << "\n"; |
|
|
|
Out.flush(); |
|
|
|
|
|
|
|
LLVMDisasmDispose(D); |
|
|
|
|
|
|
|
/* |
|
|
|
* Print GDB command, useful to verify output. |
|
|
|
*/ |