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