diff options
author | José Fonseca <jfonseca@vmware.com> | 2011-03-13 19:24:26 +0000 |
---|---|---|
committer | José Fonseca <jfonseca@vmware.com> | 2011-03-13 19:24:26 +0000 |
commit | e6314db0ac537695a20feb5fab8d77a30836eccf (patch) | |
tree | 331b6776b739823a54a3d6ddde249d6881c95f7c /src/gallium/auxiliary/gallivm | |
parent | d2332569d2be9ace850b8d6b80abe4c597968773 (diff) | |
download | external_mesa3d-e6314db0ac537695a20feb5fab8d77a30836eccf.zip external_mesa3d-e6314db0ac537695a20feb5fab8d77a30836eccf.tar.gz external_mesa3d-e6314db0ac537695a20feb5fab8d77a30836eccf.tar.bz2 |
gallivm: Use LLVM MC disassembler, instead of udis86.
Included in LLVM 2.7+. Unlink udis86, should support all instructions that
LLVM can emit.
Diffstat (limited to 'src/gallium/auxiliary/gallivm')
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_debug.c | 141 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_debug.cpp | 355 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_debug.h | 10 | ||||
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_misc.cpp | 60 |
4 files changed, 365 insertions, 201 deletions
diff --git a/src/gallium/auxiliary/gallivm/lp_bld_debug.c b/src/gallium/auxiliary/gallivm/lp_bld_debug.c deleted file mode 100644 index 93e5655..0000000 --- a/src/gallium/auxiliary/gallivm/lp_bld_debug.c +++ /dev/null @@ -1,141 +0,0 @@ -/************************************************************************** - * - * Copyright 2009 VMware, Inc. - * All Rights Reserved. - * - * Permission is hereby granted, free of charge, to any person obtaining a - * copy of this software and associated documentation files (the - * "Software"), to deal in the Software without restriction, including - * without limitation the rights to use, copy, modify, merge, publish, - * distribute, sub license, and/or sell copies of the Software, and to - * permit persons to whom the Software is furnished to do so, subject to - * the following conditions: - * - * The above copyright notice and this permission notice (including the - * next paragraph) shall be included in all copies or substantial portions - * of the Software. - * - * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS - * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF - * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. - * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR - * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, - * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE - * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. - * - **************************************************************************/ - - -#ifdef HAVE_UDIS86 -#include <udis86.h> -#endif - -#include "util/u_math.h" -#include "util/u_debug.h" -#include "lp_bld_debug.h" - - -/** - * Check alignment. - * - * It is important that this check is not implemented as a macro or inlined - * function, as the compiler assumptions in respect to alignment of global - * and stack variables would often make the check a no op, defeating the - * whole purpose of the exercise. - */ -boolean -lp_check_alignment(const void *ptr, unsigned alignment) -{ - assert(util_is_power_of_two(alignment)); - return ((uintptr_t)ptr & (alignment - 1)) == 0; -} - - -void -lp_disassemble(const void* func) -{ -#ifdef HAVE_UDIS86 - ud_t ud_obj; - uint64_t max_jmp_pc; - uint inst_no; - boolean emit_addrs = TRUE, emit_line_nos = FALSE; - - ud_init(&ud_obj); - - ud_set_input_buffer(&ud_obj, (void*)func, 0xffff); - - max_jmp_pc = (uint64_t) (uintptr_t) func; - ud_set_pc(&ud_obj, max_jmp_pc); - -#ifdef PIPE_ARCH_X86 - ud_set_mode(&ud_obj, 32); -#endif -#ifdef PIPE_ARCH_X86_64 - ud_set_mode(&ud_obj, 64); -#endif - - ud_set_syntax(&ud_obj, UD_SYN_ATT); - - while (ud_disassemble(&ud_obj)) { - - if (emit_addrs) { -#ifdef PIPE_ARCH_X86 - debug_printf("0x%08lx:\t", (unsigned long)ud_insn_off(&ud_obj)); -#endif -#ifdef PIPE_ARCH_X86_64 - debug_printf("0x%016llx:\t", (unsigned long long)ud_insn_off(&ud_obj)); -#endif - } - else if (emit_line_nos) { - debug_printf("%6d:\t", inst_no); - inst_no++; - } -#if 0 - debug_printf("%-16s ", ud_insn_hex(&ud_obj)); -#endif - - debug_printf("%s\n", ud_insn_asm(&ud_obj)); - - if(ud_obj.mnemonic != UD_Icall) { - unsigned i; - for(i = 0; i < 3; ++i) { - const struct ud_operand *op = &ud_obj.operand[i]; - if (op->type == UD_OP_JIMM){ - uint64_t pc = ud_obj.pc; - - switch (op->size) { - case 8: - pc += op->lval.sbyte; - break; - case 16: - pc += op->lval.sword; - break; - case 32: - pc += op->lval.sdword; - break; - default: - break; - } - if(pc > max_jmp_pc) - max_jmp_pc = pc; - } - } - } - - if (ud_obj.mnemonic == UD_Iinvalid || - (ud_insn_off(&ud_obj) >= max_jmp_pc && - (ud_obj.mnemonic == UD_Iret || - ud_obj.mnemonic == UD_Ijmp))) - break; - } - -#if 0 - /* Print GDB command, useful to verify udis86 output */ - debug_printf("disassemble %p %p\n", func, (void*)(uintptr_t)ud_obj.pc); -#endif - - debug_printf("\n"); -#else - (void)func; -#endif -} diff --git a/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp b/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp new file mode 100644 index 0000000..49388aa --- /dev/null +++ b/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp @@ -0,0 +1,355 @@ +/************************************************************************** + * + * Copyright 2009-2011 VMware, Inc. + * All Rights Reserved. + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the + * "Software"), to deal in the Software without restriction, including + * without limitation the rights to use, copy, modify, merge, publish, + * distribute, sub license, and/or sell copies of the Software, and to + * permit persons to whom the Software is furnished to do so, subject to + * the following conditions: + * + * The above copyright notice and this permission notice (including the + * next paragraph) shall be included in all copies or substantial portions + * of the Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS + * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF + * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT. + * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR + * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, + * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE + * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. + * + **************************************************************************/ + +#include <llvm-c/Core.h> +#include <llvm/Target/TargetMachine.h> +#include <llvm/Target/TargetRegistry.h> +#include <llvm/Target/TargetSelect.h> +#include <llvm/Target/TargetInstrInfo.h> +#include <llvm/Support/raw_ostream.h> +#include <llvm/Support/MemoryObject.h> +#include <llvm/System/Host.h> + +#if HAVE_LLVM >= 0x0207 +#include <llvm/MC/MCDisassembler.h> +#include <llvm/MC/MCAsmInfo.h> +#include <llvm/MC/MCInst.h> +#include <llvm/MC/MCInstPrinter.h> +#endif /* HAVE_LLVM >= 0x0207 */ + +#include "util/u_math.h" +#include "util/u_debug.h" + +#include "lp_bld_debug.h" + + + +/** + * Check alignment. + * + * It is important that this check is not implemented as a macro or inlined + * function, as the compiler assumptions in respect to alignment of global + * and stack variables would often make the check a no op, defeating the + * whole purpose of the exercise. + */ +extern "C" boolean +lp_check_alignment(const void *ptr, unsigned alignment) +{ + assert(util_is_power_of_two(alignment)); + return ((uintptr_t)ptr & (alignment - 1)) == 0; +} + + +class raw_debug_ostream : + public llvm::raw_ostream +{ + uint64_t pos; + + void write_impl(const char *Ptr, size_t Size); + uint64_t current_pos() { return pos; } + uint64_t current_pos() const { return pos; } + +#if HAVE_LLVM >= 0x207 + uint64_t preferred_buffer_size() { return 512; } +#else + size_t preferred_buffer_size() { return 512; } +#endif +}; + + +void +raw_debug_ostream::write_impl(const char *Ptr, size_t Size) +{ + if (Size > 0) { + char *lastPtr = (char *)&Ptr[Size]; + char last = *lastPtr; + *lastPtr = 0; + _debug_printf("%*s", Size, Ptr); + *lastPtr = last; + pos += Size; + } +} + + +/** + * Same as LLVMDumpValue, but through our debugging channels. + */ +extern "C" void +lp_debug_dump_value(LLVMValueRef value) +{ +#if (defined(PIPE_OS_WINDOWS) && !defined(PIPE_CC_MSVC)) || defined(PIPE_OS_EMBDDED) + raw_debug_ostream os; + llvm::unwrap(value)->print(os); + os.flush(); +#else + LLVMDumpValue(value); +#endif +} + + +/* + * MemoryObject wrapper around a buffer of memory, to be used by MC + * disassembler. + */ +class BufferMemoryObject: + public llvm::MemoryObject +{ +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; + } +}; + + +/* + * Disassemble a function, using the LLVM MC disassembler. + * + * See also: + * - http://blog.llvm.org/2010/01/x86-disassembler.html + * - http://blog.llvm.org/2010/04/intro-to-llvm-mc-project.html + */ +extern "C" void +lp_disassemble(const void* func) +{ +#if HAVE_LLVM >= 0x0207 + using namespace llvm; + + const uint8_t *bytes = (const uint8_t *)func; + + /* + * Limit disassembly to this extent + */ + const uint64_t extent = 0x10000; + + uint64_t max_pc = 0; + + /* + * Initialize all used objects. + */ + + std::string Triple = sys::getHostTriple(); + + std::string Error; + const Target *T = TargetRegistry::lookupTarget(Triple, Error); + +#if HAVE_LLVM >= 0x0208 + InitializeNativeTargetAsmPrinter(); +#else + InitializeAllAsmPrinters(); +#endif + + InitializeAllDisassemblers(); + + OwningPtr<const MCAsmInfo> AsmInfo(T->createAsmInfo(Triple)); + + if (!AsmInfo) { + debug_printf("error: no assembly info for target %s\n", Triple.c_str()); + return; + } + + OwningPtr<const MCDisassembler> DisAsm(T->createMCDisassembler()); + if (!DisAsm) { + debug_printf("error: no disassembler for target %s\n", Triple.c_str()); + return; + } + + raw_debug_ostream Out; + + int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); +#if HAVE_LLVM >= 0x0208 + OwningPtr<MCInstPrinter> Printer( + T->createMCInstPrinter(AsmPrinterVariant, *AsmInfo)); +#else + OwningPtr<MCInstPrinter> Printer( + T->createMCInstPrinter(AsmPrinterVariant, *AsmInfo, Out)); +#endif + if (!Printer) { + debug_printf("error: no instruction printer for target %s\n", Triple.c_str()); + return; + } + + TargetMachine *TM = T->createTargetMachine(Triple, ""); + + const TargetInstrInfo *TII = TM->getInstrInfo(); + + /* + * Wrap the data in a MemoryObject + */ + BufferMemoryObject memoryObject((const uint8_t *)bytes, extent); + + uint64_t pc; + pc = 0; + while (true) { + MCInst Inst; + uint64_t Size; + + /* + * Print address. We use addresses relative to the start of the function, + * so that between runs. + */ + + debug_printf("%6lu:\t", (unsigned long)pc); + + if (!DisAsm->getInstruction(Inst, Size, memoryObject, + pc, + nulls())) { + debug_printf("invalid\n"); + pc += 1; + } + + /* + * Output the bytes in hexidecimal format. + */ + + if (0) { + unsigned i; + for (i = 0; i < Size; ++i) { + debug_printf("%02x ", ((const uint8_t*)bytes)[pc + i]); + } + for (; i < 16; ++i) { + debug_printf(" "); + } + } + + /* + * Print the instruction. + */ + +#if HAVE_LLVM >= 0x208 + Printer->printInst(&Inst, Out); +#else + Printer->printInst(&Inst); +#endif + Out.flush(); + + /* + * Advance. + */ + + pc += Size; + + const TargetInstrDesc &TID = TII->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. + */ + debug_printf("\t\t; %lu", (unsigned long)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; + } + } + } + } + + debug_printf("\n"); + + /* + * Stop disassembling on return statements, if there is no record of a + * jump to a successive address. + */ + + if (TID.isReturn()) { + if (pc > max_pc) { + break; + } + } + } + + /* + * Print GDB command, useful to verify output. + */ + + if (0) { + debug_printf("disassemble %p %p\n", bytes, bytes + pc); + } + + debug_printf("\n"); +#else + (void)func; +#endif +} + diff --git a/src/gallium/auxiliary/gallivm/lp_bld_debug.h b/src/gallium/auxiliary/gallivm/lp_bld_debug.h index 8a58f95..da873f3 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_debug.h +++ b/src/gallium/auxiliary/gallivm/lp_bld_debug.h @@ -45,6 +45,11 @@ #define GALLIVM_DEBUG_GC (1 << 6) +#ifdef __cplusplus +extern "C" { +#endif + + #ifdef DEBUG extern unsigned gallivm_debug; #else @@ -81,4 +86,9 @@ void lp_disassemble(const void* func); +#ifdef __cplusplus +} +#endif + + #endif /* !LP_BLD_DEBUG_H */ diff --git a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp b/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp index 46dd00d..843a14a 100644 --- a/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp +++ b/src/gallium/auxiliary/gallivm/lp_bld_misc.cpp @@ -46,66 +46,6 @@ #include "util/u_debug.h" -#if (defined(PIPE_OS_WINDOWS) && !defined(PIPE_CC_MSVC)) || defined(PIPE_OS_EMBDDED) - -#include "llvm/Support/raw_ostream.h" - -class raw_debug_ostream : - public llvm::raw_ostream -{ - uint64_t pos; - - void write_impl(const char *Ptr, size_t Size); - uint64_t current_pos() { return pos; } - uint64_t current_pos() const { return pos; } - -#if HAVE_LLVM >= 0x207 - uint64_t preferred_buffer_size() { return 512; } -#else - size_t preferred_buffer_size() { return 512; } -#endif -}; - - -void -raw_debug_ostream::write_impl(const char *Ptr, size_t Size) -{ - if (Size > 0) { - char *lastPtr = (char *)&Ptr[Size]; - char last = *lastPtr; - *lastPtr = 0; - _debug_printf("%*s", Size, Ptr); - *lastPtr = last; - pos += Size; - } -} - - -/** - * Same as LLVMDumpValue, but through our debugging channels. - */ -extern "C" void -lp_debug_dump_value(LLVMValueRef value) -{ - raw_debug_ostream os; - llvm::unwrap(value)->print(os); - os.flush(); -} - - -#else - - -extern "C" void -lp_debug_dump_value(LLVMValueRef value) -{ - LLVMDumpValue(value); -} - - -#endif - - /** * Register the engine with oprofile. * |