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:
@@ -120,6 +120,7 @@ def generate(env):
|
||||
])
|
||||
elif llvm_version >= distutils.version.LooseVersion('3.5'):
|
||||
env.Prepend(LIBS = [
|
||||
'LLVMMCDisassembler',
|
||||
'LLVMBitWriter', 'LLVMMCJIT', 'LLVMRuntimeDyld',
|
||||
'LLVMX86Disassembler', 'LLVMX86AsmParser', 'LLVMX86CodeGen',
|
||||
'LLVMSelectionDAG', 'LLVMAsmPrinter', 'LLVMX86Desc',
|
||||
@@ -132,6 +133,7 @@ def generate(env):
|
||||
])
|
||||
else:
|
||||
env.Prepend(LIBS = [
|
||||
'LLVMMCDisassembler',
|
||||
'LLVMBitWriter', 'LLVMX86Disassembler', 'LLVMX86AsmParser',
|
||||
'LLVMX86CodeGen', 'LLVMX86Desc', 'LLVMSelectionDAG',
|
||||
'LLVMAsmPrinter', 'LLVMMCParser', 'LLVMX86AsmPrinter',
|
||||
@@ -189,7 +191,7 @@ def generate(env):
|
||||
if '-fno-rtti' in cxxflags:
|
||||
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 --ldflags')
|
||||
|
@@ -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 Triple = llvm::sys::getProcessTriple();
|
||||
LLVMDisasmContextRef D = LLVMCreateDisasm(Triple.c_str(), NULL, 0, NULL, &disassemblerSymbolLookupCB);
|
||||
char outline[1024];
|
||||
|
||||
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();
|
||||
if (!D) {
|
||||
Out << "error: couldn't create disassembler for triple " << Triple << "\n";
|
||||
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;
|
||||
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.
|
||||
*/
|
||||
|
||||
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 << outline;
|
||||
|
||||
Out << "\n";
|
||||
|
||||
/*
|
||||
* Stop disassembling on return statements, if there is no record of a
|
||||
* jump to a successive address.
|
||||
*
|
||||
* XXX: This currently assumes x86
|
||||
*/
|
||||
|
||||
if (TID.isReturn()) {
|
||||
if (pc > max_pc) {
|
||||
if (Size == 1 && bytes[pc] == 0xc3) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Advance.
|
||||
*/
|
||||
|
||||
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.
|
||||
*/
|
||||
|
Reference in New Issue
Block a user