X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=tools%2Fllvm-objdump%2FMachODump.cpp;h=258c0b520a3d4f6ecfcb9f864d9bf9668679fcf7;hp=0a790b91cb0e4010317294f3614d73660109901b;hb=ed7a4ba53481007a5d80e5588b5a9191950349f0;hpb=70ed0f67e19c0ff9cb9fada845423d5aec581566 diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index 0a790b91cb0..258c0b520a3 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -13,6 +13,7 @@ #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" @@ -666,13 +667,9 @@ static void DumpLiteral8(MachOObjectFile *O, uint32_t l0, uint32_t l1, 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); @@ -917,10 +914,7 @@ static void DumpInitTermPointerSection(MachOObjectFile *O, const char *sect, 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()) { @@ -1202,7 +1196,11 @@ static void ProcessMachO(StringRef Filename, MachOObjectFile *MachOOF, PrintSymbolTable(MachOOF); if (UnwindInfo) printMachOUnwindInfo(MachOOF); - if (PrivateHeaders) + if (PrivateHeaders) { + printMachOFileHeader(MachOOF); + printMachOLoadCommands(MachOOF); + } + if (FirstPrivateHeader) printMachOFileHeader(MachOOF); if (ObjcMetaData) printObjcMetaData(MachOOF, !NonVerbose); @@ -1483,10 +1481,8 @@ void llvm::ParseInputMachO(StringRef Filename) { // Attempt to open the binary. ErrorOr> 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(&Bin)) { @@ -1655,9 +1651,9 @@ void llvm::ParseInputMachO(StringRef Filename) { } 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 BindInfoEntry; @@ -6754,6 +6750,262 @@ static void printMachOUnwindInfoSection(const MachOObjectFile *Obj, } } +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(Pos); + break; + case 4: + return readNext(Pos); + break; + case 8: + return readNext(Pos); + break; + default: + llvm_unreachable("Illegal data size"); + } +} + +static void printMachOEHFrameSection(const MachOObjectFile *Obj, + std::map &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 FDEPointerEncoding; + Optional LSDAPointerEncoding; + bool hasAugmentationLength; + }; + + // Map from the start offset of the CIE to the cached data for that CIE. + DenseMap CachedCIEs; + + for (const char *Pos = Contents.data(), *End = Contents.end(); Pos != End; ) { + + const char *EntryStartPos = Pos; + + uint64_t Length = readNext(Pos); + if (Length == 0xffffffff) + Length = readNext(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(Pos); + if (ID == 0) { + // This is a CIE. + + uint32_t Version = readNext(Pos); + + // Parse a null terminated augmentation string + SmallString<8> AugmentationString; + for (uint8_t Char = readNext(Pos); Char; + Char = readNext(Pos)) + AugmentationString.push_back(Char); + + // Optionally parse the EH data if the augmentation string says it's there. + Optional EHData; + if (StringRef(AugmentationString).count("eh")) + EHData = is64Bit ? readNext(Pos) : readNext(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(Pos); + + Optional AugmentationLength; + Optional LSDAPointerEncoding; + Optional PersonalityEncoding; + Optional Personality; + Optional 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(Pos); + break; + case 'P': { + assert(!Personality && "Duplicate personality"); + PersonalityEncoding = readNext(Pos); + Personality = readPointer(Pos, is64Bit, *PersonalityEncoding); + break; + } + case 'R': + assert(!FDEPointerEncoding && "Duplicate FDE encoding"); + FDEPointerEncoding = readNext(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 AugmentationLength; + uint32_t LSDAPointerSize; + Optional 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 Symbols; for (const SymbolRef &SymRef : Obj->symbols()) { @@ -6775,7 +7027,7 @@ void llvm::printMachOUnwindInfo(const MachOObjectFile *Obj) { 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); } } @@ -8397,31 +8649,40 @@ static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype, } } -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(Obj); + PrintMachHeader(file, !NonVerbose); +} + +void llvm::printMachOLoadCommands(const object::ObjectFile *Obj) { const MachOObjectFile *file = dyn_cast(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); }