OSDN Git Service

gallivm: Add constructor for raw_debug_ostream.
[android-x86/external-mesa.git] / src / gallium / auxiliary / gallivm / lp_bld_debug.cpp
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/MemoryObject.h>
35
36 #if HAVE_LLVM >= 0x0300
37 #include <llvm/Support/TargetRegistry.h>
38 #else /* HAVE_LLVM < 0x0300 */
39 #include <llvm/Target/TargetRegistry.h>
40 #endif /* HAVE_LLVM < 0x0300 */
41
42 #if HAVE_LLVM >= 0x0209
43 #include <llvm/Support/Host.h>
44 #else /* HAVE_LLVM < 0x0209 */
45 #include <llvm/System/Host.h>
46 #endif /* HAVE_LLVM < 0x0209 */
47
48 #if HAVE_LLVM >= 0x0207
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 #endif /* HAVE_LLVM >= 0x0207 */
54 #if HAVE_LLVM >= 0x0301
55 #include <llvm/MC/MCRegisterInfo.h>
56 #endif /* HAVE_LLVM >= 0x0301 */
57
58 #include "util/u_math.h"
59 #include "util/u_debug.h"
60
61 #include "lp_bld_debug.h"
62
63
64
65 /**
66  * Check alignment.
67  *
68  * It is important that this check is not implemented as a macro or inlined
69  * function, as the compiler assumptions in respect to alignment of global
70  * and stack variables would often make the check a no op, defeating the
71  * whole purpose of the exercise.
72  */
73 extern "C" boolean
74 lp_check_alignment(const void *ptr, unsigned alignment)
75 {
76    assert(util_is_power_of_two(alignment));
77    return ((uintptr_t)ptr & (alignment - 1)) == 0;
78 }
79
80
81 class raw_debug_ostream :
82    public llvm::raw_ostream
83 {
84 private:
85    uint64_t pos;
86
87 public:
88    raw_debug_ostream() : pos(0) { }
89
90    void write_impl(const char *Ptr, size_t Size);
91
92 #if HAVE_LLVM >= 0x207
93    uint64_t current_pos() const { return pos; }
94    size_t preferred_buffer_size() const { return 512; }
95 #else
96    uint64_t current_pos() { return pos; }
97    size_t preferred_buffer_size() { return 512; }
98 #endif
99 };
100
101
102 void
103 raw_debug_ostream::write_impl(const char *Ptr, size_t Size)
104 {
105    if (Size > 0) {
106       char *lastPtr = (char *)&Ptr[Size];
107       char last = *lastPtr;
108       *lastPtr = 0;
109       _debug_printf("%*s", Size, Ptr);
110       *lastPtr = last;
111       pos += Size;
112    }
113 }
114
115
116 /**
117  * Same as LLVMDumpValue, but through our debugging channels.
118  */
119 extern "C" void
120 lp_debug_dump_value(LLVMValueRef value)
121 {
122 #if (defined(PIPE_OS_WINDOWS) && !defined(PIPE_CC_MSVC)) || defined(PIPE_OS_EMBDDED)
123    raw_debug_ostream os;
124    llvm::unwrap(value)->print(os);
125    os.flush();
126 #else
127    LLVMDumpValue(value);
128 #endif
129 }
130
131
132 #if HAVE_LLVM >= 0x0207
133 /*
134  * MemoryObject wrapper around a buffer of memory, to be used by MC
135  * disassembler.
136  */
137 class BufferMemoryObject:
138    public llvm::MemoryObject
139 {
140 private:
141    const uint8_t *Bytes;
142    uint64_t Length;
143 public:
144    BufferMemoryObject(const uint8_t *bytes, uint64_t length) :
145       Bytes(bytes), Length(length)
146    {
147    }
148
149    uint64_t getBase() const
150    {
151       return 0;
152    }
153
154    uint64_t getExtent() const
155    {
156       return Length;
157    }
158
159    int readByte(uint64_t addr, uint8_t *byte) const
160    {
161       if (addr > getExtent())
162          return -1;
163       *byte = Bytes[addr];
164       return 0;
165    }
166 };
167 #endif /* HAVE_LLVM >= 0x0207 */
168
169
170 /*
171  * Disassemble a function, using the LLVM MC disassembler.
172  *
173  * See also:
174  * - http://blog.llvm.org/2010/01/x86-disassembler.html
175  * - http://blog.llvm.org/2010/04/intro-to-llvm-mc-project.html
176  */
177 extern "C" void
178 lp_disassemble(const void* func)
179 {
180 #if HAVE_LLVM >= 0x0207
181    using namespace llvm;
182
183    const uint8_t *bytes = (const uint8_t *)func;
184
185    /*
186     * Limit disassembly to this extent
187     */
188    const uint64_t extent = 96 * 1024;
189
190    uint64_t max_pc = 0;
191
192    /*
193     * Initialize all used objects.
194     */
195
196 #if HAVE_LLVM >= 0x0301
197    std::string Triple = sys::getDefaultTargetTriple();
198 #else
199    std::string Triple = sys::getHostTriple();
200 #endif
201
202    std::string Error;
203    const Target *T = TargetRegistry::lookupTarget(Triple, Error);
204
205 #if HAVE_LLVM >= 0x0300
206    OwningPtr<const MCAsmInfo> AsmInfo(T->createMCAsmInfo(Triple));
207 #else
208    OwningPtr<const MCAsmInfo> AsmInfo(T->createAsmInfo(Triple));
209 #endif
210
211    if (!AsmInfo) {
212       debug_printf("error: no assembly info for target %s\n", Triple.c_str());
213       return;
214    }
215
216 #if HAVE_LLVM >= 0x0300
217    const MCSubtargetInfo *STI = T->createMCSubtargetInfo(Triple, sys::getHostCPUName(), "");
218    OwningPtr<const MCDisassembler> DisAsm(T->createMCDisassembler(*STI));
219 #else 
220    OwningPtr<const MCDisassembler> DisAsm(T->createMCDisassembler());
221 #endif 
222    if (!DisAsm) {
223       debug_printf("error: no disassembler for target %s\n", Triple.c_str());
224       return;
225    }
226
227    raw_debug_ostream Out;
228
229 #if HAVE_LLVM >= 0x0300
230    unsigned int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
231 #else
232    int AsmPrinterVariant = AsmInfo->getAssemblerDialect();
233 #endif
234
235 #if HAVE_LLVM >= 0x0301
236    OwningPtr<const MCRegisterInfo> MRI(T->createMCRegInfo(Triple));
237    if (!MRI) {
238       debug_printf("error: no register info for target %s\n", Triple.c_str());
239       return;
240    }
241
242    OwningPtr<const MCInstrInfo> MII(T->createMCInstrInfo());
243    if (!MII) {
244       debug_printf("error: no instruction info for target %s\n", Triple.c_str());
245       return;
246    }
247 #endif
248
249 #if HAVE_LLVM >= 0x0301
250    OwningPtr<MCInstPrinter> Printer(
251          T->createMCInstPrinter(AsmPrinterVariant, *AsmInfo, *MII, *MRI, *STI));
252 #elif HAVE_LLVM == 0x0300
253    OwningPtr<MCInstPrinter> Printer(
254          T->createMCInstPrinter(AsmPrinterVariant, *AsmInfo, *STI));
255 #elif HAVE_LLVM >= 0x0208
256    OwningPtr<MCInstPrinter> Printer(
257          T->createMCInstPrinter(AsmPrinterVariant, *AsmInfo));
258 #else
259    OwningPtr<MCInstPrinter> Printer(
260          T->createMCInstPrinter(AsmPrinterVariant, *AsmInfo, Out));
261 #endif
262    if (!Printer) {
263       debug_printf("error: no instruction printer for target %s\n", Triple.c_str());
264       return;
265    }
266
267 #if HAVE_LLVM >= 0x0301
268    TargetOptions options;
269 #if defined(DEBUG)
270    options.JITEmitDebugInfo = true;
271 #endif
272 #if defined(PIPE_ARCH_X86)
273    options.StackAlignmentOverride = 4;
274 #endif
275 #if defined(DEBUG) || defined(PROFILE)
276    options.NoFramePointerElim = true;
277 #endif
278    TargetMachine *TM = T->createTargetMachine(Triple, sys::getHostCPUName(), "", options);
279 #elif HAVE_LLVM == 0x0300
280    TargetMachine *TM = T->createTargetMachine(Triple, sys::getHostCPUName(), "");
281 #else
282    TargetMachine *TM = T->createTargetMachine(Triple, "");
283 #endif
284
285    const TargetInstrInfo *TII = TM->getInstrInfo();
286
287    /*
288     * Wrap the data in a MemoryObject
289     */
290    BufferMemoryObject memoryObject((const uint8_t *)bytes, extent);
291
292    uint64_t pc;
293    pc = 0;
294    while (true) {
295       MCInst Inst;
296       uint64_t Size;
297
298       /*
299        * Print address.  We use addresses relative to the start of the function,
300        * so that between runs.
301        */
302
303       debug_printf("%6lu:\t", (unsigned long)pc);
304
305       if (!DisAsm->getInstruction(Inst, Size, memoryObject,
306                                  pc,
307 #if HAVE_LLVM >= 0x0300
308                                   nulls(), nulls())) {
309 #else
310                                   nulls())) {
311 #endif
312          debug_printf("invalid\n");
313          pc += 1;
314       }
315
316       /*
317        * Output the bytes in hexidecimal format.
318        */
319
320       if (0) {
321          unsigned i;
322          for (i = 0; i < Size; ++i) {
323             debug_printf("%02x ", ((const uint8_t*)bytes)[pc + i]);
324          }
325          for (; i < 16; ++i) {
326             debug_printf("   ");
327          }
328       }
329
330       /*
331        * Print the instruction.
332        */
333
334 #if HAVE_LLVM >= 0x0300
335       Printer->printInst(&Inst, Out, "");
336 #elif HAVE_LLVM >= 0x208
337       Printer->printInst(&Inst, Out);
338 #else
339       Printer->printInst(&Inst);
340 #endif
341       Out.flush();
342
343       /*
344        * Advance.
345        */
346
347       pc += Size;
348
349 #if HAVE_LLVM >= 0x0300
350       const MCInstrDesc &TID = TII->get(Inst.getOpcode());
351 #else
352       const TargetInstrDesc &TID = TII->get(Inst.getOpcode());
353 #endif
354
355       /*
356        * Keep track of forward jumps to a nearby address.
357        */
358
359       if (TID.isBranch()) {
360          for (unsigned i = 0; i < Inst.getNumOperands(); ++i) {
361             const MCOperand &operand = Inst.getOperand(i);
362             if (operand.isImm()) {
363                uint64_t jump;
364
365                /*
366                 * FIXME: Handle both relative and absolute addresses correctly.
367                 * EDInstInfo actually has this info, but operandTypes and
368                 * operandFlags enums are not exposed in the public interface.
369                 */
370
371                if (1) {
372                   /*
373                    * PC relative addr.
374                    */
375
376                   jump = pc + operand.getImm();
377                } else {
378                   /*
379                    * Absolute addr.
380                    */
381
382                   jump = (uint64_t)operand.getImm();
383                }
384
385                /*
386                 * Output the address relative to the function start, given
387                 * that MC will print the addresses relative the current pc.
388                 */
389                debug_printf("\t\t; %lu", (unsigned long)jump);
390
391                /*
392                 * Ignore far jumps given it could be actually a tail return to
393                 * a random address.
394                 */
395
396                if (jump > max_pc &&
397                    jump < extent) {
398                   max_pc = jump;
399                }
400             }
401          }
402       }
403
404       debug_printf("\n");
405
406       /*
407        * Stop disassembling on return statements, if there is no record of a
408        * jump to a successive address.
409        */
410
411       if (TID.isReturn()) {
412          if (pc > max_pc) {
413             break;
414          }
415       }
416    }
417
418    /*
419     * Print GDB command, useful to verify output.
420     */
421
422    if (0) {
423       debug_printf("disassemble %p %p\n", bytes, bytes + pc);
424    }
425
426    debug_printf("\n");
427 #else /* HAVE_LLVM < 0x0207 */
428    (void)func;
429 #endif /* HAVE_LLVM < 0x0207 */
430 }
431