diff options
Diffstat (limited to 'tools/llvm-objdump')
-rw-r--r-- | tools/llvm-objdump/MachODump.cpp | 532 | ||||
-rw-r--r-- | tools/llvm-objdump/llvm-objdump.cpp | 104 | ||||
-rw-r--r-- | tools/llvm-objdump/llvm-objdump.h | 17 |
3 files changed, 417 insertions, 236 deletions
diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index 563084856f6f..9e02951a4a93 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -68,9 +68,6 @@ static cl::opt<std::string> DSYMFile("dsym", static cl::opt<bool> FullLeadingAddr("full-leading-addr", cl::desc("Print full leading address")); -static cl::opt<bool> NoLeadingAddr("no-leading-addr", - cl::desc("Print no leading address")); - static cl::opt<bool> NoLeadingHeaders("no-leading-headers", cl::desc("Print no leading headers")); @@ -1142,7 +1139,7 @@ static void DumpInfoPlistSectionContents(StringRef Filename, StringRef BytesStr; Section.getContents(BytesStr); const char *sect = reinterpret_cast<const char *>(BytesStr.data()); - outs() << sect; + outs() << format("%.*s", BytesStr.size(), sect) << "\n"; return; } } @@ -1566,8 +1563,13 @@ void llvm::ParseInputMachO(StringRef Filename) { // Attempt to open the binary. Expected<OwningBinary<Binary>> BinaryOrErr = createBinary(Filename); - if (!BinaryOrErr) - report_error(Filename, BinaryOrErr.takeError()); + if (!BinaryOrErr) { + if (auto E = isNotObjectErrorInvalidFileType(BinaryOrErr.takeError())) + report_error(Filename, std::move(E)); + else + outs() << Filename << ": is not an object file\n"; + return; + } Binary &Bin = *BinaryOrErr.get().getBinary(); if (Archive *A = dyn_cast<Archive>(&Bin)) { @@ -5269,42 +5271,70 @@ static void printObjc2_64bit_MetaData(MachOObjectFile *O, bool verbose) { SectionRef CL = get_section(O, "__OBJC2", "__class_list"); if (CL == SectionRef()) CL = get_section(O, "__DATA", "__objc_classlist"); + if (CL == SectionRef()) + CL = get_section(O, "__DATA_CONST", "__objc_classlist"); + if (CL == SectionRef()) + CL = get_section(O, "__DATA_DIRTY", "__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"); + if (CR == SectionRef()) + CR = get_section(O, "__DATA_CONST", "__objc_classrefs"); + if (CR == SectionRef()) + CR = get_section(O, "__DATA_DIRTY", "__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"); + if (SR == SectionRef()) + SR = get_section(O, "__DATA_CONST", "__objc_superrefs"); + if (SR == SectionRef()) + SR = get_section(O, "__DATA_DIRTY", "__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"); + if (CA == SectionRef()) + CA = get_section(O, "__DATA_CONST", "__objc_catlist"); + if (CA == SectionRef()) + CA = get_section(O, "__DATA_DIRTY", "__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"); + if (PL == SectionRef()) + PL = get_section(O, "__DATA_CONST", "__objc_protolist"); + if (PL == SectionRef()) + PL = get_section(O, "__DATA_DIRTY", "__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"); + if (MR == SectionRef()) + MR = get_section(O, "__DATA_CONST", "__objc_msgrefs"); + if (MR == SectionRef()) + MR = get_section(O, "__DATA_DIRTY", "__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"); + if (II == SectionRef()) + II = get_section(O, "__DATA_CONST", "__objc_imageinfo"); + if (II == SectionRef()) + II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo"); info.S = II; print_image_info64(II, &info); } @@ -5335,75 +5365,75 @@ static void printObjc2_32bit_MetaData(MachOObjectFile *O, bool verbose) { info.adrp_addr = 0; info.adrp_inst = 0; - const SectionRef CL = get_section(O, "__OBJC2", "__class_list"); - if (CL != SectionRef()) { - info.S = CL; - walk_pointer_list_32("class", CL, O, &info, print_class32_t); - } else { - const SectionRef CL = get_section(O, "__DATA", "__objc_classlist"); - info.S = CL; - walk_pointer_list_32("class", CL, O, &info, print_class32_t); - } + SectionRef CL = get_section(O, "__OBJC2", "__class_list"); + if (CL == SectionRef()) + CL = get_section(O, "__DATA", "__objc_classlist"); + if (CL == SectionRef()) + CL = get_section(O, "__DATA_CONST", "__objc_classlist"); + if (CL == SectionRef()) + CL = get_section(O, "__DATA_DIRTY", "__objc_classlist"); + info.S = CL; + walk_pointer_list_32("class", CL, O, &info, print_class32_t); - const SectionRef CR = get_section(O, "__OBJC2", "__class_refs"); - if (CR != SectionRef()) { - info.S = CR; - walk_pointer_list_32("class refs", CR, O, &info, nullptr); - } else { - const SectionRef CR = get_section(O, "__DATA", "__objc_classrefs"); - info.S = CR; - walk_pointer_list_32("class refs", CR, O, &info, nullptr); - } + SectionRef CR = get_section(O, "__OBJC2", "__class_refs"); + if (CR == SectionRef()) + CR = get_section(O, "__DATA", "__objc_classrefs"); + if (CR == SectionRef()) + CR = get_section(O, "__DATA_CONST", "__objc_classrefs"); + if (CR == SectionRef()) + CR = get_section(O, "__DATA_DIRTY", "__objc_classrefs"); + info.S = CR; + walk_pointer_list_32("class refs", CR, O, &info, nullptr); - const SectionRef SR = get_section(O, "__OBJC2", "__super_refs"); - if (SR != SectionRef()) { - info.S = SR; - walk_pointer_list_32("super refs", SR, O, &info, nullptr); - } else { - const SectionRef SR = get_section(O, "__DATA", "__objc_superrefs"); - info.S = SR; - walk_pointer_list_32("super refs", SR, O, &info, nullptr); - } + SectionRef SR = get_section(O, "__OBJC2", "__super_refs"); + if (SR == SectionRef()) + SR = get_section(O, "__DATA", "__objc_superrefs"); + if (SR == SectionRef()) + SR = get_section(O, "__DATA_CONST", "__objc_superrefs"); + if (SR == SectionRef()) + SR = get_section(O, "__DATA_DIRTY", "__objc_superrefs"); + info.S = SR; + walk_pointer_list_32("super refs", SR, O, &info, nullptr); - const SectionRef CA = get_section(O, "__OBJC2", "__category_list"); - if (CA != SectionRef()) { - info.S = CA; - walk_pointer_list_32("category", CA, O, &info, print_category32_t); - } else { - const SectionRef CA = get_section(O, "__DATA", "__objc_catlist"); - info.S = CA; - walk_pointer_list_32("category", CA, O, &info, print_category32_t); - } + SectionRef CA = get_section(O, "__OBJC2", "__category_list"); + if (CA == SectionRef()) + CA = get_section(O, "__DATA", "__objc_catlist"); + if (CA == SectionRef()) + CA = get_section(O, "__DATA_CONST", "__objc_catlist"); + if (CA == SectionRef()) + CA = get_section(O, "__DATA_DIRTY", "__objc_catlist"); + info.S = CA; + walk_pointer_list_32("category", CA, O, &info, print_category32_t); - const SectionRef PL = get_section(O, "__OBJC2", "__protocol_list"); - if (PL != SectionRef()) { - info.S = PL; - walk_pointer_list_32("protocol", PL, O, &info, nullptr); - } else { - const SectionRef PL = get_section(O, "__DATA", "__objc_protolist"); - info.S = PL; - walk_pointer_list_32("protocol", PL, O, &info, nullptr); - } + SectionRef PL = get_section(O, "__OBJC2", "__protocol_list"); + if (PL == SectionRef()) + PL = get_section(O, "__DATA", "__objc_protolist"); + if (PL == SectionRef()) + PL = get_section(O, "__DATA_CONST", "__objc_protolist"); + if (PL == SectionRef()) + PL = get_section(O, "__DATA_DIRTY", "__objc_protolist"); + info.S = PL; + walk_pointer_list_32("protocol", PL, O, &info, nullptr); - const SectionRef MR = get_section(O, "__OBJC2", "__message_refs"); - if (MR != SectionRef()) { - info.S = MR; - print_message_refs32(MR, &info); - } else { - const SectionRef MR = get_section(O, "__DATA", "__objc_msgrefs"); - info.S = MR; - print_message_refs32(MR, &info); - } + SectionRef MR = get_section(O, "__OBJC2", "__message_refs"); + if (MR == SectionRef()) + MR = get_section(O, "__DATA", "__objc_msgrefs"); + if (MR == SectionRef()) + MR = get_section(O, "__DATA_CONST", "__objc_msgrefs"); + if (MR == SectionRef()) + MR = get_section(O, "__DATA_DIRTY", "__objc_msgrefs"); + info.S = MR; + print_message_refs32(MR, &info); - const SectionRef II = get_section(O, "__OBJC2", "__image_info"); - if (II != SectionRef()) { - info.S = II; - print_image_info32(II, &info); - } else { - const SectionRef II = get_section(O, "__DATA", "__objc_imageinfo"); - info.S = II; - print_image_info32(II, &info); - } + SectionRef II = get_section(O, "__OBJC2", "__image_info"); + if (II == SectionRef()) + II = get_section(O, "__DATA", "__objc_imageinfo"); + if (II == SectionRef()) + II = get_section(O, "__DATA_CONST", "__objc_imageinfo"); + if (II == SectionRef()) + II = get_section(O, "__DATA_DIRTY", "__objc_imageinfo"); + info.S = II; + print_image_info32(II, &info); } static bool printObjc1_32bit_MetaData(MachOObjectFile *O, bool verbose) { @@ -6597,6 +6627,12 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, if (Bytes.size() == 0) return; + // If the section has symbols but no symbol at the start of the section + // these are used to make sure the bytes before the first symbol are + // disassembled. + bool FirstSymbol = true; + bool FirstSymbolAtSectionStart = true; + // Disassemble symbol by symbol. for (unsigned SymIdx = 0; SymIdx != Symbols.size(); SymIdx++) { Expected<StringRef> SymNameOrErr = Symbols[SymIdx].getName(); @@ -6686,11 +6722,29 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, // (i.e. we're not targeting M-class) and the function is Thumb. bool UseThumbTarget = IsThumb && ThumbTarget; - outs() << SymName << ":\n"; + // If we are not specifying a symbol to start disassembly with and this + // is the first symbol in the section but not at the start of the section + // then move the disassembly index to the start of the section and + // don't print the symbol name just yet. This is so the bytes before the + // first symbol are disassembled. + uint64_t SymbolStart = Start; + if (DisSymName.empty() && FirstSymbol && Start != 0) { + FirstSymbolAtSectionStart = false; + Start = 0; + } + else + outs() << SymName << ":\n"; + DILineInfo lastLine; for (uint64_t Index = Start; Index < End; Index += Size) { MCInst Inst; + // If this is the first symbol in the section and it was not at the + // start of the section, see if we are at its Index now and if so print + // the symbol name. + if (FirstSymbol && !FirstSymbolAtSectionStart && Index == SymbolStart) + outs() << SymName << ":\n"; + uint64_t PC = SectAddress + Index; if (!NoLeadingAddr) { if (FullLeadingAddr) { @@ -6783,6 +6837,9 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, } } } + // Now that we are done disassembled the first symbol set the bool that + // were doing this to false. + FirstSymbol = false; } if (!symbolTableWorked) { // Reading the symbol table didn't work, disassemble the whole section. @@ -6793,8 +6850,10 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, MCInst Inst; uint64_t PC = SectAddress + Index; + SmallVector<char, 64> AnnotationsBytes; + raw_svector_ostream Annotations(AnnotationsBytes); if (DisAsm->getInstruction(Inst, InstSize, Bytes.slice(Index), PC, - DebugOut, nulls())) { + DebugOut, Annotations)) { if (!NoLeadingAddr) { if (FullLeadingAddr) { if (MachOOF->is64Bit()) @@ -6809,7 +6868,8 @@ static void DisassembleMachO(StringRef Filename, MachOObjectFile *MachOOF, outs() << "\t"; dumpBytes(makeArrayRef(Bytes.data() + Index, InstSize), outs()); } - IP->printInst(&Inst, outs(), "", *STI); + StringRef AnnotationsStr = Annotations.str(); + IP->printInst(&Inst, outs(), AnnotationsStr, *STI); outs() << "\n"; } else { unsigned int Arch = MachOOF->getArch(); @@ -8169,6 +8229,51 @@ static void PrintVersionMinLoadCommand(MachO::version_min_command vd) { outs() << "\n"; } +static void PrintNoteLoadCommand(MachO::note_command Nt) { + outs() << " cmd LC_NOTE\n"; + outs() << " cmdsize " << Nt.cmdsize; + if (Nt.cmdsize != sizeof(struct MachO::note_command)) + outs() << " Incorrect size\n"; + else + outs() << "\n"; + const char *d = Nt.data_owner; + outs() << "data_owner " << format("%.16s\n", d); + outs() << " offset " << Nt.offset << "\n"; + outs() << " size " << Nt.size << "\n"; +} + +static void PrintBuildToolVersion(MachO::build_tool_version bv) { + outs() << " tool " << MachOObjectFile::getBuildTool(bv.tool) << "\n"; + outs() << " version " << MachOObjectFile::getVersionString(bv.version) + << "\n"; +} + +static void PrintBuildVersionLoadCommand(const MachOObjectFile *obj, + MachO::build_version_command bd) { + outs() << " cmd LC_BUILD_VERSION\n"; + outs() << " cmdsize " << bd.cmdsize; + if (bd.cmdsize != + sizeof(struct MachO::build_version_command) + + bd.ntools * sizeof(struct MachO::build_tool_version)) + outs() << " Incorrect size\n"; + else + outs() << "\n"; + outs() << " platform " << MachOObjectFile::getBuildPlatform(bd.platform) + << "\n"; + if (bd.sdk) + outs() << " sdk " << MachOObjectFile::getVersionString(bd.sdk) + << "\n"; + else + outs() << " sdk n/a\n"; + outs() << " minos " << MachOObjectFile::getVersionString(bd.minos) + << "\n"; + outs() << " ntools " << bd.ntools << "\n"; + for (unsigned i = 0; i < bd.ntools; ++i) { + MachO::build_tool_version bv = obj->getBuildToolVersion(i); + PrintBuildToolVersion(bv); + } +} + static void PrintSourceVersionCommand(MachO::source_version_command sd) { outs() << " cmd LC_SOURCE_VERSION\n"; outs() << " cmdsize " << sd.cmdsize; @@ -8374,6 +8479,25 @@ static void PrintRoutinesCommand64(MachO::routines_command_64 r) { outs() << " reserved6 " << r.reserved6 << "\n"; } +static void Print_x86_thread_state32_t(MachO::x86_thread_state32_t &cpu32) { + outs() << "\t eax " << format("0x%08" PRIx32, cpu32.eax); + outs() << " ebx " << format("0x%08" PRIx32, cpu32.ebx); + outs() << " ecx " << format("0x%08" PRIx32, cpu32.ecx); + outs() << " edx " << format("0x%08" PRIx32, cpu32.edx) << "\n"; + outs() << "\t edi " << format("0x%08" PRIx32, cpu32.edi); + outs() << " esi " << format("0x%08" PRIx32, cpu32.esi); + outs() << " ebp " << format("0x%08" PRIx32, cpu32.ebp); + outs() << " esp " << format("0x%08" PRIx32, cpu32.esp) << "\n"; + outs() << "\t ss " << format("0x%08" PRIx32, cpu32.ss); + outs() << " eflags " << format("0x%08" PRIx32, cpu32.eflags); + outs() << " eip " << format("0x%08" PRIx32, cpu32.eip); + outs() << " cs " << format("0x%08" PRIx32, cpu32.cs) << "\n"; + outs() << "\t ds " << format("0x%08" PRIx32, cpu32.ds); + outs() << " es " << format("0x%08" PRIx32, cpu32.es); + outs() << " fs " << format("0x%08" PRIx32, cpu32.fs); + outs() << " gs " << format("0x%08" PRIx32, cpu32.gs) << "\n"; +} + static void Print_x86_thread_state64_t(MachO::x86_thread_state64_t &cpu64) { outs() << " rax " << format("0x%016" PRIx64, cpu64.rax); outs() << " rbx " << format("0x%016" PRIx64, cpu64.rbx); @@ -8611,7 +8735,85 @@ static void PrintThreadCommand(MachO::thread_command t, const char *Ptr, const char *begin = Ptr + sizeof(struct MachO::thread_command); const char *end = Ptr + t.cmdsize; uint32_t flavor, count, left; - if (cputype == MachO::CPU_TYPE_X86_64) { + if (cputype == MachO::CPU_TYPE_I386) { + while (begin < end) { + if (end - begin > (ptrdiff_t)sizeof(uint32_t)) { + memcpy((char *)&flavor, begin, sizeof(uint32_t)); + begin += sizeof(uint32_t); + } else { + flavor = 0; + begin = end; + } + if (isLittleEndian != sys::IsLittleEndianHost) + sys::swapByteOrder(flavor); + if (end - begin > (ptrdiff_t)sizeof(uint32_t)) { + memcpy((char *)&count, begin, sizeof(uint32_t)); + begin += sizeof(uint32_t); + } else { + count = 0; + begin = end; + } + if (isLittleEndian != sys::IsLittleEndianHost) + sys::swapByteOrder(count); + if (flavor == MachO::x86_THREAD_STATE32) { + outs() << " flavor i386_THREAD_STATE\n"; + if (count == MachO::x86_THREAD_STATE32_COUNT) + outs() << " count i386_THREAD_STATE_COUNT\n"; + else + outs() << " count " << count + << " (not x86_THREAD_STATE32_COUNT)\n"; + MachO::x86_thread_state32_t cpu32; + left = end - begin; + if (left >= sizeof(MachO::x86_thread_state32_t)) { + memcpy(&cpu32, begin, sizeof(MachO::x86_thread_state32_t)); + begin += sizeof(MachO::x86_thread_state32_t); + } else { + memset(&cpu32, '\0', sizeof(MachO::x86_thread_state32_t)); + memcpy(&cpu32, begin, left); + begin += left; + } + if (isLittleEndian != sys::IsLittleEndianHost) + swapStruct(cpu32); + Print_x86_thread_state32_t(cpu32); + } else if (flavor == MachO::x86_THREAD_STATE) { + outs() << " flavor x86_THREAD_STATE\n"; + if (count == MachO::x86_THREAD_STATE_COUNT) + outs() << " count x86_THREAD_STATE_COUNT\n"; + else + outs() << " count " << count + << " (not x86_THREAD_STATE_COUNT)\n"; + struct MachO::x86_thread_state_t ts; + left = end - begin; + if (left >= sizeof(MachO::x86_thread_state_t)) { + memcpy(&ts, begin, sizeof(MachO::x86_thread_state_t)); + begin += sizeof(MachO::x86_thread_state_t); + } else { + memset(&ts, '\0', sizeof(MachO::x86_thread_state_t)); + memcpy(&ts, begin, left); + begin += left; + } + if (isLittleEndian != sys::IsLittleEndianHost) + swapStruct(ts); + if (ts.tsh.flavor == MachO::x86_THREAD_STATE32) { + outs() << "\t tsh.flavor x86_THREAD_STATE32 "; + if (ts.tsh.count == MachO::x86_THREAD_STATE32_COUNT) + outs() << "tsh.count x86_THREAD_STATE32_COUNT\n"; + else + outs() << "tsh.count " << ts.tsh.count + << " (not x86_THREAD_STATE32_COUNT\n"; + Print_x86_thread_state32_t(ts.uts.ts32); + } else { + outs() << "\t tsh.flavor " << ts.tsh.flavor << " tsh.count " + << ts.tsh.count << "\n"; + } + } else { + outs() << " flavor " << flavor << " (unknown)\n"; + outs() << " count " << count << "\n"; + outs() << " state (unknown)\n"; + begin += count * sizeof(uint32_t); + } + } + } else if (cputype == MachO::CPU_TYPE_X86_64) { while (begin < end) { if (end - begin > (ptrdiff_t)sizeof(uint32_t)) { memcpy((char *)&flavor, begin, sizeof(uint32_t)); @@ -9014,6 +9216,13 @@ static void PrintLoadCommands(const MachOObjectFile *Obj, uint32_t filetype, Command.C.cmd == MachO::LC_VERSION_MIN_WATCHOS) { MachO::version_min_command Vd = Obj->getVersionMinLoadCommand(Command); PrintVersionMinLoadCommand(Vd); + } else if (Command.C.cmd == MachO::LC_NOTE) { + MachO::note_command Nt = Obj->getNoteLoadCommand(Command); + PrintNoteLoadCommand(Nt); + } else if (Command.C.cmd == MachO::LC_BUILD_VERSION) { + MachO::build_version_command Bv = + Obj->getBuildVersionLoadCommand(Command); + PrintBuildVersionLoadCommand(Obj, Bv); } else if (Command.C.cmd == MachO::LC_SOURCE_VERSION) { MachO::source_version_command Sd = Obj->getSourceVersionCommand(Command); PrintSourceVersionCommand(Sd); @@ -9182,117 +9391,21 @@ void llvm::printMachOExportsTrie(const object::MachOObjectFile *Obj) { // rebase table dumping //===----------------------------------------------------------------------===// -namespace { -class SegInfo { -public: - SegInfo(const object::MachOObjectFile *Obj); - - StringRef segmentName(uint32_t SegIndex); - StringRef sectionName(uint32_t SegIndex, uint64_t SegOffset); - uint64_t address(uint32_t SegIndex, uint64_t SegOffset); - bool isValidSegIndexAndOffset(uint32_t SegIndex, uint64_t SegOffset); - -private: - struct SectionInfo { - uint64_t Address; - uint64_t Size; - StringRef SectionName; - StringRef SegmentName; - uint64_t OffsetInSegment; - uint64_t SegmentStartAddress; - uint32_t SegmentIndex; - }; - const SectionInfo &findSection(uint32_t SegIndex, uint64_t SegOffset); - SmallVector<SectionInfo, 32> Sections; -}; -} - -SegInfo::SegInfo(const object::MachOObjectFile *Obj) { - // Build table of sections so segIndex/offset pairs can be translated. - uint32_t CurSegIndex = Obj->hasPageZeroSegment() ? 1 : 0; - StringRef CurSegName; - uint64_t CurSegAddress; - for (const SectionRef &Section : Obj->sections()) { - SectionInfo Info; - error(Section.getName(Info.SectionName)); - Info.Address = Section.getAddress(); - Info.Size = Section.getSize(); - Info.SegmentName = - Obj->getSectionFinalSegmentName(Section.getRawDataRefImpl()); - if (!Info.SegmentName.equals(CurSegName)) { - ++CurSegIndex; - CurSegName = Info.SegmentName; - CurSegAddress = Info.Address; - } - Info.SegmentIndex = CurSegIndex - 1; - Info.OffsetInSegment = Info.Address - CurSegAddress; - Info.SegmentStartAddress = CurSegAddress; - Sections.push_back(Info); - } -} - -StringRef SegInfo::segmentName(uint32_t SegIndex) { - for (const SectionInfo &SI : Sections) { - if (SI.SegmentIndex == SegIndex) - return SI.SegmentName; - } - llvm_unreachable("invalid segIndex"); -} - -bool SegInfo::isValidSegIndexAndOffset(uint32_t SegIndex, - uint64_t OffsetInSeg) { - for (const SectionInfo &SI : Sections) { - if (SI.SegmentIndex != SegIndex) - continue; - if (SI.OffsetInSegment > OffsetInSeg) - continue; - if (OffsetInSeg >= (SI.OffsetInSegment + SI.Size)) - continue; - return true; - } - return false; -} - -const SegInfo::SectionInfo &SegInfo::findSection(uint32_t SegIndex, - uint64_t OffsetInSeg) { - for (const SectionInfo &SI : Sections) { - if (SI.SegmentIndex != SegIndex) - continue; - if (SI.OffsetInSegment > OffsetInSeg) - continue; - if (OffsetInSeg >= (SI.OffsetInSegment + SI.Size)) - continue; - return SI; - } - llvm_unreachable("segIndex and offset not in any section"); -} - -StringRef SegInfo::sectionName(uint32_t SegIndex, uint64_t OffsetInSeg) { - return findSection(SegIndex, OffsetInSeg).SectionName; -} - -uint64_t SegInfo::address(uint32_t SegIndex, uint64_t OffsetInSeg) { - const SectionInfo &SI = findSection(SegIndex, OffsetInSeg); - return SI.SegmentStartAddress + OffsetInSeg; -} - -void llvm::printMachORebaseTable(const object::MachOObjectFile *Obj) { - // Build table of sections so names can used in final output. - SegInfo sectionTable(Obj); - +void llvm::printMachORebaseTable(object::MachOObjectFile *Obj) { outs() << "segment section address type\n"; - for (const llvm::object::MachORebaseEntry &Entry : Obj->rebaseTable()) { - uint32_t SegIndex = Entry.segmentIndex(); - uint64_t OffsetInSeg = Entry.segmentOffset(); - StringRef SegmentName = sectionTable.segmentName(SegIndex); - StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg); - uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg); + Error Err = Error::success(); + for (const llvm::object::MachORebaseEntry &Entry : Obj->rebaseTable(Err)) { + StringRef SegmentName = Entry.segmentName(); + StringRef SectionName = Entry.sectionName(); + uint64_t Address = Entry.address(); // Table lines look like: __DATA __nl_symbol_ptr 0x0000F00C pointer outs() << format("%-8s %-18s 0x%08" PRIX64 " %s\n", SegmentName.str().c_str(), SectionName.str().c_str(), Address, Entry.typeName().str().c_str()); } + if (Err) + report_error(Obj->getFileName(), std::move(Err)); } static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) { @@ -9320,18 +9433,15 @@ static StringRef ordinalName(const object::MachOObjectFile *Obj, int Ordinal) { // bind table dumping //===----------------------------------------------------------------------===// -void llvm::printMachOBindTable(const object::MachOObjectFile *Obj) { +void llvm::printMachOBindTable(object::MachOObjectFile *Obj) { // Build table of sections so names can used in final output. - SegInfo sectionTable(Obj); - outs() << "segment section address type " "addend dylib symbol\n"; - for (const llvm::object::MachOBindEntry &Entry : Obj->bindTable()) { - uint32_t SegIndex = Entry.segmentIndex(); - uint64_t OffsetInSeg = Entry.segmentOffset(); - StringRef SegmentName = sectionTable.segmentName(SegIndex); - StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg); - uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg); + Error Err = Error::success(); + for (const llvm::object::MachOBindEntry &Entry : Obj->bindTable(Err)) { + StringRef SegmentName = Entry.segmentName(); + StringRef SectionName = Entry.sectionName(); + uint64_t Address = Entry.address(); // Table lines look like: // __DATA __got 0x00012010 pointer 0 libSystem ___stack_chk_guard @@ -9346,24 +9456,22 @@ void llvm::printMachOBindTable(const object::MachOObjectFile *Obj) { << left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " " << Entry.symbolName() << Attr << "\n"; } + if (Err) + report_error(Obj->getFileName(), std::move(Err)); } //===----------------------------------------------------------------------===// // lazy bind table dumping //===----------------------------------------------------------------------===// -void llvm::printMachOLazyBindTable(const object::MachOObjectFile *Obj) { - // Build table of sections so names can used in final output. - SegInfo sectionTable(Obj); - +void llvm::printMachOLazyBindTable(object::MachOObjectFile *Obj) { outs() << "segment section address " "dylib symbol\n"; - for (const llvm::object::MachOBindEntry &Entry : Obj->lazyBindTable()) { - uint32_t SegIndex = Entry.segmentIndex(); - uint64_t OffsetInSeg = Entry.segmentOffset(); - StringRef SegmentName = sectionTable.segmentName(SegIndex); - StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg); - uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg); + Error Err = Error::success(); + for (const llvm::object::MachOBindEntry &Entry : Obj->lazyBindTable(Err)) { + StringRef SegmentName = Entry.segmentName(); + StringRef SectionName = Entry.sectionName(); + uint64_t Address = Entry.address(); // Table lines look like: // __DATA __got 0x00012010 libSystem ___stack_chk_guard @@ -9373,30 +9481,28 @@ void llvm::printMachOLazyBindTable(const object::MachOObjectFile *Obj) { << left_justify(ordinalName(Obj, Entry.ordinal()), 16) << " " << Entry.symbolName() << "\n"; } + if (Err) + report_error(Obj->getFileName(), std::move(Err)); } //===----------------------------------------------------------------------===// // weak bind table dumping //===----------------------------------------------------------------------===// -void llvm::printMachOWeakBindTable(const object::MachOObjectFile *Obj) { - // Build table of sections so names can used in final output. - SegInfo sectionTable(Obj); - +void llvm::printMachOWeakBindTable(object::MachOObjectFile *Obj) { outs() << "segment section address " "type addend symbol\n"; - for (const llvm::object::MachOBindEntry &Entry : Obj->weakBindTable()) { + Error Err = Error::success(); + for (const llvm::object::MachOBindEntry &Entry : Obj->weakBindTable(Err)) { // Strong symbols don't have a location to update. if (Entry.flags() & MachO::BIND_SYMBOL_FLAGS_NON_WEAK_DEFINITION) { outs() << " strong " << Entry.symbolName() << "\n"; continue; } - uint32_t SegIndex = Entry.segmentIndex(); - uint64_t OffsetInSeg = Entry.segmentOffset(); - StringRef SegmentName = sectionTable.segmentName(SegIndex); - StringRef SectionName = sectionTable.sectionName(SegIndex, OffsetInSeg); - uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg); + StringRef SegmentName = Entry.segmentName(); + StringRef SectionName = Entry.sectionName(); + uint64_t Address = Entry.address(); // Table lines look like: // __DATA __data 0x00001000 pointer 0 _foo @@ -9407,6 +9513,8 @@ void llvm::printMachOWeakBindTable(const object::MachOObjectFile *Obj) { << format_decimal(Entry.addend(), 8) << " " << Entry.symbolName() << "\n"; } + if (Err) + report_error(Obj->getFileName(), std::move(Err)); } // get_dyld_bind_info_symbolname() is used for disassembly and passed an @@ -9417,17 +9525,15 @@ static const char *get_dyld_bind_info_symbolname(uint64_t ReferenceValue, struct DisassembleInfo *info) { if (info->bindtable == nullptr) { info->bindtable = llvm::make_unique<SymbolAddressMap>(); - SegInfo sectionTable(info->O); - for (const llvm::object::MachOBindEntry &Entry : info->O->bindTable()) { - uint32_t SegIndex = Entry.segmentIndex(); - uint64_t OffsetInSeg = Entry.segmentOffset(); - if (!sectionTable.isValidSegIndexAndOffset(SegIndex, OffsetInSeg)) - continue; - uint64_t Address = sectionTable.address(SegIndex, OffsetInSeg); + Error Err = Error::success(); + for (const llvm::object::MachOBindEntry &Entry : info->O->bindTable(Err)) { + uint64_t Address = Entry.address(); StringRef name = Entry.symbolName(); if (!name.empty()) (*info->bindtable)[Address] = name; } + if (Err) + report_error(info->O->getFileName(), std::move(Err)); } auto name = info->bindtable->lookup(ReferenceValue); return !name.empty() ? name.data() : nullptr; diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 8373f0ce3f1e..613d0643b433 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -158,6 +158,8 @@ cl::opt<bool> llvm::NoShowRawInsn("no-show-raw-insn", cl::desc("When disassembling " "instructions, do not print " "the instruction bytes.")); +cl::opt<bool> +llvm::NoLeadingAddr("no-leading-addr", cl::desc("Print no leading address")); cl::opt<bool> llvm::UnwindInfo("unwind-info", cl::desc("Display unwind information")); @@ -213,6 +215,8 @@ cl::opt<unsigned long long> cl::value_desc("address"), cl::init(UINT64_MAX)); static StringRef ToolName; +typedef std::vector<std::tuple<uint64_t, StringRef, uint8_t>> SectionSymbolsTy; + namespace { typedef std::function<bool(llvm::object::SectionRef const &)> FilterPredicate; @@ -357,7 +361,16 @@ static const Target *getTarget(const ObjectFile *Obj = nullptr) { llvm::Triple TheTriple("unknown-unknown-unknown"); if (TripleName.empty()) { if (Obj) { - TheTriple.setArch(Triple::ArchType(Obj->getArch())); + auto Arch = Obj->getArch(); + TheTriple.setArch(Triple::ArchType(Arch)); + + // For ARM targets, try to use the build attributes to build determine + // the build target. Target features are also added, but later during + // disassembly. + if (Arch == Triple::arm || Arch == Triple::armeb) { + Obj->setARMSubArch(TheTriple); + } + // TheTriple defaults to ELF, and COFF doesn't have an environment: // the best we can do here is indicate that it is mach-o. if (Obj->isMachO()) @@ -369,8 +382,16 @@ static const Target *getTarget(const ObjectFile *Obj = nullptr) { TheTriple.setTriple("thumbv7-windows"); } } - } else + } else { TheTriple.setTriple(Triple::normalize(TripleName)); + // Use the triple, but also try to combine with ARM build attributes. + if (Obj) { + auto Arch = Obj->getArch(); + if (Arch == Triple::arm || Arch == Triple::armeb) { + Obj->setARMSubArch(TheTriple); + } + } + } // Get the target specific parser. std::string Error; @@ -491,7 +512,8 @@ public: MCSubtargetInfo const &STI, SourcePrinter *SP) { if (SP && (PrintSource || PrintLines)) SP->printSourceLine(OS, Address); - OS << format("%8" PRIx64 ":", Address); + if (!NoLeadingAddr) + OS << format("%8" PRIx64 ":", Address); if (!NoShowRawInsn) { OS << "\t"; dumpBytes(Bytes, OS); @@ -509,7 +531,8 @@ public: raw_ostream &OS) { uint32_t opcode = (Bytes[3] << 24) | (Bytes[2] << 16) | (Bytes[1] << 8) | Bytes[0]; - OS << format("%8" PRIx64 ":", Address); + if (!NoLeadingAddr) + OS << format("%8" PRIx64 ":", Address); if (!NoShowRawInsn) { OS << "\t"; dumpBytes(Bytes.slice(0, 4), OS); @@ -570,6 +593,9 @@ public: void printInst(MCInstPrinter &IP, const MCInst *MI, ArrayRef<uint8_t> Bytes, uint64_t Address, raw_ostream &OS, StringRef Annot, MCSubtargetInfo const &STI, SourcePrinter *SP) override { + if (SP && (PrintSource || PrintLines)) + SP->printSourceLine(OS, Address); + if (!MI) { OS << " <unknown>"; return; @@ -601,7 +627,8 @@ public: MCSubtargetInfo const &STI, SourcePrinter *SP) override { if (SP && (PrintSource || PrintLines)) SP->printSourceLine(OS, Address); - OS << format("%8" PRId64 ":", Address / 8); + if (!NoLeadingAddr) + OS << format("%8" PRId64 ":", Address / 8); if (!NoShowRawInsn) { OS << "\t"; dumpBytes(Bytes, OS); @@ -1091,6 +1118,52 @@ static uint8_t getElfSymbolType(const ObjectFile *Obj, const SymbolRef &Sym) { llvm_unreachable("Unsupported binary format"); } +template <class ELFT> static void +addDynamicElfSymbols(const ELFObjectFile<ELFT> *Obj, + std::map<SectionRef, SectionSymbolsTy> &AllSymbols) { + for (auto Symbol : Obj->getDynamicSymbolIterators()) { + uint8_t SymbolType = Symbol.getELFType(); + if (SymbolType != ELF::STT_FUNC || Symbol.getSize() == 0) + continue; + + Expected<uint64_t> AddressOrErr = Symbol.getAddress(); + if (!AddressOrErr) + report_error(Obj->getFileName(), AddressOrErr.takeError()); + uint64_t Address = *AddressOrErr; + + Expected<StringRef> Name = Symbol.getName(); + if (!Name) + report_error(Obj->getFileName(), Name.takeError()); + if (Name->empty()) + continue; + + Expected<section_iterator> SectionOrErr = Symbol.getSection(); + if (!SectionOrErr) + report_error(Obj->getFileName(), SectionOrErr.takeError()); + section_iterator SecI = *SectionOrErr; + if (SecI == Obj->section_end()) + continue; + + AllSymbols[*SecI].emplace_back(Address, *Name, SymbolType); + } +} + +static void +addDynamicElfSymbols(const ObjectFile *Obj, + std::map<SectionRef, SectionSymbolsTy> &AllSymbols) { + assert(Obj->isELF()); + if (auto *Elf32LEObj = dyn_cast<ELF32LEObjectFile>(Obj)) + addDynamicElfSymbols(Elf32LEObj, AllSymbols); + else if (auto *Elf64LEObj = dyn_cast<ELF64LEObjectFile>(Obj)) + addDynamicElfSymbols(Elf64LEObj, AllSymbols); + else if (auto *Elf32BEObj = dyn_cast<ELF32BEObjectFile>(Obj)) + addDynamicElfSymbols(Elf32BEObj, AllSymbols); + else if (auto *Elf64BEObj = cast<ELF64BEObjectFile>(Obj)) + addDynamicElfSymbols(Elf64BEObj, AllSymbols); + else + llvm_unreachable("Unsupported binary format"); +} + static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { if (StartAddress > StopAddress) error("Start address should be less than stop address"); @@ -1165,7 +1238,6 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { // Create a mapping from virtual address to symbol name. This is used to // pretty print the symbols while disassembling. - typedef std::vector<std::tuple<uint64_t, StringRef, uint8_t>> SectionSymbolsTy; std::map<SectionRef, SectionSymbolsTy> AllSymbols; for (const SymbolRef &Symbol : Obj->symbols()) { Expected<uint64_t> AddressOrErr = Symbol.getAddress(); @@ -1193,6 +1265,8 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { AllSymbols[*SecI].emplace_back(Address, *Name, SymbolType); } + if (AllSymbols.empty() && Obj->isELF()) + addDynamicElfSymbols(Obj, AllSymbols); // Create a mapping from virtual address to section. std::vector<std::pair<uint64_t, SectionRef>> SectionAddresses; @@ -1811,9 +1885,9 @@ void llvm::printExportsTrie(const ObjectFile *o) { } } -void llvm::printRebaseTable(const ObjectFile *o) { +void llvm::printRebaseTable(ObjectFile *o) { outs() << "Rebase table:\n"; - if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o)) + if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o)) printMachORebaseTable(MachO); else { errs() << "This operation is only currently supported " @@ -1822,9 +1896,9 @@ void llvm::printRebaseTable(const ObjectFile *o) { } } -void llvm::printBindTable(const ObjectFile *o) { +void llvm::printBindTable(ObjectFile *o) { outs() << "Bind table:\n"; - if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o)) + if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o)) printMachOBindTable(MachO); else { errs() << "This operation is only currently supported " @@ -1833,9 +1907,9 @@ void llvm::printBindTable(const ObjectFile *o) { } } -void llvm::printLazyBindTable(const ObjectFile *o) { +void llvm::printLazyBindTable(ObjectFile *o) { outs() << "Lazy bind table:\n"; - if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o)) + if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o)) printMachOLazyBindTable(MachO); else { errs() << "This operation is only currently supported " @@ -1844,9 +1918,9 @@ void llvm::printLazyBindTable(const ObjectFile *o) { } } -void llvm::printWeakBindTable(const ObjectFile *o) { +void llvm::printWeakBindTable(ObjectFile *o) { outs() << "Weak bind table:\n"; - if (const MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o)) + if (MachOObjectFile *MachO = dyn_cast<MachOObjectFile>(o)) printMachOWeakBindTable(MachO); else { errs() << "This operation is only currently supported " @@ -1944,7 +2018,7 @@ static void printPrivateFileHeaders(const ObjectFile *o, bool onlyFirst) { report_error(o->getFileName(), "Invalid/Unsupported object file format"); } -static void DumpObject(const ObjectFile *o, const Archive *a = nullptr) { +static void DumpObject(ObjectFile *o, const Archive *a = nullptr) { StringRef ArchiveName = a != nullptr ? a->getFileName() : ""; // Avoid other output when using a raw option. if (!RawClangAST) { diff --git a/tools/llvm-objdump/llvm-objdump.h b/tools/llvm-objdump/llvm-objdump.h index dace82af3d07..2fcd506884b1 100644 --- a/tools/llvm-objdump/llvm-objdump.h +++ b/tools/llvm-objdump/llvm-objdump.h @@ -35,6 +35,7 @@ extern cl::list<std::string> FilterSections; extern cl::opt<bool> Disassemble; extern cl::opt<bool> DisassembleAll; extern cl::opt<bool> NoShowRawInsn; +extern cl::opt<bool> NoLeadingAddr; extern cl::opt<bool> PrivateHeaders; extern cl::opt<bool> FirstPrivateHeader; extern cl::opt<bool> ExportsTrie; @@ -69,10 +70,10 @@ void ParseInputMachO(StringRef Filename); void printCOFFUnwindInfo(const object::COFFObjectFile* o); void printMachOUnwindInfo(const object::MachOObjectFile* o); void printMachOExportsTrie(const object::MachOObjectFile* o); -void printMachORebaseTable(const object::MachOObjectFile* o); -void printMachOBindTable(const object::MachOObjectFile* o); -void printMachOLazyBindTable(const object::MachOObjectFile* o); -void printMachOWeakBindTable(const object::MachOObjectFile* o); +void printMachORebaseTable(object::MachOObjectFile* o); +void printMachOBindTable(object::MachOObjectFile* o); +void printMachOLazyBindTable(object::MachOObjectFile* o); +void printMachOWeakBindTable(object::MachOObjectFile* o); void printELFFileHeader(const object::ObjectFile *o); void printCOFFFileHeader(const object::ObjectFile *o); void printCOFFSymbolTable(const object::COFFImportFile *i); @@ -81,10 +82,10 @@ void printMachOFileHeader(const object::ObjectFile *o); void printMachOLoadCommands(const object::ObjectFile *o); void printWasmFileHeader(const object::ObjectFile *o); void printExportsTrie(const object::ObjectFile *o); -void printRebaseTable(const object::ObjectFile *o); -void printBindTable(const object::ObjectFile *o); -void printLazyBindTable(const object::ObjectFile *o); -void printWeakBindTable(const object::ObjectFile *o); +void printRebaseTable(object::ObjectFile *o); +void printBindTable(object::ObjectFile *o); +void printLazyBindTable(object::ObjectFile *o); +void printWeakBindTable(object::ObjectFile *o); void printRawClangAST(const object::ObjectFile *o); void PrintRelocations(const object::ObjectFile *o); void PrintSectionHeaders(const object::ObjectFile *o); |