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/ADT/StringExtras.h" 20 #include "llvm/Object/MachO.h" 21 #include "llvm/Support/Casting.h" 22 23 using namespace llvm; 24 using namespace object; 25 26 namespace { 27 28 class MachODumper : public ObjDumper { 29 public: 30 MachODumper(const MachOObjectFile *Obj, StreamWriter& Writer) 31 : ObjDumper(Writer) 32 , Obj(Obj) { } 33 34 virtual void printFileHeaders() override; 35 virtual void printSections() override; 36 virtual void printRelocations() override; 37 virtual void printSymbols() override; 38 virtual void printDynamicSymbols() override; 39 virtual void printUnwindInfo() override; 40 41 private: 42 void printSymbol(const SymbolRef &Symbol); 43 44 void printRelocation(const RelocationRef &Reloc); 45 46 void printRelocation(const MachOObjectFile *Obj, const RelocationRef &Reloc); 47 48 void printSections(const MachOObjectFile *Obj); 49 50 const MachOObjectFile *Obj; 51 }; 52 53 } // namespace 54 55 56 namespace llvm { 57 58 std::error_code createMachODumper(const object::ObjectFile *Obj, 59 StreamWriter &Writer, 60 std::unique_ptr<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 { "Abs", 0x2 }, 129 { "Indirect", 0xA }, 130 { "PreboundUndef", 0xC }, 131 { "Section", 0xE } 132 }; 133 134 namespace { 135 struct MachOSection { 136 ArrayRef<char> Name; 137 ArrayRef<char> SegmentName; 138 uint64_t Address; 139 uint64_t Size; 140 uint32_t Offset; 141 uint32_t Alignment; 142 uint32_t RelocationTableOffset; 143 uint32_t NumRelocationTableEntries; 144 uint32_t Flags; 145 uint32_t Reserved1; 146 uint32_t Reserved2; 147 }; 148 149 struct MachOSymbol { 150 uint32_t StringIndex; 151 uint8_t Type; 152 uint8_t SectionIndex; 153 uint16_t Flags; 154 uint64_t Value; 155 }; 156 } 157 158 static void getSection(const MachOObjectFile *Obj, 159 DataRefImpl Sec, 160 MachOSection &Section) { 161 if (!Obj->is64Bit()) { 162 MachO::section Sect = Obj->getSection(Sec); 163 Section.Address = Sect.addr; 164 Section.Size = Sect.size; 165 Section.Offset = Sect.offset; 166 Section.Alignment = Sect.align; 167 Section.RelocationTableOffset = Sect.reloff; 168 Section.NumRelocationTableEntries = Sect.nreloc; 169 Section.Flags = Sect.flags; 170 Section.Reserved1 = Sect.reserved1; 171 Section.Reserved2 = Sect.reserved2; 172 return; 173 } 174 MachO::section_64 Sect = Obj->getSection64(Sec); 175 Section.Address = Sect.addr; 176 Section.Size = Sect.size; 177 Section.Offset = Sect.offset; 178 Section.Alignment = Sect.align; 179 Section.RelocationTableOffset = Sect.reloff; 180 Section.NumRelocationTableEntries = Sect.nreloc; 181 Section.Flags = Sect.flags; 182 Section.Reserved1 = Sect.reserved1; 183 Section.Reserved2 = Sect.reserved2; 184 } 185 186 187 static void getSymbol(const MachOObjectFile *Obj, 188 DataRefImpl DRI, 189 MachOSymbol &Symbol) { 190 if (!Obj->is64Bit()) { 191 MachO::nlist Entry = Obj->getSymbolTableEntry(DRI); 192 Symbol.StringIndex = Entry.n_strx; 193 Symbol.Type = Entry.n_type; 194 Symbol.SectionIndex = Entry.n_sect; 195 Symbol.Flags = Entry.n_desc; 196 Symbol.Value = Entry.n_value; 197 return; 198 } 199 MachO::nlist_64 Entry = Obj->getSymbol64TableEntry(DRI); 200 Symbol.StringIndex = Entry.n_strx; 201 Symbol.Type = Entry.n_type; 202 Symbol.SectionIndex = Entry.n_sect; 203 Symbol.Flags = Entry.n_desc; 204 Symbol.Value = Entry.n_value; 205 } 206 207 void MachODumper::printFileHeaders() { 208 W.startLine() << "FileHeaders not implemented.\n"; 209 } 210 211 void MachODumper::printSections() { 212 return printSections(Obj); 213 } 214 215 void MachODumper::printSections(const MachOObjectFile *Obj) { 216 ListScope Group(W, "Sections"); 217 218 int SectionIndex = -1; 219 for (const SectionRef &Section : Obj->sections()) { 220 ++SectionIndex; 221 222 MachOSection MOSection; 223 getSection(Obj, Section.getRawDataRefImpl(), MOSection); 224 DataRefImpl DR = Section.getRawDataRefImpl(); 225 226 StringRef Name; 227 if (error(Section.getName(Name))) 228 Name = ""; 229 230 ArrayRef<char> RawName = Obj->getSectionRawName(DR); 231 StringRef SegmentName = Obj->getSectionFinalSegmentName(DR); 232 ArrayRef<char> RawSegmentName = Obj->getSectionRawFinalSegmentName(DR); 233 234 DictScope SectionD(W, "Section"); 235 W.printNumber("Index", SectionIndex); 236 W.printBinary("Name", Name, RawName); 237 W.printBinary("Segment", SegmentName, RawSegmentName); 238 W.printHex("Address", MOSection.Address); 239 W.printHex("Size", MOSection.Size); 240 W.printNumber("Offset", MOSection.Offset); 241 W.printNumber("Alignment", MOSection.Alignment); 242 W.printHex("RelocationOffset", MOSection.RelocationTableOffset); 243 W.printNumber("RelocationCount", MOSection.NumRelocationTableEntries); 244 W.printEnum("Type", MOSection.Flags & 0xFF, 245 makeArrayRef(MachOSectionAttributes)); 246 W.printFlags("Attributes", MOSection.Flags >> 8, 247 makeArrayRef(MachOSectionAttributes)); 248 W.printHex("Reserved1", MOSection.Reserved1); 249 W.printHex("Reserved2", MOSection.Reserved2); 250 251 if (opts::SectionRelocations) { 252 ListScope D(W, "Relocations"); 253 for (const RelocationRef &Reloc : Section.relocations()) 254 printRelocation(Reloc); 255 } 256 257 if (opts::SectionSymbols) { 258 ListScope D(W, "Symbols"); 259 for (const SymbolRef &Symbol : Obj->symbols()) { 260 bool Contained = false; 261 if (Section.containsSymbol(Symbol, Contained) || !Contained) 262 continue; 263 264 printSymbol(Symbol); 265 } 266 } 267 268 if (opts::SectionData) { 269 StringRef Data; 270 if (error(Section.getContents(Data))) 271 break; 272 273 W.printBinaryBlock("SectionData", Data); 274 } 275 } 276 } 277 278 void MachODumper::printRelocations() { 279 ListScope D(W, "Relocations"); 280 281 std::error_code EC; 282 for (const SectionRef &Section : Obj->sections()) { 283 StringRef Name; 284 if (error(Section.getName(Name))) 285 continue; 286 287 bool PrintedGroup = false; 288 for (const RelocationRef &Reloc : Section.relocations()) { 289 if (!PrintedGroup) { 290 W.startLine() << "Section " << Name << " {\n"; 291 W.indent(); 292 PrintedGroup = true; 293 } 294 295 printRelocation(Reloc); 296 } 297 298 if (PrintedGroup) { 299 W.unindent(); 300 W.startLine() << "}\n"; 301 } 302 } 303 } 304 305 void MachODumper::printRelocation(const RelocationRef &Reloc) { 306 return printRelocation(Obj, Reloc); 307 } 308 309 void MachODumper::printRelocation(const MachOObjectFile *Obj, 310 const RelocationRef &Reloc) { 311 uint64_t Offset; 312 SmallString<32> RelocName; 313 if (error(Reloc.getOffset(Offset))) 314 return; 315 if (error(Reloc.getTypeName(RelocName))) 316 return; 317 318 DataRefImpl DR = Reloc.getRawDataRefImpl(); 319 MachO::any_relocation_info RE = Obj->getRelocation(DR); 320 bool IsScattered = Obj->isRelocationScattered(RE); 321 SmallString<32> SymbolNameOrOffset("0x"); 322 if (IsScattered) { 323 // Scattered relocations don't really have an associated symbol 324 // for some reason, even if one exists in the symtab at the correct address. 325 SymbolNameOrOffset += utohexstr(Obj->getScatteredRelocationValue(RE)); 326 } else { 327 symbol_iterator Symbol = Reloc.getSymbol(); 328 if (Symbol != Obj->symbol_end()) { 329 StringRef SymbolName; 330 if (error(Symbol->getName(SymbolName))) 331 return; 332 SymbolNameOrOffset = SymbolName; 333 } else 334 SymbolNameOrOffset += utohexstr(Obj->getPlainRelocationSymbolNum(RE)); 335 } 336 337 if (opts::ExpandRelocs) { 338 DictScope Group(W, "Relocation"); 339 W.printHex("Offset", Offset); 340 W.printNumber("PCRel", Obj->getAnyRelocationPCRel(RE)); 341 W.printNumber("Length", Obj->getAnyRelocationLength(RE)); 342 if (IsScattered) 343 W.printString("Extern", StringRef("N/A")); 344 else 345 W.printNumber("Extern", Obj->getPlainRelocationExternal(RE)); 346 W.printNumber("Type", RelocName, Obj->getAnyRelocationType(RE)); 347 W.printString("Symbol", SymbolNameOrOffset); 348 W.printNumber("Scattered", IsScattered); 349 } else { 350 raw_ostream& OS = W.startLine(); 351 OS << W.hex(Offset) 352 << " " << Obj->getAnyRelocationPCRel(RE) 353 << " " << Obj->getAnyRelocationLength(RE); 354 if (IsScattered) 355 OS << " n/a"; 356 else 357 OS << " " << Obj->getPlainRelocationExternal(RE); 358 OS << " " << RelocName 359 << " " << IsScattered 360 << " " << SymbolNameOrOffset 361 << "\n"; 362 } 363 } 364 365 void MachODumper::printSymbols() { 366 ListScope Group(W, "Symbols"); 367 368 for (const SymbolRef &Symbol : Obj->symbols()) { 369 printSymbol(Symbol); 370 } 371 } 372 373 void MachODumper::printDynamicSymbols() { 374 ListScope Group(W, "DynamicSymbols"); 375 } 376 377 void MachODumper::printSymbol(const SymbolRef &Symbol) { 378 StringRef SymbolName; 379 if (Symbol.getName(SymbolName)) 380 SymbolName = ""; 381 382 MachOSymbol MOSymbol; 383 getSymbol(Obj, Symbol.getRawDataRefImpl(), MOSymbol); 384 385 StringRef SectionName = ""; 386 section_iterator SecI(Obj->section_begin()); 387 if (!error(Symbol.getSection(SecI)) && SecI != Obj->section_end()) 388 error(SecI->getName(SectionName)); 389 390 DictScope D(W, "Symbol"); 391 W.printNumber("Name", SymbolName, MOSymbol.StringIndex); 392 if (MOSymbol.Type & MachO::N_STAB) { 393 W.printHex("Type", "SymDebugTable", MOSymbol.Type); 394 } else { 395 if (MOSymbol.Type & MachO::N_PEXT) 396 W.startLine() << "PrivateExtern\n"; 397 if (MOSymbol.Type & MachO::N_EXT) 398 W.startLine() << "Extern\n"; 399 W.printEnum("Type", uint8_t(MOSymbol.Type & MachO::N_TYPE), 400 makeArrayRef(MachOSymbolTypes)); 401 } 402 W.printHex("Section", SectionName, MOSymbol.SectionIndex); 403 W.printEnum("RefType", static_cast<uint16_t>(MOSymbol.Flags & 0xF), 404 makeArrayRef(MachOSymbolRefTypes)); 405 W.printFlags("Flags", static_cast<uint16_t>(MOSymbol.Flags & ~0xF), 406 makeArrayRef(MachOSymbolFlags)); 407 W.printHex("Value", MOSymbol.Value); 408 } 409 410 void MachODumper::printUnwindInfo() { 411 W.startLine() << "UnwindInfo not implemented.\n"; 412 } 413