Home | History | Annotate | Download | only in gallivm
      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 #include <fstream>
     30 #include <sstream>
     31 #include <iomanip>
     32 
     33 #include <llvm-c/Core.h>
     34 #include <llvm-c/Disassembler.h>
     35 #include <llvm/Support/raw_ostream.h>
     36 #include <llvm/Support/Format.h>
     37 #include <llvm/Support/Host.h>
     38 #include <llvm/IR/Module.h>
     39 
     40 #include "util/u_math.h"
     41 #include "util/u_debug.h"
     42 
     43 #include "lp_bld_debug.h"
     44 
     45 #ifdef __linux__
     46 #include <sys/stat.h>
     47 #include <fcntl.h>
     48 #endif
     49 
     50 
     51 
     52 /**
     53  * Check alignment.
     54  *
     55  * It is important that this check is not implemented as a macro or inlined
     56  * function, as the compiler assumptions in respect to alignment of global
     57  * and stack variables would often make the check a no op, defeating the
     58  * whole purpose of the exercise.
     59  */
     60 extern "C" boolean
     61 lp_check_alignment(const void *ptr, unsigned alignment)
     62 {
     63    assert(util_is_power_of_two(alignment));
     64    return ((uintptr_t)ptr & (alignment - 1)) == 0;
     65 }
     66 
     67 
     68 /**
     69  * Same as LLVMDumpValue, but through our debugging channels.
     70  */
     71 extern "C" void
     72 lp_debug_dump_value(LLVMValueRef value)
     73 {
     74 #if HAVE_LLVM >= 0x0304
     75    char *str = LLVMPrintValueToString(value);
     76    if (str) {
     77       os_log_message(str);
     78       LLVMDisposeMessage(str);
     79    }
     80 #elif defined(PIPE_OS_WINDOWS) || defined(PIPE_OS_EMBEDDED)
     81    std::string str;
     82    llvm::raw_string_ostream os(str);
     83    llvm::unwrap(value)->print(os);
     84    os_log_message(str.c_str());
     85 #else
     86    LLVMDumpValue(value);
     87 #endif
     88 }
     89 
     90 
     91 /*
     92  * Disassemble a function, using the LLVM MC disassembler.
     93  *
     94  * See also:
     95  * - http://blog.llvm.org/2010/01/x86-disassembler.html
     96  * - http://blog.llvm.org/2010/04/intro-to-llvm-mc-project.html
     97  */
     98 static size_t
     99 disassemble(const void* func, std::ostream &buffer)
    100 {
    101    const uint8_t *bytes = (const uint8_t *)func;
    102 
    103    /*
    104     * Limit disassembly to this extent
    105     */
    106    const uint64_t extent = 96 * 1024;
    107 
    108    /*
    109     * Initialize all used objects.
    110     */
    111 
    112    const char *triple = LLVM_HOST_TRIPLE;
    113    LLVMDisasmContextRef D = LLVMCreateDisasm(triple, NULL, 0, NULL, NULL);
    114    char outline[1024];
    115 
    116    if (!D) {
    117       buffer << "error: could not create disassembler for triple "
    118              << triple << '\n';
    119       return 0;
    120    }
    121 
    122    uint64_t pc;
    123    pc = 0;
    124    while (pc < extent) {
    125       size_t Size;
    126 
    127       /*
    128        * Print address.  We use addresses relative to the start of the function,
    129        * so that between runs.
    130        */
    131 
    132       buffer << std::setw(6) << (unsigned long)pc << ":\t";
    133 
    134       Size = LLVMDisasmInstruction(D, (uint8_t *)bytes + pc, extent - pc, 0, outline,
    135                                    sizeof outline);
    136 
    137       if (!Size) {
    138          buffer << "invalid\n";
    139          pc += 1;
    140          break;
    141       }
    142 
    143       /*
    144        * Output the bytes in hexidecimal format.
    145        */
    146 
    147       if (0) {
    148          unsigned i;
    149          for (i = 0; i < Size; ++i) {
    150             buffer << std::hex << std::setfill('0') << std::setw(2)
    151                    << static_cast<int> (bytes[pc + i]);
    152          }
    153          for (; i < 16; ++i) {
    154             buffer << std::dec << "   ";
    155          }
    156       }
    157 
    158       /*
    159        * Print the instruction.
    160        */
    161 
    162       buffer << std::setw(Size) << outline << '\n';
    163 
    164       /*
    165        * Stop disassembling on return statements, if there is no record of a
    166        * jump to a successive address.
    167        *
    168        * XXX: This currently assumes x86
    169        */
    170 
    171 #if defined(PIPE_ARCH_X86) || defined(PIPE_ARCH_X86_64)
    172       if (Size == 1 && bytes[pc] == 0xc3) {
    173          break;
    174       }
    175 #endif
    176 
    177       /*
    178        * Advance.
    179        */
    180 
    181       pc += Size;
    182 
    183       if (pc >= extent) {
    184          buffer << "disassembly larger than " << extent << " bytes, aborting\n";
    185          break;
    186       }
    187    }
    188 
    189    buffer << '\n';
    190 
    191    LLVMDisasmDispose(D);
    192 
    193    /*
    194     * Print GDB command, useful to verify output.
    195     */
    196    if (0) {
    197       buffer << "disassemble " << static_cast<const void*>(bytes) << ' '
    198              << static_cast<const void*>(bytes + pc) << '\n';
    199    }
    200 
    201    return pc;
    202 }
    203 
    204 
    205 extern "C" void
    206 lp_disassemble(LLVMValueRef func, const void *code)
    207 {
    208    std::ostringstream buffer;
    209    std::string s;
    210 
    211    buffer << LLVMGetValueName(func) << ":\n";
    212    disassemble(code, buffer);
    213    s = buffer.str();
    214    os_log_message(s.c_str());
    215    os_log_message("\n");
    216 }
    217 
    218 
    219 /*
    220  * Linux perf profiler integration.
    221  *
    222  * See also:
    223  * - http://penberg.blogspot.co.uk/2009/06/jato-has-profiler.html
    224  * - https://github.com/penberg/jato/commit/73ad86847329d99d51b386f5aba692580d1f8fdc
    225  * - http://git.kernel.org/?p=linux/kernel/git/torvalds/linux.git;a=commitdiff;h=80d496be89ed7dede5abee5c057634e80a31c82d
    226  */
    227 extern "C" void
    228 lp_profile(LLVMValueRef func, const void *code)
    229 {
    230 #if defined(__linux__) && defined(PROFILE)
    231    static std::ofstream perf_asm_file;
    232    static boolean first_time = TRUE;
    233    static FILE *perf_map_file = NULL;
    234    if (first_time) {
    235       /*
    236        * We rely on the disassembler for determining a function's size, but
    237        * the disassembly is a leaky and slow operation, so avoid running
    238        * this except when running inside linux perf, which can be inferred
    239        * by the PERF_BUILDID_DIR environment variable.
    240        */
    241       if (getenv("PERF_BUILDID_DIR")) {
    242          pid_t pid = getpid();
    243          char filename[256];
    244          util_snprintf(filename, sizeof filename, "/tmp/perf-%llu.map", (unsigned long long)pid);
    245          perf_map_file = fopen(filename, "wt");
    246          util_snprintf(filename, sizeof filename, "/tmp/perf-%llu.map.asm", (unsigned long long)pid);
    247          perf_asm_file.open(filename);
    248       }
    249       first_time = FALSE;
    250    }
    251    if (perf_map_file) {
    252       const char *symbol = LLVMGetValueName(func);
    253       unsigned long addr = (uintptr_t)code;
    254       perf_asm_file << symbol << ":\n";
    255       unsigned long size = disassemble(code, perf_asm_file);
    256       perf_asm_file.flush();
    257       fprintf(perf_map_file, "%lx %lx %s\n", addr, size, symbol);
    258       fflush(perf_map_file);
    259    }
    260 #else
    261    (void)func;
    262    (void)code;
    263 #endif
    264 }
    265 
    266 
    267