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