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