COFFDumper.cpp revision 6c1202c459ffa6d693ad92fa84e43902bc780bca
1//===-- COFFDumper.cpp - COFF-specific dumper -------------------*- C++ -*-===// 2// 3// The LLVM Compiler Infrastructure 4// 5// This file is distributed under the University of Illinois Open Source 6// License. See LICENSE.TXT for details. 7// 8//===----------------------------------------------------------------------===// 9/// 10/// \file 11/// \brief This file implements the COFF-specific dumper for llvm-readobj. 12/// 13//===----------------------------------------------------------------------===// 14 15#include "llvm-readobj.h" 16#include "ObjDumper.h" 17 18#include "Error.h" 19#include "StreamWriter.h" 20 21#include "llvm/ADT/DenseMap.h" 22#include "llvm/ADT/SmallString.h" 23#include "llvm/Object/COFF.h" 24#include "llvm/Object/ObjectFile.h" 25#include "llvm/Support/Casting.h" 26#include "llvm/Support/Compiler.h" 27#include "llvm/Support/Format.h" 28#include "llvm/Support/SourceMgr.h" 29#include "llvm/Support/Win64EH.h" 30#include "llvm/Support/raw_ostream.h" 31#include "llvm/Support/system_error.h" 32 33#include <algorithm> 34#include <cstring> 35#include <time.h> 36 37using namespace llvm; 38using namespace llvm::object; 39using namespace llvm::Win64EH; 40 41namespace { 42 43class COFFDumper : public ObjDumper { 44public: 45 COFFDumper(const llvm::object::COFFObjectFile *Obj, StreamWriter& Writer) 46 : ObjDumper(Writer) 47 , Obj(Obj) { 48 cacheRelocations(); 49 } 50 51 virtual void printFileHeaders() LLVM_OVERRIDE; 52 virtual void printSections() LLVM_OVERRIDE; 53 virtual void printRelocations() LLVM_OVERRIDE; 54 virtual void printSymbols() LLVM_OVERRIDE; 55 virtual void printDynamicSymbols() LLVM_OVERRIDE; 56 virtual void printUnwindInfo() LLVM_OVERRIDE; 57 58private: 59 void printSymbol(symbol_iterator SymI); 60 61 void printRelocation(section_iterator SecI, relocation_iterator RelI); 62 63 void printX64UnwindInfo(); 64 65 void printRuntimeFunction( 66 const RuntimeFunction& RTF, 67 uint64_t OffsetInSection, 68 const std::vector<RelocationRef> &Rels); 69 70 void printUnwindInfo( 71 const Win64EH::UnwindInfo& UI, 72 uint64_t OffsetInSection, 73 const std::vector<RelocationRef> &Rels); 74 75 void printUnwindCode(const Win64EH::UnwindInfo& UI, ArrayRef<UnwindCode> UCs); 76 77 void cacheRelocations(); 78 79 error_code getSectionContents( 80 const std::vector<RelocationRef> &Rels, 81 uint64_t Offset, 82 ArrayRef<uint8_t> &Contents, 83 uint64_t &Addr); 84 85 error_code getSection( 86 const std::vector<RelocationRef> &Rels, 87 uint64_t Offset, 88 const coff_section **Section, 89 uint64_t *AddrPtr); 90 91 typedef DenseMap<const coff_section*, std::vector<RelocationRef> > RelocMapTy; 92 93 const llvm::object::COFFObjectFile *Obj; 94 RelocMapTy RelocMap; 95 std::vector<RelocationRef> EmptyRelocs; 96}; 97 98} // namespace 99 100 101namespace llvm { 102 103error_code createCOFFDumper(const object::ObjectFile *Obj, 104 StreamWriter& Writer, 105 OwningPtr<ObjDumper> &Result) { 106 const COFFObjectFile *COFFObj = dyn_cast<COFFObjectFile>(Obj); 107 if (!COFFObj) 108 return readobj_error::unsupported_obj_file_format; 109 110 Result.reset(new COFFDumper(COFFObj, Writer)); 111 return readobj_error::success; 112} 113 114} // namespace llvm 115 116 117// Returns the name of the unwind code. 118static StringRef getUnwindCodeTypeName(uint8_t Code) { 119 switch(Code) { 120 default: llvm_unreachable("Invalid unwind code"); 121 case UOP_PushNonVol: return "PUSH_NONVOL"; 122 case UOP_AllocLarge: return "ALLOC_LARGE"; 123 case UOP_AllocSmall: return "ALLOC_SMALL"; 124 case UOP_SetFPReg: return "SET_FPREG"; 125 case UOP_SaveNonVol: return "SAVE_NONVOL"; 126 case UOP_SaveNonVolBig: return "SAVE_NONVOL_FAR"; 127 case UOP_SaveXMM128: return "SAVE_XMM128"; 128 case UOP_SaveXMM128Big: return "SAVE_XMM128_FAR"; 129 case UOP_PushMachFrame: return "PUSH_MACHFRAME"; 130 } 131} 132 133// Returns the name of a referenced register. 134static StringRef getUnwindRegisterName(uint8_t Reg) { 135 switch(Reg) { 136 default: llvm_unreachable("Invalid register"); 137 case 0: return "RAX"; 138 case 1: return "RCX"; 139 case 2: return "RDX"; 140 case 3: return "RBX"; 141 case 4: return "RSP"; 142 case 5: return "RBP"; 143 case 6: return "RSI"; 144 case 7: return "RDI"; 145 case 8: return "R8"; 146 case 9: return "R9"; 147 case 10: return "R10"; 148 case 11: return "R11"; 149 case 12: return "R12"; 150 case 13: return "R13"; 151 case 14: return "R14"; 152 case 15: return "R15"; 153 } 154} 155 156// Calculates the number of array slots required for the unwind code. 157static unsigned getNumUsedSlots(const UnwindCode &UnwindCode) { 158 switch (UnwindCode.getUnwindOp()) { 159 default: llvm_unreachable("Invalid unwind code"); 160 case UOP_PushNonVol: 161 case UOP_AllocSmall: 162 case UOP_SetFPReg: 163 case UOP_PushMachFrame: 164 return 1; 165 case UOP_SaveNonVol: 166 case UOP_SaveXMM128: 167 return 2; 168 case UOP_SaveNonVolBig: 169 case UOP_SaveXMM128Big: 170 return 3; 171 case UOP_AllocLarge: 172 return (UnwindCode.getOpInfo() == 0) ? 2 : 3; 173 } 174} 175 176// Given a symbol sym this functions returns the address and section of it. 177static error_code resolveSectionAndAddress(const COFFObjectFile *Obj, 178 const SymbolRef &Sym, 179 const coff_section *&ResolvedSection, 180 uint64_t &ResolvedAddr) { 181 if (error_code EC = Sym.getAddress(ResolvedAddr)) 182 return EC; 183 184 section_iterator iter(Obj->begin_sections()); 185 if (error_code EC = Sym.getSection(iter)) 186 return EC; 187 188 ResolvedSection = Obj->getCOFFSection(iter); 189 return object_error::success; 190} 191 192// Given a vector of relocations for a section and an offset into this section 193// the function returns the symbol used for the relocation at the offset. 194static error_code resolveSymbol(const std::vector<RelocationRef> &Rels, 195 uint64_t Offset, SymbolRef &Sym) { 196 for (std::vector<RelocationRef>::const_iterator RelI = Rels.begin(), 197 RelE = Rels.end(); 198 RelI != RelE; ++RelI) { 199 uint64_t Ofs; 200 if (error_code EC = RelI->getOffset(Ofs)) 201 return EC; 202 203 if (Ofs == Offset) { 204 Sym = *RelI->getSymbol(); 205 return readobj_error::success; 206 } 207 } 208 209 return readobj_error::unknown_symbol; 210} 211 212// Given a vector of relocations for a section and an offset into this section 213// the function returns the name of the symbol used for the relocation at the 214// offset. 215static error_code resolveSymbolName(const std::vector<RelocationRef> &Rels, 216 uint64_t Offset, StringRef &Name) { 217 SymbolRef Sym; 218 if (error_code EC = resolveSymbol(Rels, Offset, Sym)) return EC; 219 if (error_code EC = Sym.getName(Name)) return EC; 220 return object_error::success; 221} 222 223static const EnumEntry<COFF::MachineTypes> ImageFileMachineType[] = { 224 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_UNKNOWN ), 225 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AM33 ), 226 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_AMD64 ), 227 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARM ), 228 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_ARMV7 ), 229 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_EBC ), 230 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_I386 ), 231 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_IA64 ), 232 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_M32R ), 233 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPS16 ), 234 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU ), 235 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_MIPSFPU16), 236 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPC ), 237 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_POWERPCFP), 238 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_R4000 ), 239 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3 ), 240 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH3DSP ), 241 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH4 ), 242 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_SH5 ), 243 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_THUMB ), 244 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_MACHINE_WCEMIPSV2) 245}; 246 247static const EnumEntry<COFF::Characteristics> ImageFileCharacteristics[] = { 248 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_RELOCS_STRIPPED ), 249 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_EXECUTABLE_IMAGE ), 250 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LINE_NUMS_STRIPPED ), 251 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LOCAL_SYMS_STRIPPED ), 252 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_AGGRESSIVE_WS_TRIM ), 253 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_LARGE_ADDRESS_AWARE ), 254 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_LO ), 255 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_32BIT_MACHINE ), 256 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DEBUG_STRIPPED ), 257 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_REMOVABLE_RUN_FROM_SWAP), 258 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_NET_RUN_FROM_SWAP ), 259 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_SYSTEM ), 260 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_DLL ), 261 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_UP_SYSTEM_ONLY ), 262 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_FILE_BYTES_REVERSED_HI ) 263}; 264 265static const EnumEntry<COFF::SectionCharacteristics> 266ImageSectionCharacteristics[] = { 267 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD ), 268 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE ), 269 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA ), 270 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA), 271 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER ), 272 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO ), 273 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE ), 274 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT ), 275 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_GPREL ), 276 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE ), 277 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT ), 278 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED ), 279 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD ), 280 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES ), 281 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES ), 282 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES ), 283 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES ), 284 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES ), 285 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES ), 286 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES ), 287 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES ), 288 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES ), 289 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES ), 290 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES ), 291 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES ), 292 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES ), 293 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES ), 294 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL ), 295 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE ), 296 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED ), 297 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED ), 298 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED ), 299 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE ), 300 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ ), 301 LLVM_READOBJ_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE ) 302}; 303 304static const EnumEntry<COFF::SymbolBaseType> ImageSymType[] = { 305 { "Null" , COFF::IMAGE_SYM_TYPE_NULL }, 306 { "Void" , COFF::IMAGE_SYM_TYPE_VOID }, 307 { "Char" , COFF::IMAGE_SYM_TYPE_CHAR }, 308 { "Short" , COFF::IMAGE_SYM_TYPE_SHORT }, 309 { "Int" , COFF::IMAGE_SYM_TYPE_INT }, 310 { "Long" , COFF::IMAGE_SYM_TYPE_LONG }, 311 { "Float" , COFF::IMAGE_SYM_TYPE_FLOAT }, 312 { "Double", COFF::IMAGE_SYM_TYPE_DOUBLE }, 313 { "Struct", COFF::IMAGE_SYM_TYPE_STRUCT }, 314 { "Union" , COFF::IMAGE_SYM_TYPE_UNION }, 315 { "Enum" , COFF::IMAGE_SYM_TYPE_ENUM }, 316 { "MOE" , COFF::IMAGE_SYM_TYPE_MOE }, 317 { "Byte" , COFF::IMAGE_SYM_TYPE_BYTE }, 318 { "Word" , COFF::IMAGE_SYM_TYPE_WORD }, 319 { "UInt" , COFF::IMAGE_SYM_TYPE_UINT }, 320 { "DWord" , COFF::IMAGE_SYM_TYPE_DWORD } 321}; 322 323static const EnumEntry<COFF::SymbolComplexType> ImageSymDType[] = { 324 { "Null" , COFF::IMAGE_SYM_DTYPE_NULL }, 325 { "Pointer" , COFF::IMAGE_SYM_DTYPE_POINTER }, 326 { "Function", COFF::IMAGE_SYM_DTYPE_FUNCTION }, 327 { "Array" , COFF::IMAGE_SYM_DTYPE_ARRAY } 328}; 329 330static const EnumEntry<COFF::SymbolStorageClass> ImageSymClass[] = { 331 { "EndOfFunction" , COFF::IMAGE_SYM_CLASS_END_OF_FUNCTION }, 332 { "Null" , COFF::IMAGE_SYM_CLASS_NULL }, 333 { "Automatic" , COFF::IMAGE_SYM_CLASS_AUTOMATIC }, 334 { "External" , COFF::IMAGE_SYM_CLASS_EXTERNAL }, 335 { "Static" , COFF::IMAGE_SYM_CLASS_STATIC }, 336 { "Register" , COFF::IMAGE_SYM_CLASS_REGISTER }, 337 { "ExternalDef" , COFF::IMAGE_SYM_CLASS_EXTERNAL_DEF }, 338 { "Label" , COFF::IMAGE_SYM_CLASS_LABEL }, 339 { "UndefinedLabel" , COFF::IMAGE_SYM_CLASS_UNDEFINED_LABEL }, 340 { "MemberOfStruct" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_STRUCT }, 341 { "Argument" , COFF::IMAGE_SYM_CLASS_ARGUMENT }, 342 { "StructTag" , COFF::IMAGE_SYM_CLASS_STRUCT_TAG }, 343 { "MemberOfUnion" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_UNION }, 344 { "UnionTag" , COFF::IMAGE_SYM_CLASS_UNION_TAG }, 345 { "TypeDefinition" , COFF::IMAGE_SYM_CLASS_TYPE_DEFINITION }, 346 { "UndefinedStatic", COFF::IMAGE_SYM_CLASS_UNDEFINED_STATIC }, 347 { "EnumTag" , COFF::IMAGE_SYM_CLASS_ENUM_TAG }, 348 { "MemberOfEnum" , COFF::IMAGE_SYM_CLASS_MEMBER_OF_ENUM }, 349 { "RegisterParam" , COFF::IMAGE_SYM_CLASS_REGISTER_PARAM }, 350 { "BitField" , COFF::IMAGE_SYM_CLASS_BIT_FIELD }, 351 { "Block" , COFF::IMAGE_SYM_CLASS_BLOCK }, 352 { "Function" , COFF::IMAGE_SYM_CLASS_FUNCTION }, 353 { "EndOfStruct" , COFF::IMAGE_SYM_CLASS_END_OF_STRUCT }, 354 { "File" , COFF::IMAGE_SYM_CLASS_FILE }, 355 { "Section" , COFF::IMAGE_SYM_CLASS_SECTION }, 356 { "WeakExternal" , COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL }, 357 { "CLRToken" , COFF::IMAGE_SYM_CLASS_CLR_TOKEN } 358}; 359 360static const EnumEntry<COFF::COMDATType> ImageCOMDATSelect[] = { 361 { "NoDuplicates", COFF::IMAGE_COMDAT_SELECT_NODUPLICATES }, 362 { "Any" , COFF::IMAGE_COMDAT_SELECT_ANY }, 363 { "SameSize" , COFF::IMAGE_COMDAT_SELECT_SAME_SIZE }, 364 { "ExactMatch" , COFF::IMAGE_COMDAT_SELECT_EXACT_MATCH }, 365 { "Associative" , COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE }, 366 { "Largest" , COFF::IMAGE_COMDAT_SELECT_LARGEST }, 367 { "Newest" , COFF::IMAGE_COMDAT_SELECT_NEWEST } 368}; 369 370static const EnumEntry<COFF::WeakExternalCharacteristics> 371WeakExternalCharacteristics[] = { 372 { "NoLibrary", COFF::IMAGE_WEAK_EXTERN_SEARCH_NOLIBRARY }, 373 { "Library" , COFF::IMAGE_WEAK_EXTERN_SEARCH_LIBRARY }, 374 { "Alias" , COFF::IMAGE_WEAK_EXTERN_SEARCH_ALIAS } 375}; 376 377static const EnumEntry<unsigned> UnwindFlags[] = { 378 { "ExceptionHandler", Win64EH::UNW_ExceptionHandler }, 379 { "TerminateHandler", Win64EH::UNW_TerminateHandler }, 380 { "ChainInfo" , Win64EH::UNW_ChainInfo } 381}; 382 383static const EnumEntry<unsigned> UnwindOpInfo[] = { 384 { "RAX", 0 }, 385 { "RCX", 1 }, 386 { "RDX", 2 }, 387 { "RBX", 3 }, 388 { "RSP", 4 }, 389 { "RBP", 5 }, 390 { "RSI", 6 }, 391 { "RDI", 7 }, 392 { "R8", 8 }, 393 { "R9", 9 }, 394 { "R10", 10 }, 395 { "R11", 11 }, 396 { "R12", 12 }, 397 { "R13", 13 }, 398 { "R14", 14 }, 399 { "R15", 15 } 400}; 401 402// Some additional COFF structures not defined by llvm::object. 403namespace { 404 struct coff_aux_function_definition { 405 support::ulittle32_t TagIndex; 406 support::ulittle32_t TotalSize; 407 support::ulittle32_t PointerToLineNumber; 408 support::ulittle32_t PointerToNextFunction; 409 uint8_t Unused[2]; 410 }; 411 412 struct coff_aux_weak_external_definition { 413 support::ulittle32_t TagIndex; 414 support::ulittle32_t Characteristics; 415 uint8_t Unused[10]; 416 }; 417 418 struct coff_aux_file_record { 419 char FileName[18]; 420 }; 421 422 struct coff_aux_clr_token { 423 support::ulittle8_t AuxType; 424 support::ulittle8_t Reserved; 425 support::ulittle32_t SymbolTableIndex; 426 uint8_t Unused[12]; 427 }; 428} // namespace 429 430static uint64_t getOffsetOfLSDA(const Win64EH::UnwindInfo& UI) { 431 return static_cast<const char*>(UI.getLanguageSpecificData()) 432 - reinterpret_cast<const char*>(&UI); 433} 434 435static uint32_t getLargeSlotValue(ArrayRef<UnwindCode> UCs) { 436 if (UCs.size() < 3) 437 return 0; 438 439 return UCs[1].FrameOffset + (static_cast<uint32_t>(UCs[2].FrameOffset) << 16); 440} 441 442template<typename T> 443static error_code getSymbolAuxData(const COFFObjectFile *Obj, 444 const coff_symbol *Symbol, const T* &Aux) { 445 ArrayRef<uint8_t> AuxData = Obj->getSymbolAuxData(Symbol); 446 Aux = reinterpret_cast<const T*>(AuxData.data()); 447 return readobj_error::success; 448} 449 450static std::string formatSymbol(const std::vector<RelocationRef> &Rels, 451 uint64_t Offset, uint32_t Disp) { 452 std::string Buffer; 453 raw_string_ostream Str(Buffer); 454 455 StringRef Sym; 456 if (resolveSymbolName(Rels, Offset, Sym)) { 457 Str << format(" (0x%X)", Offset); 458 return Str.str(); 459 } 460 461 Str << Sym; 462 if (Disp > 0) { 463 Str << format(" +0x%X (0x%X)", Disp, Offset); 464 } else { 465 Str << format(" (0x%X)", Offset); 466 } 467 468 return Str.str(); 469} 470 471// Given a vector of relocations for a section and an offset into this section 472// the function resolves the symbol used for the relocation at the offset and 473// returns the section content and the address inside the content pointed to 474// by the symbol. 475error_code COFFDumper::getSectionContents( 476 const std::vector<RelocationRef> &Rels, uint64_t Offset, 477 ArrayRef<uint8_t> &Contents, uint64_t &Addr) { 478 479 SymbolRef Sym; 480 const coff_section *Section; 481 482 if (error_code EC = resolveSymbol(Rels, Offset, Sym)) 483 return EC; 484 if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) 485 return EC; 486 if (error_code EC = Obj->getSectionContents(Section, Contents)) 487 return EC; 488 489 return object_error::success; 490} 491 492error_code COFFDumper::getSection( 493 const std::vector<RelocationRef> &Rels, uint64_t Offset, 494 const coff_section **SectionPtr, uint64_t *AddrPtr) { 495 496 SymbolRef Sym; 497 if (error_code EC = resolveSymbol(Rels, Offset, Sym)) 498 return EC; 499 500 const coff_section *Section; 501 uint64_t Addr; 502 if (error_code EC = resolveSectionAndAddress(Obj, Sym, Section, Addr)) 503 return EC; 504 505 if (SectionPtr) 506 *SectionPtr = Section; 507 if (AddrPtr) 508 *AddrPtr = Addr; 509 510 return object_error::success; 511} 512 513void COFFDumper::cacheRelocations() { 514 error_code EC; 515 for (section_iterator SecI = Obj->begin_sections(), 516 SecE = Obj->end_sections(); 517 SecI != SecE; SecI.increment(EC)) { 518 if (error(EC)) 519 break; 520 521 const coff_section *Section = Obj->getCOFFSection(SecI); 522 523 for (relocation_iterator RelI = SecI->begin_relocations(), 524 RelE = SecI->end_relocations(); 525 RelI != RelE; RelI.increment(EC)) { 526 if (error(EC)) 527 break; 528 529 RelocMap[Section].push_back(*RelI); 530 } 531 532 // Sort relocations by address. 533 std::sort(RelocMap[Section].begin(), RelocMap[Section].end(), 534 relocAddressLess); 535 } 536} 537 538void COFFDumper::printFileHeaders() { 539 const coff_file_header *Header = 0; 540 if (error(Obj->getHeader(Header))) 541 return; 542 543 time_t TDS = Header->TimeDateStamp; 544 char FormattedTime[20] = { }; 545 strftime(FormattedTime, 20, "%Y-%m-%d %H:%M:%S", gmtime(&TDS)); 546 547 { 548 DictScope D(W, "ImageFileHeader"); 549 W.printEnum ("Machine", Header->Machine, 550 makeArrayRef(ImageFileMachineType)); 551 W.printNumber("SectionCount", Header->NumberOfSections); 552 W.printHex ("TimeDateStamp", FormattedTime, Header->TimeDateStamp); 553 W.printHex ("PointerToSymbolTable", Header->PointerToSymbolTable); 554 W.printNumber("SymbolCount", Header->NumberOfSymbols); 555 W.printNumber("OptionalHeaderSize", Header->SizeOfOptionalHeader); 556 W.printFlags ("Characteristics", Header->Characteristics, 557 makeArrayRef(ImageFileCharacteristics)); 558 } 559} 560 561void COFFDumper::printSections() { 562 error_code EC; 563 564 ListScope SectionsD(W, "Sections"); 565 int SectionNumber = 0; 566 for (section_iterator SecI = Obj->begin_sections(), 567 SecE = Obj->end_sections(); 568 SecI != SecE; SecI.increment(EC)) { 569 if (error(EC)) 570 break; 571 572 ++SectionNumber; 573 const coff_section *Section = Obj->getCOFFSection(SecI); 574 575 StringRef Name; 576 if (error(SecI->getName(Name))) 577 Name = ""; 578 579 DictScope D(W, "Section"); 580 W.printNumber("Number", SectionNumber); 581 W.printBinary("Name", Name, Section->Name); 582 W.printHex ("VirtualSize", Section->VirtualSize); 583 W.printHex ("VirtualAddress", Section->VirtualAddress); 584 W.printNumber("RawDataSize", Section->SizeOfRawData); 585 W.printHex ("PointerToRawData", Section->PointerToRawData); 586 W.printHex ("PointerToRelocations", Section->PointerToRelocations); 587 W.printHex ("PointerToLineNumbers", Section->PointerToLinenumbers); 588 W.printNumber("RelocationCount", Section->NumberOfRelocations); 589 W.printNumber("LineNumberCount", Section->NumberOfLinenumbers); 590 W.printFlags ("Characteristics", Section->Characteristics, 591 makeArrayRef(ImageSectionCharacteristics), 592 COFF::SectionCharacteristics(0x00F00000)); 593 594 if (opts::SectionRelocations) { 595 ListScope D(W, "Relocations"); 596 for (relocation_iterator RelI = SecI->begin_relocations(), 597 RelE = SecI->end_relocations(); 598 RelI != RelE; RelI.increment(EC)) { 599 if (error(EC)) break; 600 601 printRelocation(SecI, RelI); 602 } 603 } 604 605 if (opts::SectionSymbols) { 606 ListScope D(W, "Symbols"); 607 for (symbol_iterator SymI = Obj->begin_symbols(), 608 SymE = Obj->end_symbols(); 609 SymI != SymE; SymI.increment(EC)) { 610 if (error(EC)) break; 611 612 bool Contained = false; 613 if (SecI->containsSymbol(*SymI, Contained) || !Contained) 614 continue; 615 616 printSymbol(SymI); 617 } 618 } 619 620 if (opts::SectionData) { 621 StringRef Data; 622 if (error(SecI->getContents(Data))) break; 623 624 W.printBinaryBlock("SectionData", Data); 625 } 626 } 627} 628 629void COFFDumper::printRelocations() { 630 ListScope D(W, "Relocations"); 631 632 error_code EC; 633 int SectionNumber = 0; 634 for (section_iterator SecI = Obj->begin_sections(), 635 SecE = Obj->end_sections(); 636 SecI != SecE; SecI.increment(EC)) { 637 ++SectionNumber; 638 if (error(EC)) 639 break; 640 641 StringRef Name; 642 if (error(SecI->getName(Name))) 643 continue; 644 645 bool PrintedGroup = false; 646 for (relocation_iterator RelI = SecI->begin_relocations(), 647 RelE = SecI->end_relocations(); 648 RelI != RelE; RelI.increment(EC)) { 649 if (error(EC)) break; 650 651 if (!PrintedGroup) { 652 W.startLine() << "Section (" << SectionNumber << ") " << Name << " {\n"; 653 W.indent(); 654 PrintedGroup = true; 655 } 656 657 printRelocation(SecI, RelI); 658 } 659 660 if (PrintedGroup) { 661 W.unindent(); 662 W.startLine() << "}\n"; 663 } 664 } 665} 666 667void COFFDumper::printRelocation(section_iterator SecI, 668 relocation_iterator RelI) { 669 uint64_t Offset; 670 uint64_t RelocType; 671 SmallString<32> RelocName; 672 StringRef SymbolName; 673 StringRef Contents; 674 if (error(RelI->getOffset(Offset))) return; 675 if (error(RelI->getType(RelocType))) return; 676 if (error(RelI->getTypeName(RelocName))) return; 677 symbol_iterator Symbol = RelI->getSymbol(); 678 if (error(Symbol->getName(SymbolName))) return; 679 if (error(SecI->getContents(Contents))) return; 680 681 if (opts::ExpandRelocs) { 682 DictScope Group(W, "Relocation"); 683 W.printHex("Offset", Offset); 684 W.printNumber("Type", RelocName, RelocType); 685 W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); 686 } else { 687 raw_ostream& OS = W.startLine(); 688 OS << W.hex(Offset) 689 << " " << RelocName 690 << " " << (SymbolName.size() > 0 ? SymbolName : "-") 691 << "\n"; 692 } 693} 694 695void COFFDumper::printSymbols() { 696 ListScope Group(W, "Symbols"); 697 698 error_code EC; 699 for (symbol_iterator SymI = Obj->begin_symbols(), 700 SymE = Obj->end_symbols(); 701 SymI != SymE; SymI.increment(EC)) { 702 if (error(EC)) break; 703 704 printSymbol(SymI); 705 } 706} 707 708void COFFDumper::printDynamicSymbols() { 709 ListScope Group(W, "DynamicSymbols"); 710} 711 712void COFFDumper::printSymbol(symbol_iterator SymI) { 713 DictScope D(W, "Symbol"); 714 715 const coff_symbol *Symbol = Obj->getCOFFSymbol(SymI); 716 const coff_section *Section; 717 if (error_code EC = Obj->getSection(Symbol->SectionNumber, Section)) { 718 W.startLine() << "Invalid section number: " << EC.message() << "\n"; 719 W.flush(); 720 return; 721 } 722 723 StringRef SymbolName; 724 if (Obj->getSymbolName(Symbol, SymbolName)) 725 SymbolName = ""; 726 727 StringRef SectionName = ""; 728 if (Section) 729 Obj->getSectionName(Section, SectionName); 730 731 W.printString("Name", SymbolName); 732 W.printNumber("Value", Symbol->Value); 733 W.printNumber("Section", SectionName, Symbol->SectionNumber); 734 W.printEnum ("BaseType", Symbol->getBaseType(), makeArrayRef(ImageSymType)); 735 W.printEnum ("ComplexType", Symbol->getComplexType(), 736 makeArrayRef(ImageSymDType)); 737 W.printEnum ("StorageClass", Symbol->StorageClass, 738 makeArrayRef(ImageSymClass)); 739 W.printNumber("AuxSymbolCount", Symbol->NumberOfAuxSymbols); 740 741 for (unsigned I = 0; I < Symbol->NumberOfAuxSymbols; ++I) { 742 if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && 743 Symbol->getBaseType() == COFF::IMAGE_SYM_TYPE_NULL && 744 Symbol->getComplexType() == COFF::IMAGE_SYM_DTYPE_FUNCTION && 745 Symbol->SectionNumber > 0) { 746 const coff_aux_function_definition *Aux; 747 if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) 748 break; 749 750 DictScope AS(W, "AuxFunctionDef"); 751 W.printNumber("TagIndex", Aux->TagIndex); 752 W.printNumber("TotalSize", Aux->TotalSize); 753 W.printHex("PointerToLineNumber", Aux->PointerToLineNumber); 754 W.printHex("PointerToNextFunction", Aux->PointerToNextFunction); 755 W.printBinary("Unused", makeArrayRef(Aux->Unused)); 756 757 } else if ( 758 Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_WEAK_EXTERNAL || 759 (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && 760 Symbol->SectionNumber == 0 && 761 Symbol->Value == 0)) { 762 const coff_aux_weak_external_definition *Aux; 763 if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) 764 break; 765 766 const coff_symbol *Linked; 767 StringRef LinkedName; 768 error_code EC; 769 if ((EC = Obj->getSymbol(Aux->TagIndex, Linked)) || 770 (EC = Obj->getSymbolName(Linked, LinkedName))) { 771 LinkedName = ""; 772 error(EC); 773 } 774 775 DictScope AS(W, "AuxWeakExternal"); 776 W.printNumber("Linked", LinkedName, Aux->TagIndex); 777 W.printEnum ("Search", Aux->Characteristics, 778 makeArrayRef(WeakExternalCharacteristics)); 779 W.printBinary("Unused", Aux->Unused); 780 781 } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_FILE) { 782 const coff_aux_file_record *Aux; 783 if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) 784 break; 785 786 DictScope AS(W, "AuxFileRecord"); 787 W.printString("FileName", StringRef(Aux->FileName)); 788 789 } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_STATIC || 790 (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_EXTERNAL && 791 Symbol->SectionNumber != COFF::IMAGE_SYM_UNDEFINED)) { 792 const coff_aux_section_definition *Aux; 793 if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) 794 break; 795 796 DictScope AS(W, "AuxSectionDef"); 797 W.printNumber("Length", Aux->Length); 798 W.printNumber("RelocationCount", Aux->NumberOfRelocations); 799 W.printNumber("LineNumberCount", Aux->NumberOfLinenumbers); 800 W.printHex("Checksum", Aux->CheckSum); 801 W.printNumber("Number", Aux->Number); 802 W.printEnum("Selection", Aux->Selection, makeArrayRef(ImageCOMDATSelect)); 803 W.printBinary("Unused", makeArrayRef(Aux->Unused)); 804 805 if (Section && Section->Characteristics & COFF::IMAGE_SCN_LNK_COMDAT 806 && Aux->Selection == COFF::IMAGE_COMDAT_SELECT_ASSOCIATIVE) { 807 const coff_section *Assoc; 808 StringRef AssocName; 809 error_code EC; 810 if ((EC = Obj->getSection(Aux->Number, Assoc)) || 811 (EC = Obj->getSectionName(Assoc, AssocName))) { 812 AssocName = ""; 813 error(EC); 814 } 815 816 W.printNumber("AssocSection", AssocName, Aux->Number); 817 } 818 } else if (Symbol->StorageClass == COFF::IMAGE_SYM_CLASS_CLR_TOKEN) { 819 const coff_aux_clr_token *Aux; 820 if (error(getSymbolAuxData(Obj, Symbol + I, Aux))) 821 break; 822 823 DictScope AS(W, "AuxCLRToken"); 824 W.printNumber("AuxType", Aux->AuxType); 825 W.printNumber("Reserved", Aux->Reserved); 826 W.printNumber("SymbolTableIndex", Aux->SymbolTableIndex); 827 W.printBinary("Unused", Aux->Unused); 828 829 } else { 830 W.startLine() << "<unhandled auxiliary record>\n"; 831 } 832 } 833} 834 835void COFFDumper::printUnwindInfo() { 836 const coff_file_header *Header; 837 if (error(Obj->getHeader(Header))) 838 return; 839 840 ListScope D(W, "UnwindInformation"); 841 if (Header->Machine != COFF::IMAGE_FILE_MACHINE_AMD64) { 842 W.startLine() << "Unsupported image machine type " 843 "(currently only AMD64 is supported).\n"; 844 return; 845 } 846 847 printX64UnwindInfo(); 848} 849 850void COFFDumper::printX64UnwindInfo() { 851 error_code EC; 852 for (section_iterator SecI = Obj->begin_sections(), 853 SecE = Obj->end_sections(); 854 SecI != SecE; SecI.increment(EC)) { 855 if (error(EC)) break; 856 857 StringRef Name; 858 if (error(SecI->getName(Name))) 859 continue; 860 if (Name != ".pdata" && !Name.startswith(".pdata$")) 861 continue; 862 863 const coff_section *PData = Obj->getCOFFSection(SecI); 864 865 ArrayRef<uint8_t> Contents; 866 if (error(Obj->getSectionContents(PData, Contents)) || 867 Contents.empty()) 868 continue; 869 870 ArrayRef<RuntimeFunction> RFs( 871 reinterpret_cast<const RuntimeFunction *>(Contents.data()), 872 Contents.size() / sizeof(RuntimeFunction)); 873 874 for (const RuntimeFunction *I = RFs.begin(), *E = RFs.end(); I < E; ++I) { 875 const uint64_t OffsetInSection = std::distance(RFs.begin(), I) 876 * sizeof(RuntimeFunction); 877 878 printRuntimeFunction(*I, OffsetInSection, RelocMap[PData]); 879 } 880 } 881} 882 883void COFFDumper::printRuntimeFunction( 884 const RuntimeFunction& RTF, 885 uint64_t OffsetInSection, 886 const std::vector<RelocationRef> &Rels) { 887 888 DictScope D(W, "RuntimeFunction"); 889 W.printString("StartAddress", 890 formatSymbol(Rels, OffsetInSection + 0, RTF.StartAddress)); 891 W.printString("EndAddress", 892 formatSymbol(Rels, OffsetInSection + 4, RTF.EndAddress)); 893 W.printString("UnwindInfoAddress", 894 formatSymbol(Rels, OffsetInSection + 8, RTF.UnwindInfoOffset)); 895 896 const coff_section* XData = 0; 897 uint64_t UnwindInfoOffset = 0; 898 if (error(getSection(Rels, OffsetInSection + 8, &XData, &UnwindInfoOffset))) 899 return; 900 901 ArrayRef<uint8_t> XContents; 902 if (error(Obj->getSectionContents(XData, XContents)) || XContents.empty()) 903 return; 904 905 UnwindInfoOffset += RTF.UnwindInfoOffset; 906 if (UnwindInfoOffset > XContents.size()) 907 return; 908 909 const Win64EH::UnwindInfo *UI = 910 reinterpret_cast<const Win64EH::UnwindInfo *>( 911 XContents.data() + UnwindInfoOffset); 912 913 printUnwindInfo(*UI, UnwindInfoOffset, RelocMap[XData]); 914} 915 916void COFFDumper::printUnwindInfo( 917 const Win64EH::UnwindInfo& UI, 918 uint64_t OffsetInSection, 919 const std::vector<RelocationRef> &Rels) { 920 DictScope D(W, "UnwindInfo"); 921 W.printNumber("Version", UI.getVersion()); 922 W.printFlags("Flags", UI.getFlags(), makeArrayRef(UnwindFlags)); 923 W.printNumber("PrologSize", UI.PrologSize); 924 if (UI.getFrameRegister() != 0) { 925 W.printEnum("FrameRegister", UI.getFrameRegister(), 926 makeArrayRef(UnwindOpInfo)); 927 W.printHex("FrameOffset", UI.getFrameOffset()); 928 } else { 929 W.printString("FrameRegister", StringRef("-")); 930 W.printString("FrameOffset", StringRef("-")); 931 } 932 933 W.printNumber("UnwindCodeCount", UI.NumCodes); 934 { 935 ListScope CodesD(W, "UnwindCodes"); 936 ArrayRef<UnwindCode> UCs(&UI.UnwindCodes[0], UI.NumCodes); 937 for (const UnwindCode *I = UCs.begin(), *E = UCs.end(); I < E; ++I) { 938 unsigned UsedSlots = getNumUsedSlots(*I); 939 if (UsedSlots > UCs.size()) { 940 errs() << "Corrupt unwind data"; 941 return; 942 } 943 printUnwindCode(UI, ArrayRef<UnwindCode>(I, E)); 944 I += UsedSlots - 1; 945 } 946 } 947 948 uint64_t LSDAOffset = OffsetInSection + getOffsetOfLSDA(UI); 949 if (UI.getFlags() & (UNW_ExceptionHandler | UNW_TerminateHandler)) { 950 W.printString("Handler", formatSymbol(Rels, LSDAOffset, 951 UI.getLanguageSpecificHandlerOffset())); 952 } else if (UI.getFlags() & UNW_ChainInfo) { 953 const RuntimeFunction *Chained = UI.getChainedFunctionEntry(); 954 if (Chained) { 955 DictScope D(W, "Chained"); 956 W.printString("StartAddress", formatSymbol(Rels, LSDAOffset + 0, 957 Chained->StartAddress)); 958 W.printString("EndAddress", formatSymbol(Rels, LSDAOffset + 4, 959 Chained->EndAddress)); 960 W.printString("UnwindInfoAddress", formatSymbol(Rels, LSDAOffset + 8, 961 Chained->UnwindInfoOffset)); 962 } 963 } 964} 965 966// Prints one unwind code. Because an unwind code can occupy up to 3 slots in 967// the unwind codes array, this function requires that the correct number of 968// slots is provided. 969void COFFDumper::printUnwindCode(const Win64EH::UnwindInfo& UI, 970 ArrayRef<UnwindCode> UCs) { 971 assert(UCs.size() >= getNumUsedSlots(UCs[0])); 972 973 W.startLine() << format("0x%02X: ", unsigned(UCs[0].u.CodeOffset)) 974 << getUnwindCodeTypeName(UCs[0].getUnwindOp()); 975 976 uint32_t AllocSize = 0; 977 978 switch (UCs[0].getUnwindOp()) { 979 case UOP_PushNonVol: 980 outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()); 981 break; 982 983 case UOP_AllocLarge: 984 if (UCs[0].getOpInfo() == 0) { 985 AllocSize = UCs[1].FrameOffset * 8; 986 } else { 987 AllocSize = getLargeSlotValue(UCs); 988 } 989 outs() << " size=" << AllocSize; 990 break; 991 case UOP_AllocSmall: 992 outs() << " size=" << ((UCs[0].getOpInfo() + 1) * 8); 993 break; 994 case UOP_SetFPReg: 995 if (UI.getFrameRegister() == 0) { 996 outs() << " reg=<invalid>"; 997 } else { 998 outs() << " reg=" << getUnwindRegisterName(UI.getFrameRegister()) 999 << format(", offset=0x%X", UI.getFrameOffset() * 16); 1000 } 1001 break; 1002 case UOP_SaveNonVol: 1003 outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()) 1004 << format(", offset=0x%X", UCs[1].FrameOffset * 8); 1005 break; 1006 case UOP_SaveNonVolBig: 1007 outs() << " reg=" << getUnwindRegisterName(UCs[0].getOpInfo()) 1008 << format(", offset=0x%X", getLargeSlotValue(UCs)); 1009 break; 1010 case UOP_SaveXMM128: 1011 outs() << " reg=XMM" << static_cast<uint32_t>(UCs[0].getOpInfo()) 1012 << format(", offset=0x%X", UCs[1].FrameOffset * 16); 1013 break; 1014 case UOP_SaveXMM128Big: 1015 outs() << " reg=XMM" << static_cast<uint32_t>(UCs[0].getOpInfo()) 1016 << format(", offset=0x%X", getLargeSlotValue(UCs)); 1017 break; 1018 case UOP_PushMachFrame: 1019 outs() << " errcode=" << (UCs[0].getOpInfo() == 0 ? "no" : "yes"); 1020 break; 1021 } 1022 1023 outs() << "\n"; 1024} 1025