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