1 //===-- macho-dump.cpp - Mach Object Dumping Tool -------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This is a testing tool for use with the MC/Mach-O LLVM components.
12 //===----------------------------------------------------------------------===//
14 #include "llvm/Object/MachOObject.h"
15 #include "llvm/ADT/StringExtras.h"
16 #include "llvm/ADT/Twine.h"
17 #include "llvm/Support/CommandLine.h"
18 #include "llvm/Support/Format.h"
19 #include "llvm/Support/ManagedStatic.h"
20 #include "llvm/Support/MemoryBuffer.h"
21 #include "llvm/Support/raw_ostream.h"
22 #include "llvm/Support/system_error.h"
24 using namespace llvm::object
;
26 static cl::opt
<std::string
>
27 InputFile(cl::Positional
, cl::desc("<input file>"), cl::init("-"));
30 ShowSectionData("dump-section-data", cl::desc("Dump the contents of sections"),
35 static const char *ProgramName
;
37 static void Message(const char *Type
, const Twine
&Msg
) {
38 errs() << ProgramName
<< ": " << Type
<< ": " << Msg
<< "\n";
41 static int Error(const Twine
&Msg
) {
42 Message("error", Msg
);
46 static void Warning(const Twine
&Msg
) {
47 Message("warning", Msg
);
52 static int DumpHeader(MachOObject
&Obj
) {
54 const macho::Header
&Hdr
= Obj
.getHeader();
55 outs() << "('cputype', " << Hdr
.CPUType
<< ")\n";
56 outs() << "('cpusubtype', " << Hdr
.CPUSubtype
<< ")\n";
57 outs() << "('filetype', " << Hdr
.FileType
<< ")\n";
58 outs() << "('num_load_commands', " << Hdr
.NumLoadCommands
<< ")\n";
59 outs() << "('load_commands_size', " << Hdr
.SizeOfLoadCommands
<< ")\n";
60 outs() << "('flag', " << Hdr
.Flags
<< ")\n";
62 // Print extended header if 64-bit.
64 const macho::Header64Ext
&Hdr64
= Obj
.getHeader64Ext();
65 outs() << "('reserved', " << Hdr64
.Reserved
<< ")\n";
71 static void DumpSegmentCommandData(StringRef Name
,
72 uint64_t VMAddr
, uint64_t VMSize
,
73 uint64_t FileOffset
, uint64_t FileSize
,
74 uint32_t MaxProt
, uint32_t InitProt
,
75 uint32_t NumSections
, uint32_t Flags
) {
76 outs() << " ('segment_name', '";
77 outs().write_escaped(Name
, /*UseHexEscapes=*/true) << "')\n";
78 outs() << " ('vm_addr', " << VMAddr
<< ")\n";
79 outs() << " ('vm_size', " << VMSize
<< ")\n";
80 outs() << " ('file_offset', " << FileOffset
<< ")\n";
81 outs() << " ('file_size', " << FileSize
<< ")\n";
82 outs() << " ('maxprot', " << MaxProt
<< ")\n";
83 outs() << " ('initprot', " << InitProt
<< ")\n";
84 outs() << " ('num_sections', " << NumSections
<< ")\n";
85 outs() << " ('flags', " << Flags
<< ")\n";
88 static int DumpSectionData(MachOObject
&Obj
, unsigned Index
, StringRef Name
,
89 StringRef SegmentName
, uint64_t Address
,
90 uint64_t Size
, uint32_t Offset
,
91 uint32_t Align
, uint32_t RelocationTableOffset
,
92 uint32_t NumRelocationTableEntries
,
93 uint32_t Flags
, uint32_t Reserved1
,
94 uint32_t Reserved2
, uint64_t Reserved3
= ~0ULL) {
95 outs() << " # Section " << Index
<< "\n";
96 outs() << " (('section_name', '";
97 outs().write_escaped(Name
, /*UseHexEscapes=*/true) << "')\n";
98 outs() << " ('segment_name', '";
99 outs().write_escaped(SegmentName
, /*UseHexEscapes=*/true) << "')\n";
100 outs() << " ('address', " << Address
<< ")\n";
101 outs() << " ('size', " << Size
<< ")\n";
102 outs() << " ('offset', " << Offset
<< ")\n";
103 outs() << " ('alignment', " << Align
<< ")\n";
104 outs() << " ('reloc_offset', " << RelocationTableOffset
<< ")\n";
105 outs() << " ('num_reloc', " << NumRelocationTableEntries
<< ")\n";
106 outs() << " ('flags', " << format("0x%x", Flags
) << ")\n";
107 outs() << " ('reserved1', " << Reserved1
<< ")\n";
108 outs() << " ('reserved2', " << Reserved2
<< ")\n";
109 if (Reserved3
!= ~0ULL)
110 outs() << " ('reserved3', " << Reserved3
<< ")\n";
113 // Dump the relocation entries.
115 outs() << " ('_relocations', [\n";
116 for (unsigned i
= 0; i
!= NumRelocationTableEntries
; ++i
) {
117 InMemoryStruct
<macho::RelocationEntry
> RE
;
118 Obj
.ReadRelocationEntry(RelocationTableOffset
, i
, RE
);
120 Res
= Error("unable to read relocation table entry '" + Twine(i
) + "'");
124 outs() << " # Relocation " << i
<< "\n";
125 outs() << " (('word-0', " << format("0x%x", RE
->Word0
) << "),\n";
126 outs() << " ('word-1', " << format("0x%x", RE
->Word1
) << ")),\n";
130 // Dump the section data, if requested.
131 if (ShowSectionData
) {
132 outs() << " ('_section_data', '";
133 StringRef Data
= Obj
.getData(Offset
, Size
);
134 for (unsigned i
= 0; i
!= Data
.size(); ++i
) {
135 if (i
&& (i
% 4) == 0)
137 outs() << hexdigit((Data
[i
] >> 4) & 0xF, /*LowerCase=*/true);
138 outs() << hexdigit((Data
[i
] >> 0) & 0xF, /*LowerCase=*/true);
146 static int DumpSegmentCommand(MachOObject
&Obj
,
147 const MachOObject::LoadCommandInfo
&LCI
) {
148 InMemoryStruct
<macho::SegmentLoadCommand
> SLC
;
149 Obj
.ReadSegmentLoadCommand(LCI
, SLC
);
151 return Error("unable to read segment load command");
153 DumpSegmentCommandData(StringRef(SLC
->Name
, 16), SLC
->VMAddress
,
154 SLC
->VMSize
, SLC
->FileOffset
, SLC
->FileSize
,
155 SLC
->MaxVMProtection
, SLC
->InitialVMProtection
,
156 SLC
->NumSections
, SLC
->Flags
);
158 // Dump the sections.
160 outs() << " ('sections', [\n";
161 for (unsigned i
= 0; i
!= SLC
->NumSections
; ++i
) {
162 InMemoryStruct
<macho::Section
> Sect
;
163 Obj
.ReadSection(LCI
, i
, Sect
);
165 Res
= Error("unable to read section '" + Twine(i
) + "'");
169 if ((Res
= DumpSectionData(Obj
, i
, StringRef(Sect
->Name
, 16),
170 StringRef(Sect
->SegmentName
, 16), Sect
->Address
,
171 Sect
->Size
, Sect
->Offset
, Sect
->Align
,
172 Sect
->RelocationTableOffset
,
173 Sect
->NumRelocationTableEntries
, Sect
->Flags
,
174 Sect
->Reserved1
, Sect
->Reserved2
)))
182 static int DumpSegment64Command(MachOObject
&Obj
,
183 const MachOObject::LoadCommandInfo
&LCI
) {
184 InMemoryStruct
<macho::Segment64LoadCommand
> SLC
;
185 Obj
.ReadSegment64LoadCommand(LCI
, SLC
);
187 return Error("unable to read segment load command");
189 DumpSegmentCommandData(StringRef(SLC
->Name
, 16), SLC
->VMAddress
,
190 SLC
->VMSize
, SLC
->FileOffset
, SLC
->FileSize
,
191 SLC
->MaxVMProtection
, SLC
->InitialVMProtection
,
192 SLC
->NumSections
, SLC
->Flags
);
194 // Dump the sections.
196 outs() << " ('sections', [\n";
197 for (unsigned i
= 0; i
!= SLC
->NumSections
; ++i
) {
198 InMemoryStruct
<macho::Section64
> Sect
;
199 Obj
.ReadSection64(LCI
, i
, Sect
);
201 Res
= Error("unable to read section '" + Twine(i
) + "'");
205 if ((Res
= DumpSectionData(Obj
, i
, StringRef(Sect
->Name
, 16),
206 StringRef(Sect
->SegmentName
, 16), Sect
->Address
,
207 Sect
->Size
, Sect
->Offset
, Sect
->Align
,
208 Sect
->RelocationTableOffset
,
209 Sect
->NumRelocationTableEntries
, Sect
->Flags
,
210 Sect
->Reserved1
, Sect
->Reserved2
,
219 static void DumpSymbolTableEntryData(MachOObject
&Obj
,
220 unsigned Index
, uint32_t StringIndex
,
221 uint8_t Type
, uint8_t SectionIndex
,
222 uint16_t Flags
, uint64_t Value
) {
223 outs() << " # Symbol " << Index
<< "\n";
224 outs() << " (('n_strx', " << StringIndex
<< ")\n";
225 outs() << " ('n_type', " << format("0x%x", Type
) << ")\n";
226 outs() << " ('n_sect', " << uint32_t(SectionIndex
) << ")\n";
227 outs() << " ('n_desc', " << Flags
<< ")\n";
228 outs() << " ('n_value', " << Value
<< ")\n";
229 outs() << " ('_string', '" << Obj
.getStringAtIndex(StringIndex
) << "')\n";
233 static int DumpSymtabCommand(MachOObject
&Obj
,
234 const MachOObject::LoadCommandInfo
&LCI
) {
235 InMemoryStruct
<macho::SymtabLoadCommand
> SLC
;
236 Obj
.ReadSymtabLoadCommand(LCI
, SLC
);
238 return Error("unable to read segment load command");
240 outs() << " ('symoff', " << SLC
->SymbolTableOffset
<< ")\n";
241 outs() << " ('nsyms', " << SLC
->NumSymbolTableEntries
<< ")\n";
242 outs() << " ('stroff', " << SLC
->StringTableOffset
<< ")\n";
243 outs() << " ('strsize', " << SLC
->StringTableSize
<< ")\n";
245 // Cache the string table data.
246 Obj
.RegisterStringTable(*SLC
);
248 // Dump the string data.
249 outs() << " ('_string_data', '";
250 outs().write_escaped(Obj
.getStringTableData(),
251 /*UseHexEscapes=*/true) << "')\n";
253 // Dump the symbol table.
255 outs() << " ('_symbols', [\n";
256 for (unsigned i
= 0; i
!= SLC
->NumSymbolTableEntries
; ++i
) {
258 InMemoryStruct
<macho::Symbol64TableEntry
> STE
;
259 Obj
.ReadSymbol64TableEntry(SLC
->SymbolTableOffset
, i
, STE
);
261 Res
= Error("unable to read symbol: '" + Twine(i
) + "'");
265 DumpSymbolTableEntryData(Obj
, i
, STE
->StringIndex
, STE
->Type
,
266 STE
->SectionIndex
, STE
->Flags
, STE
->Value
);
268 InMemoryStruct
<macho::SymbolTableEntry
> STE
;
269 Obj
.ReadSymbolTableEntry(SLC
->SymbolTableOffset
, i
, STE
);
271 Res
= Error("unable to read symbol: '" + Twine(i
) + "'");
275 DumpSymbolTableEntryData(Obj
, i
, STE
->StringIndex
, STE
->Type
,
276 STE
->SectionIndex
, STE
->Flags
, STE
->Value
);
284 static int DumpDysymtabCommand(MachOObject
&Obj
,
285 const MachOObject::LoadCommandInfo
&LCI
) {
286 InMemoryStruct
<macho::DysymtabLoadCommand
> DLC
;
287 Obj
.ReadDysymtabLoadCommand(LCI
, DLC
);
289 return Error("unable to read segment load command");
291 outs() << " ('ilocalsym', " << DLC
->LocalSymbolsIndex
<< ")\n";
292 outs() << " ('nlocalsym', " << DLC
->NumLocalSymbols
<< ")\n";
293 outs() << " ('iextdefsym', " << DLC
->ExternalSymbolsIndex
<< ")\n";
294 outs() << " ('nextdefsym', " << DLC
->NumExternalSymbols
<< ")\n";
295 outs() << " ('iundefsym', " << DLC
->UndefinedSymbolsIndex
<< ")\n";
296 outs() << " ('nundefsym', " << DLC
->NumUndefinedSymbols
<< ")\n";
297 outs() << " ('tocoff', " << DLC
->TOCOffset
<< ")\n";
298 outs() << " ('ntoc', " << DLC
->NumTOCEntries
<< ")\n";
299 outs() << " ('modtaboff', " << DLC
->ModuleTableOffset
<< ")\n";
300 outs() << " ('nmodtab', " << DLC
->NumModuleTableEntries
<< ")\n";
301 outs() << " ('extrefsymoff', " << DLC
->ReferenceSymbolTableOffset
<< ")\n";
302 outs() << " ('nextrefsyms', "
303 << DLC
->NumReferencedSymbolTableEntries
<< ")\n";
304 outs() << " ('indirectsymoff', " << DLC
->IndirectSymbolTableOffset
<< ")\n";
305 outs() << " ('nindirectsyms', "
306 << DLC
->NumIndirectSymbolTableEntries
<< ")\n";
307 outs() << " ('extreloff', " << DLC
->ExternalRelocationTableOffset
<< ")\n";
308 outs() << " ('nextrel', " << DLC
->NumExternalRelocationTableEntries
<< ")\n";
309 outs() << " ('locreloff', " << DLC
->LocalRelocationTableOffset
<< ")\n";
310 outs() << " ('nlocrel', " << DLC
->NumLocalRelocationTableEntries
<< ")\n";
312 // Dump the indirect symbol table.
314 outs() << " ('_indirect_symbols', [\n";
315 for (unsigned i
= 0; i
!= DLC
->NumIndirectSymbolTableEntries
; ++i
) {
316 InMemoryStruct
<macho::IndirectSymbolTableEntry
> ISTE
;
317 Obj
.ReadIndirectSymbolTableEntry(*DLC
, i
, ISTE
);
319 Res
= Error("unable to read segment load command");
323 outs() << " # Indirect Symbol " << i
<< "\n";
324 outs() << " (('symbol_index', "
325 << format("0x%x", ISTE
->Index
) << "),),\n";
332 static int DumpLoadCommand(MachOObject
&Obj
, unsigned Index
) {
333 const MachOObject::LoadCommandInfo
&LCI
= Obj
.getLoadCommandInfo(Index
);
336 outs() << " # Load Command " << Index
<< "\n"
337 << " (('command', " << LCI
.Command
.Type
<< ")\n"
338 << " ('size', " << LCI
.Command
.Size
<< ")\n";
339 switch (LCI
.Command
.Type
) {
340 case macho::LCT_Segment
:
341 Res
= DumpSegmentCommand(Obj
, LCI
);
343 case macho::LCT_Segment64
:
344 Res
= DumpSegment64Command(Obj
, LCI
);
346 case macho::LCT_Symtab
:
347 Res
= DumpSymtabCommand(Obj
, LCI
);
349 case macho::LCT_Dysymtab
:
350 Res
= DumpDysymtabCommand(Obj
, LCI
);
353 Warning("unknown load command: " + Twine(LCI
.Command
.Type
));
361 int main(int argc
, char **argv
) {
362 ProgramName
= argv
[0];
363 llvm_shutdown_obj Y
; // Call llvm_shutdown() on exit.
365 cl::ParseCommandLineOptions(argc
, argv
, "llvm Mach-O dumping tool\n");
367 // Load the input file.
368 std::string ErrorStr
;
369 OwningPtr
<MemoryBuffer
> InputBuffer
;
370 if (error_code ec
= MemoryBuffer::getFileOrSTDIN(InputFile
, InputBuffer
))
371 return Error("unable to read input: '" + ec
.message() + "'");
373 // Construct the Mach-O wrapper object.
374 OwningPtr
<MachOObject
> InputObject(
375 MachOObject::LoadFromBuffer(InputBuffer
.take(), &ErrorStr
));
377 return Error("unable to load object: '" + ErrorStr
+ "'");
379 if (int Res
= DumpHeader(*InputObject
))
382 // Print the load commands.
384 outs() << "('load_commands', [\n";
385 for (unsigned i
= 0; i
!= InputObject
->getHeader().NumLoadCommands
; ++i
)
386 if ((Res
= DumpLoadCommand(*InputObject
, i
)))