Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
PojavLauncherTeam
GitHub Repository: PojavLauncherTeam/mesa
Path: blob/21.2-virgl/src/gallium/auxiliary/gallivm/lp_bld_debug.cpp
4565 views
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
259
260