~mmach/netext73/mesa-haswell

« back to all changes in this revision

Viewing changes to src/gallium/auxiliary/gallivm/lp_bld_debug.cpp

  • Committer: mmach
  • Date: 2022-09-22 19:56:13 UTC
  • Revision ID: netbit73@gmail.com-20220922195613-wtik9mmy20tmor0i
2022-09-22 21:17:09

Show diffs side-by-side

added added

removed removed

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