MachODumper.cpp revision 263508
1230557Sjimharris//===-- MachODump.cpp - Object file dumping utility for llvm --------------===// 2230557Sjimharris// 3230557Sjimharris// The LLVM Compiler Infrastructure 4230557Sjimharris// 5230557Sjimharris// This file is distributed under the University of Illinois Open Source 6230557Sjimharris// License. See LICENSE.TXT for details. 7230557Sjimharris// 8230557Sjimharris//===----------------------------------------------------------------------===// 9230557Sjimharris// 10230557Sjimharris// This file implements the MachO-specific dumper for llvm-readobj. 11230557Sjimharris// 12230557Sjimharris//===----------------------------------------------------------------------===// 13230557Sjimharris 14230557Sjimharris#include "llvm-readobj.h" 15230557Sjimharris#include "Error.h" 16230557Sjimharris#include "ObjDumper.h" 17230557Sjimharris#include "StreamWriter.h" 18230557Sjimharris 19230557Sjimharris#include "llvm/ADT/SmallString.h" 20230557Sjimharris#include "llvm/Object/MachO.h" 21230557Sjimharris#include "llvm/Support/Casting.h" 22230557Sjimharris 23230557Sjimharrisusing namespace llvm; 24230557Sjimharrisusing namespace object; 25230557Sjimharris 26230557Sjimharrisnamespace { 27230557Sjimharris 28230557Sjimharrisclass MachODumper : public ObjDumper { 29230557Sjimharrispublic: 30230557Sjimharris MachODumper(const MachOObjectFile *Obj, StreamWriter& Writer) 31230557Sjimharris : ObjDumper(Writer) 32230557Sjimharris , Obj(Obj) { } 33230557Sjimharris 34230557Sjimharris virtual void printFileHeaders() LLVM_OVERRIDE; 35230557Sjimharris virtual void printSections() LLVM_OVERRIDE; 36230557Sjimharris virtual void printRelocations() LLVM_OVERRIDE; 37230557Sjimharris virtual void printSymbols() LLVM_OVERRIDE; 38230557Sjimharris virtual void printDynamicSymbols() LLVM_OVERRIDE; 39230557Sjimharris virtual void printUnwindInfo() LLVM_OVERRIDE; 40230557Sjimharris 41230557Sjimharrisprivate: 42230557Sjimharris void printSymbol(symbol_iterator SymI); 43230557Sjimharris 44230557Sjimharris void printRelocation(section_iterator SecI, relocation_iterator RelI); 45230557Sjimharris 46230557Sjimharris void printRelocation(const MachOObjectFile *Obj, 47230557Sjimharris section_iterator SecI, relocation_iterator RelI); 48230557Sjimharris 49230557Sjimharris void printSections(const MachOObjectFile *Obj); 50230557Sjimharris 51230557Sjimharris const MachOObjectFile *Obj; 52230557Sjimharris}; 53230557Sjimharris 54230557Sjimharris} // namespace 55230557Sjimharris 56230557Sjimharris 57230557Sjimharrisnamespace llvm { 58230557Sjimharris 59230557Sjimharriserror_code createMachODumper(const object::ObjectFile *Obj, 60230557Sjimharris StreamWriter& Writer, 61230557Sjimharris OwningPtr<ObjDumper> &Result) { 62230557Sjimharris const MachOObjectFile *MachOObj = dyn_cast<MachOObjectFile>(Obj); 63230557Sjimharris if (!MachOObj) 64230557Sjimharris return readobj_error::unsupported_obj_file_format; 65230557Sjimharris 66230557Sjimharris Result.reset(new MachODumper(MachOObj, Writer)); 67230557Sjimharris return readobj_error::success; 68230557Sjimharris} 69230557Sjimharris 70230557Sjimharris} // namespace llvm 71230557Sjimharris 72230557Sjimharris 73230557Sjimharrisstatic const EnumEntry<unsigned> MachOSectionTypes[] = { 74230557Sjimharris { "Regular" , 0x00 }, 75230557Sjimharris { "ZeroFill" , 0x01 }, 76230557Sjimharris { "CStringLiterals" , 0x02 }, 77230557Sjimharris { "4ByteLiterals" , 0x03 }, 78230557Sjimharris { "8ByteLiterals" , 0x04 }, 79230557Sjimharris { "LiteralPointers" , 0x05 }, 80 { "NonLazySymbolPointers" , 0x06 }, 81 { "LazySymbolPointers" , 0x07 }, 82 { "SymbolStubs" , 0x08 }, 83 { "ModInitFuncs" , 0x09 }, 84 { "ModTermFuncs" , 0x0A }, 85 { "Coalesced" , 0x0B }, 86 { "GBZeroFill" , 0x0C }, 87 { "Interposing" , 0x0D }, 88 { "16ByteLiterals" , 0x0E }, 89 { "DTraceDOF" , 0x0F }, 90 { "LazyDylibSymbolPoints" , 0x10 }, 91 { "ThreadLocalRegular" , 0x11 }, 92 { "ThreadLocalZerofill" , 0x12 }, 93 { "ThreadLocalVariables" , 0x13 }, 94 { "ThreadLocalVariablePointers" , 0x14 }, 95 { "ThreadLocalInitFunctionPointers", 0x15 } 96}; 97 98static const EnumEntry<unsigned> MachOSectionAttributes[] = { 99 { "LocReloc" , 1 << 0 /*S_ATTR_LOC_RELOC */ }, 100 { "ExtReloc" , 1 << 1 /*S_ATTR_EXT_RELOC */ }, 101 { "SomeInstructions" , 1 << 2 /*S_ATTR_SOME_INSTRUCTIONS */ }, 102 { "Debug" , 1 << 17 /*S_ATTR_DEBUG */ }, 103 { "SelfModifyingCode", 1 << 18 /*S_ATTR_SELF_MODIFYING_CODE*/ }, 104 { "LiveSupport" , 1 << 19 /*S_ATTR_LIVE_SUPPORT */ }, 105 { "NoDeadStrip" , 1 << 20 /*S_ATTR_NO_DEAD_STRIP */ }, 106 { "StripStaticSyms" , 1 << 21 /*S_ATTR_STRIP_STATIC_SYMS */ }, 107 { "NoTOC" , 1 << 22 /*S_ATTR_NO_TOC */ }, 108 { "PureInstructions" , 1 << 23 /*S_ATTR_PURE_INSTRUCTIONS */ }, 109}; 110 111static const EnumEntry<unsigned> MachOSymbolRefTypes[] = { 112 { "UndefinedNonLazy", 0 }, 113 { "ReferenceFlagUndefinedLazy", 1 }, 114 { "ReferenceFlagDefined", 2 }, 115 { "ReferenceFlagPrivateDefined", 3 }, 116 { "ReferenceFlagPrivateUndefinedNonLazy", 4 }, 117 { "ReferenceFlagPrivateUndefinedLazy", 5 } 118}; 119 120static const EnumEntry<unsigned> MachOSymbolFlags[] = { 121 { "ReferencedDynamically", 0x10 }, 122 { "NoDeadStrip", 0x20 }, 123 { "WeakRef", 0x40 }, 124 { "WeakDef", 0x80 } 125}; 126 127static const EnumEntry<unsigned> MachOSymbolTypes[] = { 128 { "Undef", 0x0 }, 129 { "External", 0x1 }, 130 { "Abs", 0x2 }, 131 { "Indirect", 0xA }, 132 { "PreboundUndef", 0xC }, 133 { "Section", 0xE }, 134 { "PrivateExternal", 0x10 } 135}; 136 137namespace { 138 enum { 139 N_STAB = 0xE0 140 }; 141 142 struct MachOSection { 143 ArrayRef<char> Name; 144 ArrayRef<char> SegmentName; 145 uint64_t Address; 146 uint64_t Size; 147 uint32_t Offset; 148 uint32_t Alignment; 149 uint32_t RelocationTableOffset; 150 uint32_t NumRelocationTableEntries; 151 uint32_t Flags; 152 uint32_t Reserved1; 153 uint32_t Reserved2; 154 }; 155 156 struct MachOSymbol { 157 uint32_t StringIndex; 158 uint8_t Type; 159 uint8_t SectionIndex; 160 uint16_t Flags; 161 uint64_t Value; 162 }; 163} 164 165static void getSection(const MachOObjectFile *Obj, 166 DataRefImpl Sec, 167 MachOSection &Section) { 168 if (!Obj->is64Bit()) { 169 MachO::section Sect = Obj->getSection(Sec); 170 Section.Address = Sect.addr; 171 Section.Size = Sect.size; 172 Section.Offset = Sect.offset; 173 Section.Alignment = Sect.align; 174 Section.RelocationTableOffset = Sect.reloff; 175 Section.NumRelocationTableEntries = Sect.nreloc; 176 Section.Flags = Sect.flags; 177 Section.Reserved1 = Sect.reserved1; 178 Section.Reserved2 = Sect.reserved2; 179 return; 180 } 181 MachO::section_64 Sect = Obj->getSection64(Sec); 182 Section.Address = Sect.addr; 183 Section.Size = Sect.size; 184 Section.Offset = Sect.offset; 185 Section.Alignment = Sect.align; 186 Section.RelocationTableOffset = Sect.reloff; 187 Section.NumRelocationTableEntries = Sect.nreloc; 188 Section.Flags = Sect.flags; 189 Section.Reserved1 = Sect.reserved1; 190 Section.Reserved2 = Sect.reserved2; 191} 192 193 194static void getSymbol(const MachOObjectFile *Obj, 195 DataRefImpl DRI, 196 MachOSymbol &Symbol) { 197 if (!Obj->is64Bit()) { 198 MachO::nlist Entry = Obj->getSymbolTableEntry(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 return; 205 } 206 MachO::nlist_64 Entry = Obj->getSymbol64TableEntry(DRI); 207 Symbol.StringIndex = Entry.n_strx; 208 Symbol.Type = Entry.n_type; 209 Symbol.SectionIndex = Entry.n_sect; 210 Symbol.Flags = Entry.n_desc; 211 Symbol.Value = Entry.n_value; 212} 213 214void MachODumper::printFileHeaders() { 215 W.startLine() << "FileHeaders not implemented.\n"; 216} 217 218void MachODumper::printSections() { 219 return printSections(Obj); 220} 221 222void MachODumper::printSections(const MachOObjectFile *Obj) { 223 ListScope Group(W, "Sections"); 224 225 int SectionIndex = -1; 226 error_code EC; 227 for (section_iterator SecI = Obj->begin_sections(), 228 SecE = Obj->end_sections(); 229 SecI != SecE; SecI.increment(EC)) { 230 if (error(EC)) break; 231 232 ++SectionIndex; 233 234 MachOSection Section; 235 getSection(Obj, SecI->getRawDataRefImpl(), Section); 236 DataRefImpl DR = SecI->getRawDataRefImpl(); 237 238 StringRef Name; 239 if (error(SecI->getName(Name))) 240 Name = ""; 241 242 ArrayRef<char> RawName = Obj->getSectionRawName(DR); 243 StringRef SegmentName = Obj->getSectionFinalSegmentName(DR); 244 ArrayRef<char> RawSegmentName = Obj->getSectionRawFinalSegmentName(DR); 245 246 DictScope SectionD(W, "Section"); 247 W.printNumber("Index", SectionIndex); 248 W.printBinary("Name", Name, RawName); 249 W.printBinary("Segment", SegmentName, RawSegmentName); 250 W.printHex ("Address", Section.Address); 251 W.printHex ("Size", Section.Size); 252 W.printNumber("Offset", Section.Offset); 253 W.printNumber("Alignment", Section.Alignment); 254 W.printHex ("RelocationOffset", Section.RelocationTableOffset); 255 W.printNumber("RelocationCount", Section.NumRelocationTableEntries); 256 W.printEnum ("Type", Section.Flags & 0xFF, 257 makeArrayRef(MachOSectionAttributes)); 258 W.printFlags ("Attributes", Section.Flags >> 8, 259 makeArrayRef(MachOSectionAttributes)); 260 W.printHex ("Reserved1", Section.Reserved1); 261 W.printHex ("Reserved2", Section.Reserved2); 262 263 if (opts::SectionRelocations) { 264 ListScope D(W, "Relocations"); 265 for (relocation_iterator RelI = SecI->begin_relocations(), 266 RelE = SecI->end_relocations(); 267 RelI != RelE; RelI.increment(EC)) { 268 if (error(EC)) break; 269 270 printRelocation(SecI, RelI); 271 } 272 } 273 274 if (opts::SectionSymbols) { 275 ListScope D(W, "Symbols"); 276 for (symbol_iterator SymI = Obj->begin_symbols(), 277 SymE = Obj->end_symbols(); 278 SymI != SymE; SymI.increment(EC)) { 279 if (error(EC)) break; 280 281 bool Contained = false; 282 if (SecI->containsSymbol(*SymI, Contained) || !Contained) 283 continue; 284 285 printSymbol(SymI); 286 } 287 } 288 289 if (opts::SectionData) { 290 StringRef Data; 291 if (error(SecI->getContents(Data))) break; 292 293 W.printBinaryBlock("SectionData", Data); 294 } 295 } 296} 297 298void MachODumper::printRelocations() { 299 ListScope D(W, "Relocations"); 300 301 error_code EC; 302 for (section_iterator SecI = Obj->begin_sections(), 303 SecE = Obj->end_sections(); 304 SecI != SecE; SecI.increment(EC)) { 305 if (error(EC)) break; 306 307 StringRef Name; 308 if (error(SecI->getName(Name))) 309 continue; 310 311 bool PrintedGroup = false; 312 for (relocation_iterator RelI = SecI->begin_relocations(), 313 RelE = SecI->end_relocations(); 314 RelI != RelE; RelI.increment(EC)) { 315 if (error(EC)) break; 316 317 if (!PrintedGroup) { 318 W.startLine() << "Section " << Name << " {\n"; 319 W.indent(); 320 PrintedGroup = true; 321 } 322 323 printRelocation(SecI, RelI); 324 } 325 326 if (PrintedGroup) { 327 W.unindent(); 328 W.startLine() << "}\n"; 329 } 330 } 331} 332 333void MachODumper::printRelocation(section_iterator SecI, 334 relocation_iterator RelI) { 335 return printRelocation(Obj, SecI, RelI); 336} 337 338void MachODumper::printRelocation(const MachOObjectFile *Obj, 339 section_iterator SecI, 340 relocation_iterator RelI) { 341 uint64_t Offset; 342 SmallString<32> RelocName; 343 StringRef SymbolName; 344 if (error(RelI->getOffset(Offset))) return; 345 if (error(RelI->getTypeName(RelocName))) return; 346 symbol_iterator Symbol = RelI->getSymbol(); 347 if (Symbol != Obj->end_symbols() && 348 error(Symbol->getName(SymbolName))) 349 return; 350 351 DataRefImpl DR = RelI->getRawDataRefImpl(); 352 MachO::any_relocation_info RE = Obj->getRelocation(DR); 353 bool IsScattered = Obj->isRelocationScattered(RE); 354 355 if (opts::ExpandRelocs) { 356 DictScope Group(W, "Relocation"); 357 W.printHex("Offset", Offset); 358 W.printNumber("PCRel", Obj->getAnyRelocationPCRel(RE)); 359 W.printNumber("Length", Obj->getAnyRelocationLength(RE)); 360 if (IsScattered) 361 W.printString("Extern", StringRef("N/A")); 362 else 363 W.printNumber("Extern", Obj->getPlainRelocationExternal(RE)); 364 W.printNumber("Type", RelocName, Obj->getAnyRelocationType(RE)); 365 W.printString("Symbol", SymbolName.size() > 0 ? SymbolName : "-"); 366 W.printNumber("Scattered", IsScattered); 367 } else { 368 raw_ostream& OS = W.startLine(); 369 OS << W.hex(Offset) 370 << " " << Obj->getAnyRelocationPCRel(RE) 371 << " " << Obj->getAnyRelocationLength(RE); 372 if (IsScattered) 373 OS << " n/a"; 374 else 375 OS << " " << Obj->getPlainRelocationExternal(RE); 376 OS << " " << RelocName 377 << " " << IsScattered 378 << " " << (SymbolName.size() > 0 ? SymbolName : "-") 379 << "\n"; 380 } 381} 382 383void MachODumper::printSymbols() { 384 ListScope Group(W, "Symbols"); 385 386 error_code EC; 387 for (symbol_iterator SymI = Obj->begin_symbols(), 388 SymE = Obj->end_symbols(); 389 SymI != SymE; SymI.increment(EC)) { 390 if (error(EC)) break; 391 392 printSymbol(SymI); 393 } 394} 395 396void MachODumper::printDynamicSymbols() { 397 ListScope Group(W, "DynamicSymbols"); 398} 399 400void MachODumper::printSymbol(symbol_iterator SymI) { 401 StringRef SymbolName; 402 if (SymI->getName(SymbolName)) 403 SymbolName = ""; 404 405 MachOSymbol Symbol; 406 getSymbol(Obj, SymI->getRawDataRefImpl(), Symbol); 407 408 StringRef SectionName = ""; 409 section_iterator SecI(Obj->end_sections()); 410 if (!error(SymI->getSection(SecI)) && 411 SecI != Obj->end_sections()) 412 error(SecI->getName(SectionName)); 413 414 DictScope D(W, "Symbol"); 415 W.printNumber("Name", SymbolName, Symbol.StringIndex); 416 if (Symbol.Type & N_STAB) { 417 W.printHex ("Type", "SymDebugTable", Symbol.Type); 418 } else { 419 W.printEnum("Type", Symbol.Type, makeArrayRef(MachOSymbolTypes)); 420 } 421 W.printHex ("Section", SectionName, Symbol.SectionIndex); 422 W.printEnum ("RefType", static_cast<uint16_t>(Symbol.Flags & 0xF), 423 makeArrayRef(MachOSymbolRefTypes)); 424 W.printFlags ("Flags", static_cast<uint16_t>(Symbol.Flags & ~0xF), 425 makeArrayRef(MachOSymbolFlags)); 426 W.printHex ("Value", Symbol.Value); 427} 428 429void MachODumper::printUnwindInfo() { 430 W.startLine() << "UnwindInfo not implemented.\n"; 431} 432