Subversion Repositories Kolibri OS

Rev

Blame | Last modification | View Log | RSS feed

  1. /**************************************************************************
  2.  *
  3.  * Copyright 2009-2011 VMware, Inc.
  4.  * All Rights Reserved.
  5.  *
  6.  * Permission is hereby granted, free of charge, to any person obtaining a
  7.  * copy of this software and associated documentation files (the
  8.  * "Software"), to deal in the Software without restriction, including
  9.  * without limitation the rights to use, copy, modify, merge, publish,
  10.  * distribute, sub license, and/or sell copies of the Software, and to
  11.  * permit persons to whom the Software is furnished to do so, subject to
  12.  * the following conditions:
  13.  *
  14.  * The above copyright notice and this permission notice (including the
  15.  * next paragraph) shall be included in all copies or substantial portions
  16.  * of the Software.
  17.  *
  18.  * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  19.  * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
  20.  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT.
  21.  * IN NO EVENT SHALL VMWARE AND/OR ITS SUPPLIERS BE LIABLE FOR
  22.  * ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
  23.  * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
  24.  * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
  25.  *
  26.  **************************************************************************/
  27.  
  28. #include <stddef.h>
  29.  
  30. #include <llvm-c/Core.h>
  31. #include <llvm/Target/TargetMachine.h>
  32. #include <llvm/Target/TargetInstrInfo.h>
  33. #include <llvm/Support/raw_ostream.h>
  34. #include <llvm/Support/Format.h>
  35.  
  36. #if HAVE_LLVM >= 0x0306
  37. #include <llvm/Target/TargetSubtargetInfo.h>
  38. #else
  39. #include <llvm/Support/MemoryObject.h>
  40. #endif
  41.  
  42. #include <llvm/Support/TargetRegistry.h>
  43. #include <llvm/MC/MCSubtargetInfo.h>
  44.  
  45. #include <llvm/Support/Host.h>
  46.  
  47. #include <llvm/IR/Module.h>
  48.  
  49. #include <llvm/MC/MCDisassembler.h>
  50. #include <llvm/MC/MCAsmInfo.h>
  51. #include <llvm/MC/MCInst.h>
  52. #include <llvm/MC/MCInstPrinter.h>
  53. #include <llvm/MC/MCRegisterInfo.h>
  54.  
  55. #if HAVE_LLVM >= 0x0305
  56. #define OwningPtr std::unique_ptr
  57. #else
  58. #include <llvm/ADT/OwningPtr.h>
  59. #endif
  60.  
  61. #if HAVE_LLVM >= 0x0305
  62. #include <llvm/MC/MCContext.h>
  63. #endif
  64.  
  65. #include "util/u_math.h"
  66. #include "util/u_debug.h"
  67.  
  68. #include "lp_bld_debug.h"
  69.  
  70. #ifdef __linux__
  71. #include <sys/stat.h>
  72. #include <fcntl.h>
  73. #endif
  74.  
  75.  
  76.  
  77. /**
  78.  * Check alignment.
  79.  *
  80.  * It is important that this check is not implemented as a macro or inlined
  81.  * function, as the compiler assumptions in respect to alignment of global
  82.  * and stack variables would often make the check a no op, defeating the
  83.  * whole purpose of the exercise.
  84.  */
  85. extern "C" boolean
  86. lp_check_alignment(const void *ptr, unsigned alignment)
  87. {
  88.    assert(util_is_power_of_two(alignment));
  89.    return ((uintptr_t)ptr & (alignment - 1)) == 0;
  90. }
  91.  
  92.  
  93. class raw_debug_ostream :
  94.    public llvm::raw_ostream
  95. {
  96. private:
  97.    uint64_t pos;
  98.  
  99. public:
  100.    raw_debug_ostream() : pos(0) { }
  101.  
  102.    void write_impl(const char *Ptr, size_t Size);
  103.  
  104.    uint64_t current_pos() const { return pos; }
  105.    size_t preferred_buffer_size() const { return 512; }
  106. };
  107.  
  108.  
  109. void
  110. raw_debug_ostream::write_impl(const char *Ptr, size_t Size)
  111. {
  112.    if (Size > 0) {
  113.       char *lastPtr = (char *)&Ptr[Size];
  114.       char last = *lastPtr;
  115.       *lastPtr = 0;
  116.       _debug_printf("%*s", Size, Ptr);
  117.       *lastPtr = last;
  118.       pos += Size;
  119.    }
  120. }
  121.  
  122.  
  123. extern "C" const char *
  124. lp_get_module_id(LLVMModuleRef module)
  125. {
  126.    return llvm::unwrap(module)->getModuleIdentifier().c_str();
  127. }
  128.  
  129.  
  130. /**
  131.  * Same as LLVMDumpValue, but through our debugging channels.
  132.  */
  133. extern "C" void
  134. lp_debug_dump_value(LLVMValueRef value)
  135. {
  136. #if (defined(PIPE_OS_WINDOWS) && !defined(PIPE_CC_MSVC)) || defined(PIPE_OS_EMBDDED)
  137.    raw_debug_ostream os;
  138.    llvm::unwrap(value)->print(os);
  139.    os.flush();
  140. #else
  141.    LLVMDumpValue(value);
  142. #endif
  143. }
  144.  
  145.  
  146. #if HAVE_LLVM < 0x0306
  147.  
  148. /*
  149.  * MemoryObject wrapper around a buffer of memory, to be used by MC
  150.  * disassembler.
  151.  */
  152. class BufferMemoryObject:
  153.    public llvm::MemoryObject
  154. {
  155. private:
  156.    const uint8_t *Bytes;
  157.    uint64_t Length;
  158. public:
  159.    BufferMemoryObject(const uint8_t *bytes, uint64_t length) :
  160.       Bytes(bytes), Length(length)
  161.    {
  162.    }
  163.  
  164.    uint64_t getBase() const
  165.    {
  166.       return 0;
  167.    }
  168.  
  169.    uint64_t getExtent() const
  170.    {
  171.       return Length;
  172.    }
  173.  
  174.    int readByte(uint64_t addr, uint8_t *byte) const
  175.    {
  176.       if (addr > getExtent())
  177.          return -1;
  178.       *byte = Bytes[addr];
  179.       return 0;
  180.    }
  181. };
  182.  
  183. #endif /* HAVE_LLVM < 0x0306 */
  184.  
  185.  
  186. /*
  187.  * Disassemble a function, using the LLVM MC disassembler.
  188.  *
  189.  * See also:
  190.  * - http://blog.llvm.org/2010/01/x86-disassembler.html
  191.  * - http://blog.llvm.org/2010/04/intro-to-llvm-mc-project.html
  192.  */
  193. static size_t
  194. disassemble(const void* func, llvm::raw_ostream & Out)
  195. {
  196.    using namespace llvm;
  197.  
  198.    const uint8_t *bytes = (const uint8_t *)func;
  199.  
  200.    /*
  201.     * Limit disassembly to this extent
  202.     */
  203.    const uint64_t extent = 96 * 1024;
  204.  
  205.    uint64_t max_pc = 0;
  206.  
  207.    /*
  208.     * Initialize all used objects.
  209.     */
  210.  
  211.    std::string Triple = sys::getDefaultTargetTriple();
  212.  
  213.    std::string Error;
  214.    const Target *T = TargetRegistry::lookupTarget(Triple, Error);
  215.  
  216. #if HAVE_LLVM >= 0x0304
  217.    OwningPtr<const MCAsmInfo> AsmInfo(T->createMCAsmInfo(*T->createMCRegInfo(Triple), Triple));
  218. #else
  219.    OwningPtr<const MCAsmInfo> AsmInfo(T->createMCAsmInfo(Triple));
  220. #endif
  221.  
  222.    if (!AsmInfo) {
  223.       Out << "error: no assembly info for target " << Triple << "\n";
  224.       Out.flush();
  225.       return 0;
  226.    }
  227.  
  228.    unsigned int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
  229.  
  230.    OwningPtr<const MCRegisterInfo> MRI(T->createMCRegInfo(Triple));
  231.    if (!MRI) {
  232.       Out << "error: no register info for target " << Triple.c_str() << "\n";
  233.       Out.flush();
  234.       return 0;
  235.    }
  236.  
  237.    OwningPtr<const MCInstrInfo> MII(T->createMCInstrInfo());
  238.    if (!MII) {
  239.       Out << "error: no instruction info for target " << Triple.c_str() << "\n";
  240.       Out.flush();
  241.       return 0;
  242.    }
  243.  
  244. #if HAVE_LLVM >= 0x0305
  245.    OwningPtr<const MCSubtargetInfo> STI(T->createMCSubtargetInfo(Triple, sys::getHostCPUName(), ""));
  246.    OwningPtr<MCContext> MCCtx(new MCContext(AsmInfo.get(), MRI.get(), 0));
  247.    OwningPtr<const MCDisassembler> DisAsm(T->createMCDisassembler(*STI, *MCCtx));
  248. #else
  249.    OwningPtr<const MCSubtargetInfo> STI(T->createMCSubtargetInfo(Triple, sys::getHostCPUName(), ""));
  250.    OwningPtr<const MCDisassembler> DisAsm(T->createMCDisassembler(*STI));
  251. #endif
  252.    if (!DisAsm) {
  253.       Out << "error: no disassembler for target " << Triple << "\n";
  254.       Out.flush();
  255.       return 0;
  256.    }
  257.  
  258.  
  259. #if HAVE_LLVM >= 0x0307
  260.    OwningPtr<MCInstPrinter> Printer(
  261.          T->createMCInstPrinter(llvm::Triple(Triple), AsmPrinterVariant, *AsmInfo, *MII, *MRI));
  262. #else
  263.    OwningPtr<MCInstPrinter> Printer(
  264.          T->createMCInstPrinter(AsmPrinterVariant, *AsmInfo, *MII, *MRI, *STI));
  265. #endif
  266.    if (!Printer) {
  267.       Out << "error: no instruction printer for target " << Triple.c_str() << "\n";
  268.       Out.flush();
  269.       return 0;
  270.    }
  271.  
  272.    TargetOptions options;
  273. #if defined(DEBUG) && HAVE_LLVM < 0x0307
  274.    options.JITEmitDebugInfo = true;
  275. #endif
  276. #if defined(PIPE_ARCH_X86)
  277.    options.StackAlignmentOverride = 4;
  278. #endif
  279. #if defined(DEBUG) || defined(PROFILE)
  280.    options.NoFramePointerElim = true;
  281. #endif
  282.    OwningPtr<TargetMachine> TM(T->createTargetMachine(Triple, sys::getHostCPUName(), "", options));
  283.  
  284.    /*
  285.     * Wrap the data in a MemoryObject
  286.     */
  287. #if HAVE_LLVM >= 0x0306
  288.    ArrayRef<uint8_t> memoryObject((const uint8_t *)bytes, extent);
  289. #else
  290.    BufferMemoryObject memoryObject((const uint8_t *)bytes, extent);
  291. #endif
  292.  
  293.    uint64_t pc;
  294.    pc = 0;
  295.    while (true) {
  296.       MCInst Inst;
  297.       uint64_t Size;
  298.  
  299.       /*
  300.        * Print address.  We use addresses relative to the start of the function,
  301.        * so that between runs.
  302.        */
  303.  
  304.       Out << llvm::format("%6lu:\t", (unsigned long)pc);
  305.  
  306.       if (!DisAsm->getInstruction(Inst, Size, memoryObject,
  307.                                  pc,
  308.                                   nulls(), nulls())) {
  309.          Out << "invalid";
  310.          pc += 1;
  311.       }
  312.  
  313.       /*
  314.        * Output the bytes in hexidecimal format.
  315.        */
  316.  
  317.       if (0) {
  318.          unsigned i;
  319.          for (i = 0; i < Size; ++i) {
  320.             Out << llvm::format("%02x ", ((const uint8_t*)bytes)[pc + i]);
  321.          }
  322.          for (; i < 16; ++i) {
  323.             Out << "   ";
  324.          }
  325.       }
  326.  
  327.       /*
  328.        * Print the instruction.
  329.        */
  330. #if HAVE_LLVM >= 0x0307
  331.       Printer->printInst(&Inst, Out, "", *STI);
  332. #else
  333.       Printer->printInst(&Inst, Out, "");
  334. #endif
  335.  
  336.       /*
  337.        * Advance.
  338.        */
  339.  
  340.       pc += Size;
  341.  
  342.       const MCInstrDesc &TID = MII->get(Inst.getOpcode());
  343.  
  344.       /*
  345.        * Keep track of forward jumps to a nearby address.
  346.        */
  347.  
  348.       if (TID.isBranch()) {
  349.          for (unsigned i = 0; i < Inst.getNumOperands(); ++i) {
  350.             const MCOperand &operand = Inst.getOperand(i);
  351.             if (operand.isImm()) {
  352.                uint64_t jump;
  353.  
  354.                /*
  355.                 * FIXME: Handle both relative and absolute addresses correctly.
  356.                 * EDInstInfo actually has this info, but operandTypes and
  357.                 * operandFlags enums are not exposed in the public interface.
  358.                 */
  359.  
  360.                if (1) {
  361.                   /*
  362.                    * PC relative addr.
  363.                    */
  364.  
  365.                   jump = pc + operand.getImm();
  366.                } else {
  367.                   /*
  368.                    * Absolute addr.
  369.                    */
  370.  
  371.                   jump = (uint64_t)operand.getImm();
  372.                }
  373.  
  374.                /*
  375.                 * Output the address relative to the function start, given
  376.                 * that MC will print the addresses relative the current pc.
  377.                 */
  378.                Out << "\t\t; " << jump;
  379.  
  380.                /*
  381.                 * Ignore far jumps given it could be actually a tail return to
  382.                 * a random address.
  383.                 */
  384.  
  385.                if (jump > max_pc &&
  386.                    jump < extent) {
  387.                   max_pc = jump;
  388.                }
  389.             }
  390.          }
  391.       }
  392.  
  393.       Out << "\n";
  394.  
  395.       /*
  396.        * Stop disassembling on return statements, if there is no record of a
  397.        * jump to a successive address.
  398.        */
  399.  
  400.       if (TID.isReturn()) {
  401.          if (pc > max_pc) {
  402.             break;
  403.          }
  404.       }
  405.  
  406.       if (pc >= extent) {
  407.          Out << "disassembly larger than " << extent << "bytes, aborting\n";
  408.          break;
  409.       }
  410.    }
  411.  
  412.    Out << "\n";
  413.    Out.flush();
  414.  
  415.    /*
  416.     * Print GDB command, useful to verify output.
  417.     */
  418.    if (0) {
  419.       _debug_printf("disassemble %p %p\n", bytes, bytes + pc);
  420.    }
  421.  
  422.    return pc;
  423. }
  424.  
  425.  
  426. extern "C" void
  427. lp_disassemble(LLVMValueRef func, const void *code) {
  428.    raw_debug_ostream Out;
  429.    Out << LLVMGetValueName(func) << ":\n";
  430.    disassemble(code, Out);
  431. }
  432.  
  433.  
  434. /*
  435.  * Linux perf profiler integration.
  436.  *
  437.  * See also:
  438.  * - http://penberg.blogspot.co.uk/2009/06/jato-has-profiler.html
  439.  * - https://github.com/penberg/jato/commit/73ad86847329d99d51b386f5aba692580d1f8fdc
  440.  * - http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commitdiff;h=80d496be89ed7dede5abee5c057634e80a31c82d
  441.  */
  442. extern "C" void
  443. lp_profile(LLVMValueRef func, const void *code)
  444. {
  445. #if defined(__linux__) && (defined(DEBUG) || defined(PROFILE))
  446.    static boolean first_time = TRUE;
  447.    static FILE *perf_map_file = NULL;
  448.    static int perf_asm_fd = -1;
  449.    if (first_time) {
  450.       /*
  451.        * We rely on the disassembler for determining a function's size, but
  452.        * the disassembly is a leaky and slow operation, so avoid running
  453.        * this except when running inside linux perf, which can be inferred
  454.        * by the PERF_BUILDID_DIR environment variable.
  455.        */
  456.       if (getenv("PERF_BUILDID_DIR")) {
  457.          pid_t pid = getpid();
  458.          char filename[256];
  459.          util_snprintf(filename, sizeof filename, "/tmp/perf-%llu.map", (unsigned long long)pid);
  460.          perf_map_file = fopen(filename, "wt");
  461.          util_snprintf(filename, sizeof filename, "/tmp/perf-%llu.map.asm", (unsigned long long)pid);
  462.          mode_t mode = S_IRUSR | S_IWUSR | S_IRGRP | S_IROTH;
  463.          perf_asm_fd = open(filename, O_WRONLY | O_CREAT, mode);
  464.       }
  465.       first_time = FALSE;
  466.    }
  467.    if (perf_map_file) {
  468.       const char *symbol = LLVMGetValueName(func);
  469.       unsigned long addr = (uintptr_t)code;
  470.       llvm::raw_fd_ostream Out(perf_asm_fd, false);
  471.       Out << symbol << ":\n";
  472.       unsigned long size = disassemble(code, Out);
  473.       fprintf(perf_map_file, "%lx %lx %s\n", addr, size, symbol);
  474.       fflush(perf_map_file);
  475.    }
  476. #else
  477.    (void)func;
  478.    (void)code;
  479. #endif
  480. }
  481.  
  482.  
  483.