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 void DumpSegmentCommandData(StringRef Name
,
53 uint64_t VMAddr
, uint64_t VMSize
,
54 uint64_t FileOffset
, uint64_t FileSize
,
55 uint32_t MaxProt
, uint32_t InitProt
,
56 uint32_t NumSections
, uint32_t Flags
) {
57 outs() << " ('segment_name', '";
58 outs().write_escaped(Name
, /*UseHexEscapes=*/true) << "')\n";
59 outs() << " ('vm_addr', " << VMAddr
<< ")\n";
60 outs() << " ('vm_size', " << VMSize
<< ")\n";
61 outs() << " ('file_offset', " << FileOffset
<< ")\n";
62 outs() << " ('file_size', " << FileSize
<< ")\n";
63 outs() << " ('maxprot', " << MaxProt
<< ")\n";
64 outs() << " ('initprot', " << InitProt
<< ")\n";
65 outs() << " ('num_sections', " << NumSections
<< ")\n";
66 outs() << " ('flags', " << Flags
<< ")\n";
69 static int DumpSectionData(MachOObject
&Obj
, unsigned Index
, StringRef Name
,
70 StringRef SegmentName
, uint64_t Address
,
71 uint64_t Size
, uint32_t Offset
,
72 uint32_t Align
, uint32_t RelocationTableOffset
,
73 uint32_t NumRelocationTableEntries
,
74 uint32_t Flags
, uint32_t Reserved1
,
75 uint32_t Reserved2
, uint64_t Reserved3
= ~0ULL) {
76 outs() << " # Section " << Index
<< "\n";
77 outs() << " (('section_name', '";
78 outs().write_escaped(Name
, /*UseHexEscapes=*/true) << "')\n";
79 outs() << " ('segment_name', '";
80 outs().write_escaped(SegmentName
, /*UseHexEscapes=*/true) << "')\n";
81 outs() << " ('address', " << Address
<< ")\n";
82 outs() << " ('size', " << Size
<< ")\n";
83 outs() << " ('offset', " << Offset
<< ")\n";
84 outs() << " ('alignment', " << Align
<< ")\n";
85 outs() << " ('reloc_offset', " << RelocationTableOffset
<< ")\n";
86 outs() << " ('num_reloc', " << NumRelocationTableEntries
<< ")\n";
87 outs() << " ('flags', " << format("0x%x", Flags
) << ")\n";
88 outs() << " ('reserved1', " << Reserved1
<< ")\n";
89 outs() << " ('reserved2', " << Reserved2
<< ")\n";
90 if (Reserved3
!= ~0ULL)
91 outs() << " ('reserved3', " << Reserved3
<< ")\n";
94 // Dump the relocation entries.
96 outs() << " ('_relocations', [\n";
97 for (unsigned i
= 0; i
!= NumRelocationTableEntries
; ++i
) {
98 InMemoryStruct
<macho::RelocationEntry
> RE
;
99 Obj
.ReadRelocationEntry(RelocationTableOffset
, i
, RE
);
101 Res
= Error("unable to read relocation table entry '" + Twine(i
) + "'");
105 outs() << " # Relocation " << i
<< "\n";
106 outs() << " (('word-0', " << format("0x%x", RE
->Word0
) << "),\n";
107 outs() << " ('word-1', " << format("0x%x", RE
->Word1
) << ")),\n";
111 // Dump the section data, if requested.
112 if (ShowSectionData
) {
113 outs() << " ('_section_data', '";
114 StringRef Data
= Obj
.getData(Offset
, Size
);
115 for (unsigned i
= 0; i
!= Data
.size(); ++i
) {
116 if (i
&& (i
% 4) == 0)
118 outs() << hexdigit((Data
[i
] >> 4) & 0xF, /*LowerCase=*/true);
119 outs() << hexdigit((Data
[i
] >> 0) & 0xF, /*LowerCase=*/true);
127 static int DumpSegmentCommand(MachOObject
&Obj
,
128 const MachOObject::LoadCommandInfo
&LCI
) {
129 InMemoryStruct
<macho::SegmentLoadCommand
> SLC
;
130 Obj
.ReadSegmentLoadCommand(LCI
, SLC
);
132 return Error("unable to read segment load command");
134 DumpSegmentCommandData(StringRef(SLC
->Name
, 16), SLC
->VMAddress
,
135 SLC
->VMSize
, SLC
->FileOffset
, SLC
->FileSize
,
136 SLC
->MaxVMProtection
, SLC
->InitialVMProtection
,
137 SLC
->NumSections
, SLC
->Flags
);
139 // Dump the sections.
141 outs() << " ('sections', [\n";
142 for (unsigned i
= 0; i
!= SLC
->NumSections
; ++i
) {
143 InMemoryStruct
<macho::Section
> Sect
;
144 Obj
.ReadSection(LCI
, i
, Sect
);
146 Res
= Error("unable to read section '" + Twine(i
) + "'");
150 if ((Res
= DumpSectionData(Obj
, i
, StringRef(Sect
->Name
, 16),
151 StringRef(Sect
->SegmentName
, 16), Sect
->Address
,
152 Sect
->Size
, Sect
->Offset
, Sect
->Align
,
153 Sect
->RelocationTableOffset
,
154 Sect
->NumRelocationTableEntries
, Sect
->Flags
,
155 Sect
->Reserved1
, Sect
->Reserved2
)))
163 static int DumpSegment64Command(MachOObject
&Obj
,
164 const MachOObject::LoadCommandInfo
&LCI
) {
165 InMemoryStruct
<macho::Segment64LoadCommand
> SLC
;
166 Obj
.ReadSegment64LoadCommand(LCI
, SLC
);
168 return Error("unable to read segment load command");
170 DumpSegmentCommandData(StringRef(SLC
->Name
, 16), SLC
->VMAddress
,
171 SLC
->VMSize
, SLC
->FileOffset
, SLC
->FileSize
,
172 SLC
->MaxVMProtection
, SLC
->InitialVMProtection
,
173 SLC
->NumSections
, SLC
->Flags
);
175 // Dump the sections.
177 outs() << " ('sections', [\n";
178 for (unsigned i
= 0; i
!= SLC
->NumSections
; ++i
) {
179 InMemoryStruct
<macho::Section64
> Sect
;
180 Obj
.ReadSection64(LCI
, i
, Sect
);
182 Res
= Error("unable to read section '" + Twine(i
) + "'");
186 if ((Res
= DumpSectionData(Obj
, i
, StringRef(Sect
->Name
, 16),
187 StringRef(Sect
->SegmentName
, 16), Sect
->Address
,
188 Sect
->Size
, Sect
->Offset
, Sect
->Align
,
189 Sect
->RelocationTableOffset
,
190 Sect
->NumRelocationTableEntries
, Sect
->Flags
,
191 Sect
->Reserved1
, Sect
->Reserved2
,
200 static void DumpSymbolTableEntryData(MachOObject
&Obj
,
201 unsigned Index
, uint32_t StringIndex
,
202 uint8_t Type
, uint8_t SectionIndex
,
203 uint16_t Flags
, uint64_t Value
) {
204 outs() << " # Symbol " << Index
<< "\n";
205 outs() << " (('n_strx', " << StringIndex
<< ")\n";
206 outs() << " ('n_type', " << format("0x%x", Type
) << ")\n";
207 outs() << " ('n_sect', " << uint32_t(SectionIndex
) << ")\n";
208 outs() << " ('n_desc', " << Flags
<< ")\n";
209 outs() << " ('n_value', " << Value
<< ")\n";
210 outs() << " ('_string', '" << Obj
.getStringAtIndex(StringIndex
) << "')\n";
214 static int DumpSymtabCommand(MachOObject
&Obj
,
215 const MachOObject::LoadCommandInfo
&LCI
) {
216 InMemoryStruct
<macho::SymtabLoadCommand
> SLC
;
217 Obj
.ReadSymtabLoadCommand(LCI
, SLC
);
219 return Error("unable to read segment load command");
221 outs() << " ('symoff', " << SLC
->SymbolTableOffset
<< ")\n";
222 outs() << " ('nsyms', " << SLC
->NumSymbolTableEntries
<< ")\n";
223 outs() << " ('stroff', " << SLC
->StringTableOffset
<< ")\n";
224 outs() << " ('strsize', " << SLC
->StringTableSize
<< ")\n";
226 // Cache the string table data.
227 Obj
.RegisterStringTable(*SLC
);
229 // Dump the string data.
230 outs() << " ('_string_data', '";
231 outs().write_escaped(Obj
.getStringTableData(),
232 /*UseHexEscapes=*/true) << "')\n";
234 // Dump the symbol table.
236 outs() << " ('_symbols', [\n";
237 for (unsigned i
= 0; i
!= SLC
->NumSymbolTableEntries
; ++i
) {
239 InMemoryStruct
<macho::Symbol64TableEntry
> STE
;
240 Obj
.ReadSymbol64TableEntry(SLC
->SymbolTableOffset
, i
, STE
);
242 Res
= Error("unable to read symbol: '" + Twine(i
) + "'");
246 DumpSymbolTableEntryData(Obj
, i
, STE
->StringIndex
, STE
->Type
,
247 STE
->SectionIndex
, STE
->Flags
, STE
->Value
);
249 InMemoryStruct
<macho::SymbolTableEntry
> STE
;
250 Obj
.ReadSymbolTableEntry(SLC
->SymbolTableOffset
, i
, STE
);
252 Res
= Error("unable to read symbol: '" + Twine(i
) + "'");
256 DumpSymbolTableEntryData(Obj
, i
, STE
->StringIndex
, STE
->Type
,
257 STE
->SectionIndex
, STE
->Flags
, STE
->Value
);
265 static int DumpDysymtabCommand(MachOObject
&Obj
,
266 const MachOObject::LoadCommandInfo
&LCI
) {
267 InMemoryStruct
<macho::DysymtabLoadCommand
> DLC
;
268 Obj
.ReadDysymtabLoadCommand(LCI
, DLC
);
270 return Error("unable to read segment load command");
272 outs() << " ('ilocalsym', " << DLC
->LocalSymbolsIndex
<< ")\n";
273 outs() << " ('nlocalsym', " << DLC
->NumLocalSymbols
<< ")\n";
274 outs() << " ('iextdefsym', " << DLC
->ExternalSymbolsIndex
<< ")\n";
275 outs() << " ('nextdefsym', " << DLC
->NumExternalSymbols
<< ")\n";
276 outs() << " ('iundefsym', " << DLC
->UndefinedSymbolsIndex
<< ")\n";
277 outs() << " ('nundefsym', " << DLC
->NumUndefinedSymbols
<< ")\n";
278 outs() << " ('tocoff', " << DLC
->TOCOffset
<< ")\n";
279 outs() << " ('ntoc', " << DLC
->NumTOCEntries
<< ")\n";
280 outs() << " ('modtaboff', " << DLC
->ModuleTableOffset
<< ")\n";
281 outs() << " ('nmodtab', " << DLC
->NumModuleTableEntries
<< ")\n";
282 outs() << " ('extrefsymoff', " << DLC
->ReferenceSymbolTableOffset
<< ")\n";
283 outs() << " ('nextrefsyms', "
284 << DLC
->NumReferencedSymbolTableEntries
<< ")\n";
285 outs() << " ('indirectsymoff', " << DLC
->IndirectSymbolTableOffset
<< ")\n";
286 outs() << " ('nindirectsyms', "
287 << DLC
->NumIndirectSymbolTableEntries
<< ")\n";
288 outs() << " ('extreloff', " << DLC
->ExternalRelocationTableOffset
<< ")\n";
289 outs() << " ('nextrel', " << DLC
->NumExternalRelocationTableEntries
<< ")\n";
290 outs() << " ('locreloff', " << DLC
->LocalRelocationTableOffset
<< ")\n";
291 outs() << " ('nlocrel', " << DLC
->NumLocalRelocationTableEntries
<< ")\n";
293 // Dump the indirect symbol table.
295 outs() << " ('_indirect_symbols', [\n";
296 for (unsigned i
= 0; i
!= DLC
->NumIndirectSymbolTableEntries
; ++i
) {
297 InMemoryStruct
<macho::IndirectSymbolTableEntry
> ISTE
;
298 Obj
.ReadIndirectSymbolTableEntry(*DLC
, i
, ISTE
);
300 Res
= Error("unable to read segment load command");
304 outs() << " # Indirect Symbol " << i
<< "\n";
305 outs() << " (('symbol_index', "
306 << format("0x%x", ISTE
->Index
) << "),),\n";
313 static int DumpLoadCommand(MachOObject
&Obj
, unsigned Index
) {
314 const MachOObject::LoadCommandInfo
&LCI
= Obj
.getLoadCommandInfo(Index
);
317 outs() << " # Load Command " << Index
<< "\n"
318 << " (('command', " << LCI
.Command
.Type
<< ")\n"
319 << " ('size', " << LCI
.Command
.Size
<< ")\n";
320 switch (LCI
.Command
.Type
) {
321 case macho::LCT_Segment
:
322 Res
= DumpSegmentCommand(Obj
, LCI
);
324 case macho::LCT_Segment64
:
325 Res
= DumpSegment64Command(Obj
, LCI
);
327 case macho::LCT_Symtab
:
328 Res
= DumpSymtabCommand(Obj
, LCI
);
330 case macho::LCT_Dysymtab
:
331 Res
= DumpDysymtabCommand(Obj
, LCI
);
334 Warning("unknown load command: " + Twine(LCI
.Command
.Type
));
342 int main(int argc
, char **argv
) {
343 ProgramName
= argv
[0];
344 llvm_shutdown_obj Y
; // Call llvm_shutdown() on exit.
346 cl::ParseCommandLineOptions(argc
, argv
, "llvm Mach-O dumping tool\n");
348 // Load the input file.
349 std::string ErrorStr
;
350 OwningPtr
<MemoryBuffer
> InputBuffer
;
351 if (error_code ec
= MemoryBuffer::getFileOrSTDIN(InputFile
, InputBuffer
))
352 return Error("unable to read input: '" + ec
.message() + "'");
354 // Construct the Mach-O wrapper object.
355 OwningPtr
<MachOObject
> InputObject(
356 MachOObject::LoadFromBuffer(InputBuffer
.take(), &ErrorStr
));
358 return Error("unable to load object: '" + ErrorStr
+ "'");
361 InputObject
->printHeader(outs());
363 // Print the load commands.
365 outs() << "('load_commands', [\n";
366 for (unsigned i
= 0; i
!= InputObject
->getHeader().NumLoadCommands
; ++i
)
367 if ((Res
= DumpLoadCommand(*InputObject
, i
)))