#include "llvm-objdump.h"
#include "llvm-c/Disassembler.h"
+#include "llvm/ADT/Optional.h"
#include "llvm/ADT/STLExtras.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/ADT/Triple.h"
double d) {
outs() << format("0x%08" PRIx32, l0) << " " << format("0x%08" PRIx32, l1);
uint32_t Hi, Lo;
- if (O->isLittleEndian()) {
- Hi = l1;
- Lo = l0;
- } else {
- Hi = l0;
- Lo = l1;
- }
+ Hi = (O->isLittleEndian()) ? l1 : l0;
+ Lo = (O->isLittleEndian()) ? l0 : l1;
+
// Hi is the high word, so this is equivalent to if(isfinite(d))
if ((Hi & 0x7ff00000) != 0x7ff00000)
outs() << format(" (%.16e)\n", d);
SymbolAddressMap *AddrMap,
bool verbose) {
uint32_t stride;
- if (O->is64Bit())
- stride = sizeof(uint64_t);
- else
- stride = sizeof(uint32_t);
+ stride = (O->is64Bit()) ? sizeof(uint64_t) : sizeof(uint32_t);
for (uint32_t i = 0; i < sect_size; i += stride) {
const char *SymbolName = nullptr;
if (O->is64Bit()) {
PrintSymbolTable(MachOOF);
if (UnwindInfo)
printMachOUnwindInfo(MachOOF);
- if (PrivateHeaders)
+ if (PrivateHeaders) {
+ printMachOFileHeader(MachOOF);
+ printMachOLoadCommands(MachOOF);
+ }
+ if (FirstPrivateHeader)
printMachOFileHeader(MachOOF);
if (ObjcMetaData)
printObjcMetaData(MachOOF, !NonVerbose);
// Attempt to open the binary.
ErrorOr<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename);
- if (std::error_code EC = BinaryOrErr.getError()) {
- errs() << "llvm-objdump: '" << Filename << "': " << EC.message() << ".\n";
- return;
- }
+ if (std::error_code EC = BinaryOrErr.getError())
+ report_error(Filename, EC);
Binary &Bin = *BinaryOrErr.get().getBinary();
if (Archive *A = dyn_cast<Archive>(&Bin)) {
printArchiveHeaders(A, !NonVerbose, ArchiveMemberOffsets);
for (Archive::child_iterator I = A->child_begin(), E = A->child_end();
I != E; ++I) {
- if (std::error_code EC = I->getError()) {
- errs() << "llvm-objdump: '" << Filename << "': " << EC.message()
- << ".\n";
- exit(1);
- }
+ if (std::error_code EC = I->getError())
+ report_error(Filename, EC);
auto &C = I->get();
ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
if (ChildOrErr.getError())
for (Archive::child_iterator AI = A->child_begin(),
AE = A->child_end();
AI != AE; ++AI) {
- if (std::error_code EC = AI->getError()) {
- errs() << "llvm-objdump: '" << Filename
- << "': " << EC.message() << ".\n";
- exit(1);
- }
+ if (std::error_code EC = AI->getError())
+ report_error(Filename, EC);
auto &C = AI->get();
ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
if (ChildOrErr.getError())
for (Archive::child_iterator AI = A->child_begin(),
AE = A->child_end();
AI != AE; ++AI) {
- if (std::error_code EC = AI->getError()) {
- errs() << "llvm-objdump: '" << Filename << "': " << EC.message()
- << ".\n";
- exit(1);
- }
+ if (std::error_code EC = AI->getError())
+ report_error(Filename, EC);
auto &C = AI->get();
ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
if (ChildOrErr.getError())
printArchiveHeaders(A.get(), !NonVerbose, ArchiveMemberOffsets);
for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end();
AI != AE; ++AI) {
- if (std::error_code EC = AI->getError()) {
- errs() << "llvm-objdump: '" << Filename << "': " << EC.message()
- << ".\n";
- exit(1);
- }
+ if (std::error_code EC = AI->getError())
+ report_error(Filename, EC);
auto &C = AI->get();
ErrorOr<std::unique_ptr<Binary>> ChildOrErr = C.getAsBinary();
if (ChildOrErr.getError())
} else
errs() << "llvm-objdump: '" << Filename << "': "
<< "Object is not a Mach-O file type.\n";
- } else
- errs() << "llvm-objdump: '" << Filename << "': "
- << "Unrecognized file type.\n";
+ return;
+ }
+ llvm_unreachable("Input object can't be invalid at this point");
}
typedef std::pair<uint64_t, const char *> BindInfoEntry;
info.adrp_inst = 0;
info.depth = 0;
- const SectionRef CL = get_section(O, "__OBJC2", "__class_list");
- if (CL != SectionRef()) {
- info.S = CL;
- walk_pointer_list_64("class", CL, O, &info, print_class64_t);
- } else {
- const SectionRef CL = get_section(O, "__DATA", "__objc_classlist");
- info.S = CL;
- walk_pointer_list_64("class", CL, O, &info, print_class64_t);
- }
-
- const SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
- if (CR != SectionRef()) {
- info.S = CR;
- walk_pointer_list_64("class refs", CR, O, &info, nullptr);
- } else {
- const SectionRef CR = get_section(O, "__DATA", "__objc_classrefs");
- info.S = CR;
- walk_pointer_list_64("class refs", CR, O, &info, nullptr);
- }
-
- const SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
- if (SR != SectionRef()) {
- info.S = SR;
- walk_pointer_list_64("super refs", SR, O, &info, nullptr);
- } else {
- const SectionRef SR = get_section(O, "__DATA", "__objc_superrefs");
- info.S = SR;
- walk_pointer_list_64("super refs", SR, O, &info, nullptr);
- }
-
- const SectionRef CA = get_section(O, "__OBJC2", "__category_list");
- if (CA != SectionRef()) {
- info.S = CA;
- walk_pointer_list_64("category", CA, O, &info, print_category64_t);
- } else {
- const SectionRef CA = get_section(O, "__DATA", "__objc_catlist");
- info.S = CA;
- walk_pointer_list_64("category", CA, O, &info, print_category64_t);
- }
-
- const SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
- if (PL != SectionRef()) {
- info.S = PL;
- walk_pointer_list_64("protocol", PL, O, &info, nullptr);
- } else {
- const SectionRef PL = get_section(O, "__DATA", "__objc_protolist");
- info.S = PL;
- walk_pointer_list_64("protocol", PL, O, &info, nullptr);
- }
-
- const SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
- if (MR != SectionRef()) {
- info.S = MR;
- print_message_refs64(MR, &info);
- } else {
- const SectionRef MR = get_section(O, "__DATA", "__objc_msgrefs");
- info.S = MR;
- print_message_refs64(MR, &info);
- }
-
- const SectionRef II = get_section(O, "__OBJC2", "__image_info");
- if (II != SectionRef()) {
- info.S = II;
- print_image_info64(II, &info);
- } else {
- const SectionRef II = get_section(O, "__DATA", "__objc_imageinfo");
- info.S = II;
- print_image_info64(II, &info);
- }
+ SectionRef CL = get_section(O, "__OBJC2", "__class_list");
+ if (CL == SectionRef())
+ CL = get_section(O, "__DATA", "__objc_classlist");
+ info.S = CL;
+ walk_pointer_list_64("class", CL, O, &info, print_class64_t);
+
+ SectionRef CR = get_section(O, "__OBJC2", "__class_refs");
+ if (CR == SectionRef())
+ CR = get_section(O, "__DATA", "__objc_classrefs");
+ info.S = CR;
+ walk_pointer_list_64("class refs", CR, O, &info, nullptr);
+
+ SectionRef SR = get_section(O, "__OBJC2", "__super_refs");
+ if (SR == SectionRef())
+ SR = get_section(O, "__DATA", "__objc_superrefs");
+ info.S = SR;
+ walk_pointer_list_64("super refs", SR, O, &info, nullptr);
+
+ SectionRef CA = get_section(O, "__OBJC2", "__category_list");
+ if (CA == SectionRef())
+ CA = get_section(O, "__DATA", "__objc_catlist");
+ info.S = CA;
+ walk_pointer_list_64("category", CA, O, &info, print_category64_t);
+
+ SectionRef PL = get_section(O, "__OBJC2", "__protocol_list");
+ if (PL == SectionRef())
+ PL = get_section(O, "__DATA", "__objc_protolist");
+ info.S = PL;
+ walk_pointer_list_64("protocol", PL, O, &info, nullptr);
+
+ SectionRef MR = get_section(O, "__OBJC2", "__message_refs");
+ if (MR == SectionRef())
+ MR = get_section(O, "__DATA", "__objc_msgrefs");
+ info.S = MR;
+ print_message_refs64(MR, &info);
+
+ SectionRef II = get_section(O, "__OBJC2", "__image_info");
+ if (II == SectionRef())
+ II = get_section(O, "__DATA", "__objc_imageinfo");
+ info.S = II;
+ print_image_info64(II, &info);
if (info.bindtable != nullptr)
delete info.bindtable;
}
}
+static unsigned getSizeForEncoding(bool is64Bit,
+ unsigned symbolEncoding) {
+ unsigned format = symbolEncoding & 0x0f;
+ switch (format) {
+ default: llvm_unreachable("Unknown Encoding");
+ case dwarf::DW_EH_PE_absptr:
+ case dwarf::DW_EH_PE_signed:
+ return is64Bit ? 8 : 4;
+ case dwarf::DW_EH_PE_udata2:
+ case dwarf::DW_EH_PE_sdata2:
+ return 2;
+ case dwarf::DW_EH_PE_udata4:
+ case dwarf::DW_EH_PE_sdata4:
+ return 4;
+ case dwarf::DW_EH_PE_udata8:
+ case dwarf::DW_EH_PE_sdata8:
+ return 8;
+ }
+}
+
+static uint64_t readPointer(const char *&Pos, bool is64Bit, unsigned Encoding) {
+ switch (getSizeForEncoding(is64Bit, Encoding)) {
+ case 2:
+ return readNext<uint16_t>(Pos);
+ break;
+ case 4:
+ return readNext<uint32_t>(Pos);
+ break;
+ case 8:
+ return readNext<uint64_t>(Pos);
+ break;
+ default:
+ llvm_unreachable("Illegal data size");
+ }
+}
+
+static void printMachOEHFrameSection(const MachOObjectFile *Obj,
+ std::map<uint64_t, SymbolRef> &Symbols,
+ const SectionRef &EHFrame) {
+ if (!Obj->isLittleEndian()) {
+ outs() << "warning: cannot handle big endian __eh_frame section\n";
+ return;
+ }
+
+ bool is64Bit = Obj->is64Bit();
+
+ outs() << "Contents of __eh_frame section:\n";
+
+ StringRef Contents;
+ EHFrame.getContents(Contents);
+
+ /// A few fields of the CIE are used when decoding the FDE's. This struct
+ /// will cache those fields we need so that we don't have to decode it
+ /// repeatedly for each FDE that references it.
+ struct DecodedCIE {
+ Optional<uint32_t> FDEPointerEncoding;
+ Optional<uint32_t> LSDAPointerEncoding;
+ bool hasAugmentationLength;
+ };
+
+ // Map from the start offset of the CIE to the cached data for that CIE.
+ DenseMap<uint64_t, DecodedCIE> CachedCIEs;
+
+ for (const char *Pos = Contents.data(), *End = Contents.end(); Pos != End; ) {
+
+ const char *EntryStartPos = Pos;
+
+ uint64_t Length = readNext<uint32_t>(Pos);
+ if (Length == 0xffffffff)
+ Length = readNext<uint64_t>(Pos);
+
+ // Save the Pos so that we can check the length we encoded against what we
+ // end up decoding.
+ const char *PosAfterLength = Pos;
+ const char *EntryEndPos = PosAfterLength + Length;
+
+ assert(EntryEndPos <= End &&
+ "__eh_frame entry length exceeds section size");
+
+ uint32_t ID = readNext<uint32_t>(Pos);
+ if (ID == 0) {
+ // This is a CIE.
+
+ uint32_t Version = readNext<uint8_t>(Pos);
+
+ // Parse a null terminated augmentation string
+ SmallString<8> AugmentationString;
+ for (uint8_t Char = readNext<uint8_t>(Pos); Char;
+ Char = readNext<uint8_t>(Pos))
+ AugmentationString.push_back(Char);
+
+ // Optionally parse the EH data if the augmentation string says it's there.
+ Optional<uint64_t> EHData;
+ if (StringRef(AugmentationString).count("eh"))
+ EHData = is64Bit ? readNext<uint64_t>(Pos) : readNext<uint32_t>(Pos);
+
+ unsigned ULEBByteCount;
+ uint64_t CodeAlignmentFactor = decodeULEB128((const uint8_t *)Pos,
+ &ULEBByteCount);
+ Pos += ULEBByteCount;
+
+ int64_t DataAlignmentFactor = decodeSLEB128((const uint8_t *)Pos,
+ &ULEBByteCount);
+ Pos += ULEBByteCount;
+
+ uint32_t ReturnAddressRegister = readNext<uint8_t>(Pos);
+
+ Optional<uint64_t> AugmentationLength;
+ Optional<uint32_t> LSDAPointerEncoding;
+ Optional<uint32_t> PersonalityEncoding;
+ Optional<uint64_t> Personality;
+ Optional<uint32_t> FDEPointerEncoding;
+ if (!AugmentationString.empty() && AugmentationString.front() == 'z') {
+ AugmentationLength = decodeULEB128((const uint8_t *)Pos,
+ &ULEBByteCount);
+ Pos += ULEBByteCount;
+
+ // Walk the augmentation string to get all the augmentation data.
+ for (unsigned i = 1, e = AugmentationString.size(); i != e; ++i) {
+ char Char = AugmentationString[i];
+ switch (Char) {
+ case 'e':
+ assert((i + 1) != e && AugmentationString[i + 1] == 'h' &&
+ "Expected 'eh' in augmentation string");
+ break;
+ case 'L':
+ assert(!LSDAPointerEncoding && "Duplicate LSDA encoding");
+ LSDAPointerEncoding = readNext<uint8_t>(Pos);
+ break;
+ case 'P': {
+ assert(!Personality && "Duplicate personality");
+ PersonalityEncoding = readNext<uint8_t>(Pos);
+ Personality = readPointer(Pos, is64Bit, *PersonalityEncoding);
+ break;
+ }
+ case 'R':
+ assert(!FDEPointerEncoding && "Duplicate FDE encoding");
+ FDEPointerEncoding = readNext<uint8_t>(Pos);
+ break;
+ case 'z':
+ llvm_unreachable("'z' must be first in the augmentation string");
+ }
+ }
+ }
+
+ outs() << "CIE:\n";
+ outs() << " Length: " << Length << "\n";
+ outs() << " CIE ID: " << ID << "\n";
+ outs() << " Version: " << Version << "\n";
+ outs() << " Augmentation String: " << AugmentationString << "\n";
+ if (EHData)
+ outs() << " EHData: " << *EHData << "\n";
+ outs() << " Code Alignment Factor: " << CodeAlignmentFactor << "\n";
+ outs() << " Data Alignment Factor: " << DataAlignmentFactor << "\n";
+ outs() << " Return Address Register: " << ReturnAddressRegister << "\n";
+ if (AugmentationLength) {
+ outs() << " Augmentation Data Length: " << *AugmentationLength << "\n";
+ if (LSDAPointerEncoding) {
+ outs() << " FDE LSDA Pointer Encoding: "
+ << *LSDAPointerEncoding << "\n";
+ }
+ if (Personality) {
+ outs() << " Personality Encoding: " << *PersonalityEncoding << "\n";
+ outs() << " Personality: " << *Personality << "\n";
+ }
+ if (FDEPointerEncoding) {
+ outs() << " FDE Address Pointer Encoding: "
+ << *FDEPointerEncoding << "\n";
+ }
+ }
+ // FIXME: Handle instructions.
+ // For now just emit some bytes
+ outs() << " Instructions:\n ";
+ dumpBytes(makeArrayRef((const uint8_t*)Pos, (const uint8_t*)EntryEndPos),
+ outs());
+ outs() << "\n";
+ Pos = EntryEndPos;
+
+ // Cache this entry.
+ uint64_t Offset = EntryStartPos - Contents.data();
+ CachedCIEs[Offset] = { FDEPointerEncoding, LSDAPointerEncoding,
+ AugmentationLength.hasValue() };
+ continue;
+ }
+
+ // This is an FDE.
+ // The CIE pointer for an FDE is the same location as the ID which we
+ // already read.
+ uint32_t CIEPointer = ID;
+
+ const char *CIEStart = PosAfterLength - CIEPointer;
+ assert(CIEStart >= Contents.data() &&
+ "FDE points to CIE before the __eh_frame start");
+
+ uint64_t CIEOffset = CIEStart - Contents.data();
+ auto CIEIt = CachedCIEs.find(CIEOffset);
+ if (CIEIt == CachedCIEs.end())
+ llvm_unreachable("Couldn't find CIE at offset in to __eh_frame section");
+
+ const DecodedCIE &CIE = CIEIt->getSecond();
+ assert(CIE.FDEPointerEncoding &&
+ "FDE references CIE which did not set pointer encoding");
+
+ uint64_t PCPointerSize = getSizeForEncoding(is64Bit,
+ *CIE.FDEPointerEncoding);
+
+ uint64_t PCBegin = readPointer(Pos, is64Bit, *CIE.FDEPointerEncoding);
+ uint64_t PCRange = readPointer(Pos, is64Bit, *CIE.FDEPointerEncoding);
+
+ Optional<uint64_t> AugmentationLength;
+ uint32_t LSDAPointerSize;
+ Optional<uint64_t> LSDAPointer;
+ if (CIE.hasAugmentationLength) {
+ unsigned ULEBByteCount;
+ AugmentationLength = decodeULEB128((const uint8_t *)Pos,
+ &ULEBByteCount);
+ Pos += ULEBByteCount;
+
+ // Decode the LSDA if the CIE augmentation string said we should.
+ if (CIE.LSDAPointerEncoding) {
+ LSDAPointerSize = getSizeForEncoding(is64Bit, *CIE.LSDAPointerEncoding);
+ LSDAPointer = readPointer(Pos, is64Bit, *CIE.LSDAPointerEncoding);
+ }
+ }
+
+ outs() << "FDE:\n";
+ outs() << " Length: " << Length << "\n";
+ outs() << " CIE Offset: " << CIEOffset << "\n";
+
+ if (PCPointerSize == 8) {
+ outs() << format(" PC Begin: %016" PRIx64, PCBegin) << "\n";
+ outs() << format(" PC Range: %016" PRIx64, PCRange) << "\n";
+ } else {
+ outs() << format(" PC Begin: %08" PRIx64, PCBegin) << "\n";
+ outs() << format(" PC Range: %08" PRIx64, PCRange) << "\n";
+ }
+ if (AugmentationLength) {
+ outs() << " Augmentation Data Length: " << *AugmentationLength << "\n";
+ if (LSDAPointer) {
+ if (LSDAPointerSize == 8)
+ outs() << format(" LSDA Pointer: %016\n" PRIx64, *LSDAPointer);
+ else
+ outs() << format(" LSDA Pointer: %08\n" PRIx64, *LSDAPointer);
+ }
+ }
+
+ // FIXME: Handle instructions.
+ // For now just emit some bytes
+ outs() << " Instructions:\n ";
+ dumpBytes(makeArrayRef((const uint8_t*)Pos, (const uint8_t*)EntryEndPos),
+ outs());
+ outs() << "\n";
+ Pos = EntryEndPos;
+ }
+}
+
void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) {
std::map<uint64_t, SymbolRef> Symbols;
for (const SymbolRef &SymRef : Obj->symbols()) {
else if (SectName == "__unwind_info")
printMachOUnwindInfoSection(Obj, Symbols, Section);
else if (SectName == "__eh_frame")
- outs() << "llvm-objdump: warning: unhandled __eh_frame section\n";
+ printMachOEHFrameSection(Obj, Symbols, Section);
}
}
else
outs() << "\n";
outs() << " uuid ";
- outs() << format("%02" PRIX32, uuid.uuid[0]);
- outs() << format("%02" PRIX32, uuid.uuid[1]);
- outs() << format("%02" PRIX32, uuid.uuid[2]);
- outs() << format("%02" PRIX32, uuid.uuid[3]);
- outs() << "-";
- outs() << format("%02" PRIX32, uuid.uuid[4]);
- outs() << format("%02" PRIX32, uuid.uuid[5]);
- outs() << "-";
- outs() << format("%02" PRIX32, uuid.uuid[6]);
- outs() << format("%02" PRIX32, uuid.uuid[7]);
- outs() << "-";
- outs() << format("%02" PRIX32, uuid.uuid[8]);
- outs() << format("%02" PRIX32, uuid.uuid[9]);
- outs() << "-";
- outs() << format("%02" PRIX32, uuid.uuid[10]);
- outs() << format("%02" PRIX32, uuid.uuid[11]);
- outs() << format("%02" PRIX32, uuid.uuid[12]);
- outs() << format("%02" PRIX32, uuid.uuid[13]);
- outs() << format("%02" PRIX32, uuid.uuid[14]);
- outs() << format("%02" PRIX32, uuid.uuid[15]);
+ for (int i = 0; i < 16; ++i) {
+ outs() << format("%02" PRIX32, uuid.uuid[i]);
+ if (i == 3 || i == 5 || i == 7 || i == 9)
+ outs() << "-";
+ }
outs() << "\n";
}
}
}
-static void getAndPrintMachHeader(const MachOObjectFile *Obj,
- uint32_t &filetype, uint32_t &cputype,
- bool verbose) {
+static void PrintMachHeader(const MachOObjectFile *Obj, bool verbose) {
if (Obj->is64Bit()) {
MachO::mach_header_64 H_64;
H_64 = Obj->getHeader64();
PrintMachHeader(H_64.magic, H_64.cputype, H_64.cpusubtype, H_64.filetype,
H_64.ncmds, H_64.sizeofcmds, H_64.flags, verbose);
- filetype = H_64.filetype;
- cputype = H_64.cputype;
} else {
MachO::mach_header H;
H = Obj->getHeader();
PrintMachHeader(H.magic, H.cputype, H.cpusubtype, H.filetype, H.ncmds,
H.sizeofcmds, H.flags, verbose);
- filetype = H.filetype;
- cputype = H.cputype;
}
}
void llvm::printMachOFileHeader(const object::ObjectFile *Obj) {
+ const MachOObjectFile *file = dyn_cast<const MachOObjectFile>(Obj);
+ PrintMachHeader(file, !NonVerbose);
+}
+
+void llvm::printMachOLoadCommands(const object::ObjectFile *Obj) {
const MachOObjectFile *file = dyn_cast<const MachOObjectFile>(Obj);
uint32_t filetype = 0;
uint32_t cputype = 0;
- getAndPrintMachHeader(file, filetype, cputype, !NonVerbose);
+ if (file->is64Bit()) {
+ MachO::mach_header_64 H_64;
+ H_64 = file->getHeader64();
+ filetype = H_64.filetype;
+ cputype = H_64.cputype;
+ } else {
+ MachO::mach_header H;
+ H = file->getHeader();
+ filetype = H.filetype;
+ cputype = H.cputype;
+ }
PrintLoadCommands(file, filetype, cputype, !NonVerbose);
}