diff options
Diffstat (limited to 'src/gallium/auxiliary/gallivm/lp_bld_debug.cpp')
-rw-r--r-- | src/gallium/auxiliary/gallivm/lp_bld_debug.cpp | 357 |
1 files changed, 357 insertions, 0 deletions
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 00000000000..bb2c82fe0ed --- /dev/null +++ b/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp @@ -0,0 +1,357 @@ +/************************************************************************** + * + * 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 +} + + +#if HAVE_LLVM >= 0x0207 +/* + * 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; + } +}; +#endif /* HAVE_LLVM >= 0x0207 */ + + +/* + * 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 /* HAVE_LLVM < 0x0207 */ + (void)func; +#endif /* HAVE_LLVM < 0x0207 */ +} + |