lp_bld_debug.cpp revision 9228bfb37519e4a03183ec89e82a80f39addeeeb
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#if HAVE_LLVM >= 0x0300 197 OwningPtr<const MCAsmInfo> AsmInfo(T->createMCAsmInfo(Triple)); 198#else 199 OwningPtr<const MCAsmInfo> AsmInfo(T->createAsmInfo(Triple)); 200#endif 201 202 if (!AsmInfo) { 203 debug_printf("error: no assembly info for target %s\n", Triple.c_str()); 204 return; 205 } 206 207 OwningPtr<const MCDisassembler> DisAsm(T->createMCDisassembler()); 208 if (!DisAsm) { 209 debug_printf("error: no disassembler for target %s\n", Triple.c_str()); 210 return; 211 } 212 213 raw_debug_ostream Out; 214 215#if HAVE_LLVM >= 0x0300 216 unsigned int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); 217#else 218 int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); 219#endif 220#if 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#if HAVE_LLVM >= 0x0300 233 TargetMachine *TM = T->createTargetMachine(Triple, sys::getHostCPUName(), ""); 234#else 235 TargetMachine *TM = T->createTargetMachine(Triple, ""); 236#endif 237 238 const TargetInstrInfo *TII = TM->getInstrInfo(); 239 240 /* 241 * Wrap the data in a MemoryObject 242 */ 243 BufferMemoryObject memoryObject((const uint8_t *)bytes, extent); 244 245 uint64_t pc; 246 pc = 0; 247 while (true) { 248 MCInst Inst; 249 uint64_t Size; 250 251 /* 252 * Print address. We use addresses relative to the start of the function, 253 * so that between runs. 254 */ 255 256 debug_printf("%6lu:\t", (unsigned long)pc); 257 258 if (!DisAsm->getInstruction(Inst, Size, memoryObject, 259 pc, 260 nulls())) { 261 debug_printf("invalid\n"); 262 pc += 1; 263 } 264 265 /* 266 * Output the bytes in hexidecimal format. 267 */ 268 269 if (0) { 270 unsigned i; 271 for (i = 0; i < Size; ++i) { 272 debug_printf("%02x ", ((const uint8_t*)bytes)[pc + i]); 273 } 274 for (; i < 16; ++i) { 275 debug_printf(" "); 276 } 277 } 278 279 /* 280 * Print the instruction. 281 */ 282 283#if HAVE_LLVM >= 0x208 284 Printer->printInst(&Inst, Out); 285#else 286 Printer->printInst(&Inst); 287#endif 288 Out.flush(); 289 290 /* 291 * Advance. 292 */ 293 294 pc += Size; 295 296#if HAVE_LLVM >= 0x0300 297 const MCInstrDesc &TID = TII->get(Inst.getOpcode()); 298#else 299 const TargetInstrDesc &TID = TII->get(Inst.getOpcode()); 300#endif 301 302 /* 303 * Keep track of forward jumps to a nearby address. 304 */ 305 306 if (TID.isBranch()) { 307 for (unsigned i = 0; i < Inst.getNumOperands(); ++i) { 308 const MCOperand &operand = Inst.getOperand(i); 309 if (operand.isImm()) { 310 uint64_t jump; 311 312 /* 313 * FIXME: Handle both relative and absolute addresses correctly. 314 * EDInstInfo actually has this info, but operandTypes and 315 * operandFlags enums are not exposed in the public interface. 316 */ 317 318 if (1) { 319 /* 320 * PC relative addr. 321 */ 322 323 jump = pc + operand.getImm(); 324 } else { 325 /* 326 * Absolute addr. 327 */ 328 329 jump = (uint64_t)operand.getImm(); 330 } 331 332 /* 333 * Output the address relative to the function start, given 334 * that MC will print the addresses relative the current pc. 335 */ 336 debug_printf("\t\t; %lu", (unsigned long)jump); 337 338 /* 339 * Ignore far jumps given it could be actually a tail return to 340 * a random address. 341 */ 342 343 if (jump > max_pc && 344 jump < extent) { 345 max_pc = jump; 346 } 347 } 348 } 349 } 350 351 debug_printf("\n"); 352 353 /* 354 * Stop disassembling on return statements, if there is no record of a 355 * jump to a successive address. 356 */ 357 358 if (TID.isReturn()) { 359 if (pc > max_pc) { 360 break; 361 } 362 } 363 } 364 365 /* 366 * Print GDB command, useful to verify output. 367 */ 368 369 if (0) { 370 debug_printf("disassemble %p %p\n", bytes, bytes + pc); 371 } 372 373 debug_printf("\n"); 374#else /* HAVE_LLVM < 0x0207 */ 375 (void)func; 376#endif /* HAVE_LLVM < 0x0207 */ 377} 378 379