MachODumper.cpp revision 249423
1//===-- MachODump.cpp - Object file dumping utility for llvm --------------===// 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// This file implements the MachO-specific dumper for llvm-readobj. 11// 12//===----------------------------------------------------------------------===// 13 14#include "llvm-readobj.h" 15#include "Error.h" 16#include "ObjDumper.h" 17#include "StreamWriter.h" 18 19#include "llvm/ADT/SmallString.h" 20#include "llvm/Object/MachO.h" 21#include "llvm/Support/Casting.h" 22 23using namespace llvm; 24using namespace object; 25 26namespace { 27 28class MachODumper : public ObjDumper { 29public: 30 MachODumper(const llvm::object::MachOObjectFile *Obj, StreamWriter& Writer) 31 : ObjDumper(Writer) 32 , Obj(Obj) { } 33 34 virtual void printFileHeaders() LLVM_OVERRIDE; 35 virtual void printSections() LLVM_OVERRIDE; 36 virtual void printRelocations() LLVM_OVERRIDE; 37 virtual void printSymbols() LLVM_OVERRIDE; 38 virtual void printDynamicSymbols() LLVM_OVERRIDE; 39 virtual void printUnwindInfo() LLVM_OVERRIDE; 40 41private: 42 void printSymbol(symbol_iterator SymI); 43 44 void printRelocation(section_iterator SecI, relocation_iterator RelI); 45 46 const llvm::object::MachOObjectFile *Obj; 47}; 48 49} // namespace 50 51 52namespace llvm { 53 54error_code createMachODumper(const object::ObjectFile *Obj, 55 StreamWriter& Writer, 56 OwningPtr<ObjDumper> &Result) { 57 const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj); 58 if (!MachOObj) 59 return readobj_error::unsupported_obj_file_format; 60 61 Result.reset(new MachODumper(MachOObj, Writer)); 62 return readobj_error::success; 63} 64 65} // namespace llvm 66 67 68static const EnumEntry<unsigned> MachOSectionTypes[] = { 69 { "Regular" , 0x00 }, 70 { "ZeroFill" , 0x01 }, 71 { "CStringLiterals" , 0x02 }, 72 { "4ByteLiterals" , 0x03 }, 73 { "8ByteLiterals" , 0x04 }, 74 { "LiteralPointers" , 0x05 }, 75 { "NonLazySymbolPointers" , 0x06 }, 76 { "LazySymbolPointers" , 0x07 }, 77 { "SymbolStubs" , 0x08 }, 78 { "ModInitFuncs" , 0x09 }, 79 { "ModTermFuncs" , 0x0A }, 80 { "Coalesced" , 0x0B }, 81 { "GBZeroFill" , 0x0C }, 82 { "Interposing" , 0x0D }, 83 { "16ByteLiterals" , 0x0E }, 84 { "DTraceDOF" , 0x0F }, 85 { "LazyDylibSymbolPoints" , 0x10 }, 86 { "ThreadLocalRegular" , 0x11 }, 87 { "ThreadLocalZerofill" , 0x12 }, 88 { "ThreadLocalVariables" , 0x13 }, 89 { "ThreadLocalVariablePointers" , 0x14 }, 90 { "ThreadLocalInitFunctionPointers", 0x15 } 91}; 92 93static const EnumEntry<unsigned> MachOSectionAttributes[] = { 94 { "LocReloc" , 1 << 0 /*S_ATTR_LOC_RELOC */ }, 95 { "ExtReloc" , 1 << 1 /*S_ATTR_EXT_RELOC */ }, 96 { "SomeInstructions" , 1 << 2 /*S_ATTR_SOME_INSTRUCTIONS */ }, 97 { "Debug" , 1 << 17 /*S_ATTR_DEBUG */ }, 98 { "SelfModifyingCode", 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/ }, 99 { "LiveSupport" , 1 << 19 /*S_ATTR_LIVE_SUPPORT */ }, 100 { "NoDeadStrip" , 1 << 20 /*S_ATTR_NO_DEAD_STRIP */ }, 101 { "StripStaticSyms" , 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS */ }, 102 { "NoTOC" , 1 << 22 /*S_ATTR_NO_TOC */ }, 103 { "PureInstructions" , 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS */ }, 104}; 105 106static const EnumEntry<unsigned> MachOSymbolRefTypes[] = { 107 { "UndefinedNonLazy", 0 }, 108 { "ReferenceFlagUndefinedLazy", 1 }, 109 { "ReferenceFlagDefined", 2 }, 110 { "ReferenceFlagPrivateDefined", 3 }, 111 { "ReferenceFlagPrivateUndefinedNonLazy", 4 }, 112 { "ReferenceFlagPrivateUndefinedLazy", 5 } 113}; 114 115static const EnumEntry<unsigned> MachOSymbolFlags[] = { 116 { "ReferencedDynamically", 0x10 }, 117 { "NoDeadStrip", 0x20 }, 118 { "WeakRef", 0x40 }, 119 { "WeakDef", 0x80 } 120}; 121 122static const EnumEntry<unsigned> MachOSymbolTypes[] = { 123 { "Undef", 0x0 }, 124 { "External", 0x1 }, 125 { "Abs", 0x2 }, 126 { "Indirect", 0xA }, 127 { "PreboundUndef", 0xC }, 128 { "Section", 0xE }, 129 { "PrivateExternal", 0x10 } 130}; 131 132namespace { 133 enum { 134 N_STAB = 0xE0 135 }; 136 137 struct MachOSection { 138 ArrayRef<char> Name; 139 ArrayRef<char> SegmentName; 140 uint64_t Address; 141 uint64_t Size; 142 uint32_t Offset; 143 uint32_t Alignment; 144 uint32_t RelocationTableOffset; 145 uint32_t NumRelocationTableEntries; 146 uint32_t Flags; 147 uint32_t Reserved1; 148 uint32_t Reserved2; 149 }; 150 151 struct MachOSymbol { 152 uint32_t StringIndex; 153 uint8_t Type; 154 uint8_t SectionIndex; 155 uint16_t Flags; 156 uint64_t Value; 157 }; 158} 159 160static StringRef parseSegmentOrSectionName(ArrayRef<char> P) { 161 if (P[15] == 0) 162 // Null terminated. 163 return StringRef(P.data()); 164 // Not null terminated, so this is a 16 char string. 165 return StringRef(P.data(), 16); 166} 167 168static bool is64BitLoadCommand(const MachOObject *MachOObj, DataRefImpl DRI) { 169 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 170 if (LCI.Command.Type == macho::LCT_Segment64) 171 return true; 172 assert(LCI.Command.Type == macho::LCT_Segment && "Unexpected Type."); 173 return false; 174} 175 176static void getSection(const MachOObject *MachOObj, 177 DataRefImpl DRI, 178 MachOSection &Section) { 179 LoadCommandInfo LCI = MachOObj->getLoadCommandInfo(DRI.d.a); 180 if (is64BitLoadCommand(MachOObj, DRI)) { 181 InMemoryStruct<macho::Section64> Sect; 182 MachOObj->ReadSection64(LCI, DRI.d.b, Sect); 183 184 Section.Name = ArrayRef<char>(Sect->Name); 185 Section.SegmentName = ArrayRef<char>(Sect->SegmentName); 186 Section.Address = Sect->Address; 187 Section.Size = Sect->Size; 188 Section.Offset = Sect->Offset; 189 Section.Alignment = Sect->Align; 190 Section.RelocationTableOffset = Sect->RelocationTableOffset; 191 Section.NumRelocationTableEntries = Sect->NumRelocationTableEntries; 192 Section.Flags = Sect->Flags; 193 Section.Reserved1 = Sect->Reserved1; 194 Section.Reserved2 = Sect->Reserved2; 195 } else { 196 InMemoryStruct<macho::Section> Sect; 197 MachOObj->ReadSection(LCI, DRI.d.b, Sect); 198 199 Section.Name = Sect->Name; 200 Section.SegmentName = Sect->SegmentName; 201 Section.Address = Sect->Address; 202 Section.Size = Sect->Size; 203 Section.Offset = Sect->Offset; 204 Section.Alignment = Sect->Align; 205 Section.RelocationTableOffset = Sect->RelocationTableOffset; 206 Section.NumRelocationTableEntries = Sect->NumRelocationTableEntries; 207 Section.Flags = Sect->Flags; 208 Section.Reserved1 = Sect->Reserved1; 209 Section.Reserved2 = Sect->Reserved2; 210 } 211} 212 213static void getSymbolTableEntry(const MachOObject *MachO, 214 DataRefImpl DRI, 215 InMemoryStruct<macho::SymbolTableEntry> &Res) { 216 InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; 217 LoadCommandInfo LCI = MachO->getLoadCommandInfo(DRI.d.a); 218 MachO->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); 219 MachO->ReadSymbolTableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, Res); 220} 221 222static void getSymbol64TableEntry(const MachOObject *MachO, 223 DataRefImpl DRI, 224 InMemoryStruct<macho::Symbol64TableEntry> &Res) { 225 InMemoryStruct<macho::SymtabLoadCommand> SymtabLoadCmd; 226 LoadCommandInfo LCI = MachO->getLoadCommandInfo(DRI.d.a); 227 MachO->ReadSymtabLoadCommand(LCI, SymtabLoadCmd); 228 MachO->ReadSymbol64TableEntry(SymtabLoadCmd->SymbolTableOffset, DRI.d.b, Res); 229} 230 231static void getSymbol(const MachOObject *MachOObj, 232 DataRefImpl DRI, 233 MachOSymbol &Symbol) { 234 if (MachOObj->is64Bit()) { 235 InMemoryStruct<macho::Symbol64TableEntry> Entry; 236 getSymbol64TableEntry(MachOObj, DRI, Entry); 237 Symbol.StringIndex = Entry->StringIndex; 238 Symbol.Type = Entry->Type; 239 Symbol.SectionIndex = Entry->SectionIndex; 240 Symbol.Flags = Entry->Flags; 241 Symbol.Value = Entry->Value; 242 } else { 243 InMemoryStruct<macho::SymbolTableEntry> Entry; 244 getSymbolTableEntry(MachOObj, DRI, Entry); 245 Symbol.StringIndex = Entry->StringIndex; 246 Symbol.Type = Entry->Type; 247 Symbol.SectionIndex = Entry->SectionIndex; 248 Symbol.Flags = Entry->Flags; 249 Symbol.Value = Entry->Value; 250 } 251} 252 253void MachODumper::printFileHeaders() { 254 W.startLine() << "FileHeaders not implemented.\n"; 255} 256 257void MachODumper::printSections() { 258 ListScope Group(W, "Sections"); 259 260 int SectionIndex = -1; 261 error_code EC; 262 for (section_iterator SecI = Obj->begin_sections(), 263 SecE = Obj->end_sections(); 264 SecI != SecE; SecI.increment(EC)) { 265 if (error(EC)) break; 266 267 ++SectionIndex; 268 269 const MachOObject *MachO = const_cast<MachOObjectFile*>(Obj)->getObject(); 270 271 MachOSection Section; 272 getSection(MachO, SecI->getRawDataRefImpl(), Section); 273 StringRef Name; 274 if (error(SecI->getName(Name))) 275 Name = ""; 276 277 DictScope SectionD(W, "Section"); 278 W.printNumber("Index", SectionIndex); 279 W.printBinary("Name", Name, Section.Name); 280 W.printBinary("Segment", parseSegmentOrSectionName(Section.SegmentName), 281 Section.SegmentName); 282 W.printHex ("Address", Section.Address); 283 W.printHex ("Size", Section.Size); 284 W.printNumber("Offset", Section.Offset); 285 W.printNumber("Alignment", Section.Alignment); 286 W.printHex ("RelocationOffset", Section.RelocationTableOffset); 287 W.printNumber("RelocationCount", Section.NumRelocationTableEntries); 288 W.printEnum ("Type", Section.Flags & 0xFF, 289 makeArrayRef(MachOSectionAttributes)); 290 W.printFlags ("Attributes", Section.Flags >> 8, 291 makeArrayRef(MachOSectionAttributes)); 292 W.printHex ("Reserved1", Section.Reserved1); 293 W.printHex ("Reserved2", Section.Reserved2); 294 295 if (opts::SectionRelocations) { 296 ListScope D(W, "Relocations"); 297 for (relocation_iterator RelI = SecI->begin_relocations(), 298 RelE = SecI->end_relocations(); 299 RelI != RelE; RelI.increment(EC)) { 300 if (error(EC)) break; 301 302 printRelocation(SecI, RelI); 303 } 304 } 305 306 if (opts::SectionSymbols) { 307 ListScope D(W, "Symbols"); 308 for (symbol_iterator SymI = Obj->begin_symbols(), 309 SymE = Obj->end_symbols(); 310 SymI != SymE; SymI.increment(EC)) { 311 if (error(EC)) break; 312 313 bool Contained = false; 314 if (SecI->containsSymbol(*SymI, Contained) || !Contained) 315 continue; 316 317 printSymbol(SymI); 318 } 319 } 320 321 if (opts::SectionData) { 322 StringRef Data; 323 if (error(SecI->getContents(Data))) break; 324 325 W.printBinaryBlock("SectionData", Data); 326 } 327 } 328} 329 330void MachODumper::printRelocations() { 331 ListScope D(W, "Relocations"); 332 333 error_code EC; 334 for (section_iterator SecI = Obj->begin_sections(), 335 SecE = Obj->end_sections(); 336 SecI != SecE; SecI.increment(EC)) { 337 if (error(EC)) break; 338 339 StringRef Name; 340 if (error(SecI->getName(Name))) 341 continue; 342 343 bool PrintedGroup = false; 344 for (relocation_iterator RelI = SecI->begin_relocations(), 345 RelE = SecI->end_relocations(); 346 RelI != RelE; RelI.increment(EC)) { 347 if (error(EC)) break; 348 349 if (!PrintedGroup) { 350 W.startLine() << "Section " << Name << " {\n"; 351 W.indent(); 352 PrintedGroup = true; 353 } 354 355 printRelocation(SecI, RelI); 356 } 357 358 if (PrintedGroup) { 359 W.unindent(); 360 W.startLine() << "}\n"; 361 } 362 } 363} 364 365void MachODumper::printRelocation(section_iterator SecI, 366 relocation_iterator RelI) { 367 uint64_t Offset; 368 SmallString<32> RelocName; 369 int64_t Info; 370 StringRef SymbolName; 371 SymbolRef Symbol; 372 if (error(RelI->getOffset(Offset))) return; 373 if (error(RelI->getTypeName(RelocName))) return; 374 if (error(RelI->getAdditionalInfo(Info))) return; 375 if (error(RelI->getSymbol(Symbol))) return; 376 if (error(Symbol.getName(SymbolName))) return; 377 378 raw_ostream& OS = W.startLine(); 379 OS << W.hex(Offset) 380 << " " << RelocName 381 << " " << (SymbolName.size() > 0 ? SymbolName : "-") 382 << " " << W.hex(Info) 383 << "\n"; 384} 385 386void MachODumper::printSymbols() { 387 ListScope Group(W, "Symbols"); 388 389 error_code EC; 390 for (symbol_iterator SymI = Obj->begin_symbols(), 391 SymE = Obj->end_symbols(); 392 SymI != SymE; SymI.increment(EC)) { 393 if (error(EC)) break; 394 395 printSymbol(SymI); 396 } 397} 398 399void MachODumper::printDynamicSymbols() { 400 ListScope Group(W, "DynamicSymbols"); 401} 402 403void MachODumper::printSymbol(symbol_iterator SymI) { 404 error_code EC; 405 406 StringRef SymbolName; 407 if (SymI->getName(SymbolName)) 408 SymbolName = ""; 409 410 const MachOObject *MachO = const_cast<MachOObjectFile*>(Obj)->getObject(); 411 412 MachOSymbol Symbol; 413 getSymbol(MachO, SymI->getRawDataRefImpl(), Symbol); 414 415 StringRef SectionName; 416 section_iterator SecI(Obj->end_sections()); 417 if (error(SymI->getSection(SecI)) || 418 error(SecI->getName(SectionName))) 419 SectionName = ""; 420 421 DictScope D(W, "Symbol"); 422 W.printNumber("Name", SymbolName, Symbol.StringIndex); 423 if (Symbol.Type & N_STAB) { 424 W.printHex ("Type", "SymDebugTable", Symbol.Type); 425 } else { 426 W.printEnum("Type", Symbol.Type, makeArrayRef(MachOSymbolTypes)); 427 } 428 W.printHex ("Section", SectionName, Symbol.SectionIndex); 429 W.printEnum ("RefType", static_cast<uint16_t>(Symbol.Flags & 0xF), 430 makeArrayRef(MachOSymbolRefTypes)); 431 W.printFlags ("Flags", static_cast<uint16_t>(Symbol.Flags & ~0xF), 432 makeArrayRef(MachOSymbolFlags)); 433 W.printHex ("Value", Symbol.Value); 434} 435 436void MachODumper::printUnwindInfo() { 437 W.startLine() << "UnwindInfo not implemented.\n"; 438} 439