gallivm: Use the LLVM's C disassembly interface.

It doesn't do everything we want.  In particular it doesn't allow to
detect jumps or return opcodes.  Currently we detect the x86's RET
opcode.

Even though it's worse for LLVM 3.3, it's an improvement for LLVM 3.7,
which was totally busted.

Reviewed-by: Roland Scheidegger <sroland@vmware.com>
This commit is contained in:
Jose Fonseca
2015-05-28 16:55:10 +01:00
parent 29203e7738
commit 0db4ef9df1
2 changed files with 41 additions and 225 deletions

View File

@@ -120,6 +120,7 @@ def generate(env):
]) ])
elif llvm_version >= distutils.version.LooseVersion('3.5'): elif llvm_version >= distutils.version.LooseVersion('3.5'):
env.Prepend(LIBS = [ env.Prepend(LIBS = [
'LLVMMCDisassembler',
'LLVMBitWriter', 'LLVMMCJIT', 'LLVMRuntimeDyld', 'LLVMBitWriter', 'LLVMMCJIT', 'LLVMRuntimeDyld',
'LLVMX86Disassembler', 'LLVMX86AsmParser', 'LLVMX86CodeGen', 'LLVMX86Disassembler', 'LLVMX86AsmParser', 'LLVMX86CodeGen',
'LLVMSelectionDAG', 'LLVMAsmPrinter', 'LLVMX86Desc', 'LLVMSelectionDAG', 'LLVMAsmPrinter', 'LLVMX86Desc',
@@ -132,6 +133,7 @@ def generate(env):
]) ])
else: else:
env.Prepend(LIBS = [ env.Prepend(LIBS = [
'LLVMMCDisassembler',
'LLVMBitWriter', 'LLVMX86Disassembler', 'LLVMX86AsmParser', 'LLVMBitWriter', 'LLVMX86Disassembler', 'LLVMX86AsmParser',
'LLVMX86CodeGen', 'LLVMX86Desc', 'LLVMSelectionDAG', 'LLVMX86CodeGen', 'LLVMX86Desc', 'LLVMSelectionDAG',
'LLVMAsmPrinter', 'LLVMMCParser', 'LLVMX86AsmPrinter', 'LLVMAsmPrinter', 'LLVMMCParser', 'LLVMX86AsmPrinter',
@@ -189,7 +191,7 @@ def generate(env):
if '-fno-rtti' in cxxflags: if '-fno-rtti' in cxxflags:
env.Append(CXXFLAGS = ['-fno-rtti']) env.Append(CXXFLAGS = ['-fno-rtti'])
components = ['engine', 'mcjit', 'bitwriter', 'x86asmprinter'] components = ['engine', 'mcjit', 'bitwriter', 'x86asmprinter', 'mcdisassembler']
env.ParseConfig('llvm-config --libs ' + ' '.join(components)) env.ParseConfig('llvm-config --libs ' + ' '.join(components))
env.ParseConfig('llvm-config --ldflags') env.ParseConfig('llvm-config --ldflags')

View File

@@ -28,40 +28,12 @@
#include <stddef.h> #include <stddef.h>
#include <llvm-c/Core.h> #include <llvm-c/Core.h>
#include <llvm/Target/TargetMachine.h> #include <llvm-c/Disassembler.h>
#include <llvm/Target/TargetInstrInfo.h>
#include <llvm/Support/raw_ostream.h> #include <llvm/Support/raw_ostream.h>
#include <llvm/Support/Format.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/Support/Host.h>
#include <llvm/IR/Module.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_math.h"
#include "util/u_debug.h" #include "util/u_debug.h"
@@ -133,7 +105,7 @@ lp_get_module_id(LLVMModuleRef module)
extern "C" void extern "C" void
lp_debug_dump_value(LLVMValueRef value) 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; raw_debug_ostream os;
llvm::unwrap(value)->print(os); llvm::unwrap(value)->print(os);
os.flush(); os.flush();
@@ -143,44 +115,16 @@ lp_debug_dump_value(LLVMValueRef value)
} }
#if HAVE_LLVM < 0x0306 static const char *
disassemblerSymbolLookupCB(void *DisInfo,
/* uint64_t ReferenceValue,
* MemoryObject wrapper around a buffer of memory, to be used by MC uint64_t *ReferenceType,
* disassembler. uint64_t ReferencePC,
*/ const char **ReferenceName)
class BufferMemoryObject:
public llvm::MemoryObject
{ {
private: // TODO: Maybe this can be used to guess jumps
const uint8_t *Bytes; return NULL;
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 */
/* /*
@@ -193,8 +137,6 @@ public:
static size_t static size_t
disassemble(const void* func, llvm::raw_ostream & Out) disassemble(const void* func, llvm::raw_ostream & Out)
{ {
using namespace llvm;
const uint8_t *bytes = (const uint8_t *)func; 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; const uint64_t extent = 96 * 1024;
uint64_t max_pc = 0;
/* /*
* Initialize all used objects. * Initialize all used objects.
*/ */
std::string Triple = sys::getDefaultTargetTriple(); std::string Triple = llvm::sys::getProcessTriple();
LLVMDisasmContextRef D = LLVMCreateDisasm(Triple.c_str(), NULL, 0, NULL, &disassemblerSymbolLookupCB);
char outline[1024];
std::string Error; if (!D) {
const Target *T = TargetRegistry::lookupTarget(Triple, Error); Out << "error: couldn't create disassembler for triple " << Triple << "\n";
#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; 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;
}
#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();
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; uint64_t pc;
pc = 0; pc = 0;
while (true) { while (pc < extent) {
MCInst Inst; size_t Size;
uint64_t Size;
/* /*
* Print address. We use addresses relative to the start of the function, * 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); Out << llvm::format("%6lu:\t", (unsigned long)pc);
if (!DisAsm->getInstruction(Inst, Size, memoryObject, Size = LLVMDisasmInstruction(D, (uint8_t *)bytes + pc, extent - pc, 0, outline,
pc, sizeof outline);
nulls(), nulls())) {
Out << "invalid"; if (!Size) {
Out << "invalid\n";
pc += 1; pc += 1;
break;
} }
/* /*
@@ -319,7 +185,7 @@ disassemble(const void* func, llvm::raw_ostream & Out)
if (0) { if (0) {
unsigned i; unsigned i;
for (i = 0; i < Size; ++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) { for (; i < 16; ++i) {
Out << " "; Out << " ";
@@ -329,82 +195,28 @@ disassemble(const void* func, llvm::raw_ostream & Out)
/* /*
* Print the instruction. * Print the instruction.
*/ */
#if HAVE_LLVM >= 0x0307
Printer->printInst(&Inst, Out, "", *STI);
#else
Printer->printInst(&Inst, Out, "");
#endif
/* Out << outline;
* Advance.
*/
pc += Size;
const MCInstrDesc &TID = MII->get(Inst.getOpcode());
/*
* Keep track of forward jumps to a nearby address.
*/
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;
}
}
}
}
Out << "\n"; Out << "\n";
/* /*
* Stop disassembling on return statements, if there is no record of a * Stop disassembling on return statements, if there is no record of a
* jump to a successive address. * jump to a successive address.
*
* XXX: This currently assumes x86
*/ */
if (TID.isReturn()) { if (Size == 1 && bytes[pc] == 0xc3) {
if (pc > max_pc) { break;
break;
}
} }
/*
* Advance.
*/
pc += Size;
if (pc >= extent) { if (pc >= extent) {
Out << "disassembly larger than " << extent << "bytes, aborting\n"; Out << "disassembly larger than " << extent << "bytes, aborting\n";
break; break;
@@ -414,6 +226,8 @@ disassemble(const void* func, llvm::raw_ostream & Out)
Out << "\n"; Out << "\n";
Out.flush(); Out.flush();
LLVMDisasmDispose(D);
/* /*
* Print GDB command, useful to verify output. * Print GDB command, useful to verify output.
*/ */