X-Git-Url: http://plrg.eecs.uci.edu/git/?p=oota-llvm.git;a=blobdiff_plain;f=tools%2Fllvm-objdump%2Fllvm-objdump.cpp;h=a2c43e11a78ed6e925ec55a53e44d33a7168817d;hp=22f5519f5008a6a598d0256dfb7027a70a930b62;hb=f2765767e6131c9b9b50acd53d58b54717fbd7c7;hpb=0de20884796d0806e2e3541d8e925bb4b3c5bf9e diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 22f5519f500..a2c43e11a78 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -189,7 +189,7 @@ public: : Predicate(P), Iterator(I), End(E) { ScanPredicate(); } - llvm::object::SectionRef operator*() const { return *Iterator; } + const llvm::object::SectionRef &operator*() const { return *Iterator; } SectionFilterIterator &operator++() { ++Iterator; ScanPredicate(); @@ -252,7 +252,7 @@ void llvm::error(std::error_code EC) { exit(1); } -static void report_error(StringRef File, std::error_code EC) { +void llvm::report_error(StringRef File, std::error_code EC) { assert(EC); errs() << ToolName << ": '" << File << "': " << EC.message() << ".\n"; exit(1); @@ -282,10 +282,8 @@ static const Target *getTarget(const ObjectFile *Obj = nullptr) { std::string Error; const Target *TheTarget = TargetRegistry::lookupTarget(ArchName, TheTriple, Error); - if (!TheTarget) { - errs() << ToolName << ": " << Error; - return nullptr; - } + if (!TheTarget) + report_fatal_error("can't find target: " + Error); // Update the triple name and return the found target. TripleName = TheTriple.getTriple(); @@ -378,11 +376,12 @@ PrettyPrinter &selectPrettyPrinter(Triple const &Triple) { template static std::error_code getRelocationValueString(const ELFObjectFile *Obj, - DataRefImpl Rel, + const RelocationRef &RelRef, SmallVectorImpl &Result) { + DataRefImpl Rel = RelRef.getRawDataRefImpl(); + typedef typename ELFObjectFile::Elf_Sym Elf_Sym; typedef typename ELFObjectFile::Elf_Shdr Elf_Shdr; - typedef typename ELFObjectFile::Elf_Rel Elf_Rel; typedef typename ELFObjectFile::Elf_Rela Elf_Rela; const ELFFile &EF = *Obj->getELFFile(); @@ -404,36 +403,31 @@ static std::error_code getRelocationValueString(const ELFObjectFile *Obj, if (std::error_code EC = StrTabOrErr.getError()) return EC; StringRef StrTab = *StrTabOrErr; - uint8_t type; + uint8_t type = RelRef.getType(); StringRef res; int64_t addend = 0; - uint16_t symbol_index = 0; switch (Sec->sh_type) { default: return object_error::parse_failed; case ELF::SHT_REL: { - const Elf_Rel *ERel = Obj->getRel(Rel); - type = ERel->getType(EF.isMips64EL()); - symbol_index = ERel->getSymbol(EF.isMips64EL()); // TODO: Read implicit addend from section data. break; } case ELF::SHT_RELA: { const Elf_Rela *ERela = Obj->getRela(Rel); - type = ERela->getType(EF.isMips64EL()); - symbol_index = ERela->getSymbol(EF.isMips64EL()); addend = ERela->r_addend; break; } } - const Elf_Sym *symb = - EF.template getEntry(Sec->sh_link, symbol_index); + symbol_iterator SI = RelRef.getSymbol(); + const Elf_Sym *symb = Obj->getSymbol(SI->getRawDataRefImpl()); StringRef Target; - ErrorOr SymSec = EF.getSection(symb); - if (std::error_code EC = SymSec.getError()) - return EC; if (symb->getType() == ELF::STT_SECTION) { - ErrorOr SecName = EF.getSectionName(*SymSec); + ErrorOr SymSI = SI->getSection(); + if (std::error_code EC = SymSI.getError()) + return EC; + const Elf_Shdr *SymSec = Obj->getSection((*SymSI)->getRawDataRefImpl()); + ErrorOr SecName = EF.getSectionName(SymSec); if (std::error_code EC = SecName.getError()) return EC; Target = *SecName; @@ -481,6 +475,7 @@ static std::error_code getRelocationValueString(const ELFObjectFile *Obj, break; } case ELF::EM_386: + case ELF::EM_IAMCU: case ELF::EM_ARM: case ELF::EM_HEXAGON: case ELF::EM_MIPS: @@ -495,9 +490,8 @@ static std::error_code getRelocationValueString(const ELFObjectFile *Obj, } static std::error_code getRelocationValueString(const ELFObjectFileBase *Obj, - const RelocationRef &RelRef, + const RelocationRef &Rel, SmallVectorImpl &Result) { - DataRefImpl Rel = RelRef.getRawDataRefImpl(); if (auto *ELF32LE = dyn_cast(Obj)) return getRelocationValueString(ELF32LE, Rel, Result); if (auto *ELF64LE = dyn_cast(Obj)) @@ -809,10 +803,6 @@ static bool getHidden(RelocationRef RelRef) { static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { const Target *TheTarget = getTarget(Obj); - // getTarget() will have already issued a diagnostic if necessary, so - // just bail here if it failed. - if (!TheTarget) - return; // Package up features to be passed to target/subtarget std::string FeaturesStr; @@ -890,27 +880,66 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { } // Create a mapping from virtual address to symbol name. This is used to - // pretty print the target of a call. - std::vector> AllSymbols; - if (MIA) { - for (const SymbolRef &Symbol : Obj->symbols()) { - if (Symbol.getType() != SymbolRef::ST_Function) - continue; + // pretty print the symbols while disassembling. + typedef std::vector> SectionSymbolsTy; + std::map AllSymbols; + for (const SymbolRef &Symbol : Obj->symbols()) { + ErrorOr AddressOrErr = Symbol.getAddress(); + error(AddressOrErr.getError()); + uint64_t Address = *AddressOrErr; + + ErrorOr Name = Symbol.getName(); + error(Name.getError()); + if (Name->empty()) + continue; - ErrorOr AddressOrErr = Symbol.getAddress(); - error(AddressOrErr.getError()); - uint64_t Address = *AddressOrErr; + ErrorOr SectionOrErr = Symbol.getSection(); + error(SectionOrErr.getError()); + section_iterator SecI = *SectionOrErr; + if (SecI == Obj->section_end()) + continue; - ErrorOr Name = Symbol.getName(); - error(Name.getError()); - if (Name->empty()) + AllSymbols[*SecI].emplace_back(Address, *Name); + } + + // Create a mapping from virtual address to section. + std::vector> SectionAddresses; + for (SectionRef Sec : Obj->sections()) + SectionAddresses.emplace_back(Sec.getAddress(), Sec); + array_pod_sort(SectionAddresses.begin(), SectionAddresses.end()); + + // Linked executables (.exe and .dll files) typically don't include a real + // symbol table but they might contain an export table. + if (const auto *COFFObj = dyn_cast(Obj)) { + for (const auto &ExportEntry : COFFObj->export_directories()) { + StringRef Name; + error(ExportEntry.getSymbolName(Name)); + if (Name.empty()) continue; - AllSymbols.push_back(std::make_pair(Address, *Name)); - } + uint32_t RVA; + error(ExportEntry.getExportRVA(RVA)); + + uint64_t VA = COFFObj->getImageBase() + RVA; + auto Sec = std::upper_bound( + SectionAddresses.begin(), SectionAddresses.end(), VA, + [](uint64_t LHS, const std::pair &RHS) { + return LHS < RHS.first; + }); + if (Sec != SectionAddresses.begin()) + --Sec; + else + Sec = SectionAddresses.end(); - array_pod_sort(AllSymbols.begin(), AllSymbols.end()); + if (Sec != SectionAddresses.end()) + AllSymbols[Sec->second].emplace_back(VA, Name); + } } + // Sort all the symbols, this allows us to use a simple binary search to find + // a symbol near an address. + for (std::pair &SecSyms : AllSymbols) + array_pod_sort(SecSyms.second.begin(), SecSyms.second.end()); + for (const SectionRef &Section : ToolSectionFilter(*Obj)) { if (!DisassembleAll && (!Section.isText() || Section.isVirtual())) continue; @@ -920,25 +949,23 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { if (!SectSize) continue; - // Make a list of all the symbols in this section. - std::vector> Symbols; - for (const SymbolRef &Symbol : Obj->symbols()) { - if (Section.containsSymbol(Symbol)) { - ErrorOr AddressOrErr = Symbol.getAddress(); - error(AddressOrErr.getError()); - uint64_t Address = *AddressOrErr; - Address -= SectionAddr; - if (Address >= SectSize) - continue; - - ErrorOr Name = Symbol.getName(); - error(Name.getError()); - Symbols.push_back(std::make_pair(Address, *Name)); + // Get the list of all the symbols in this section. + SectionSymbolsTy &Symbols = AllSymbols[Section]; + std::vector DataMappingSymsAddr; + std::vector TextMappingSymsAddr; + if (Obj->isELF() && Obj->getArch() == Triple::aarch64) { + for (const auto &Symb : Symbols) { + uint64_t Address = Symb.first; + StringRef Name = Symb.second; + if (Name.startswith("$d")) + DataMappingSymsAddr.push_back(Address - SectionAddr); + if (Name.startswith("$x")) + TextMappingSymsAddr.push_back(Address - SectionAddr); } } - // Sort the symbols by address, just in case they didn't come in that way. - array_pod_sort(Symbols.begin(), Symbols.end()); + std::sort(DataMappingSymsAddr.begin(), DataMappingSymsAddr.end()); + std::sort(TextMappingSymsAddr.begin(), TextMappingSymsAddr.end()); // Make a list of all the relocations for this section. std::vector Rels; @@ -967,7 +994,7 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { // If the section has no symbol at the start, just insert a dummy one. if (Symbols.empty() || Symbols[0].first != 0) - Symbols.insert(Symbols.begin(), std::make_pair(0, name)); + Symbols.insert(Symbols.begin(), std::make_pair(SectionAddr, name)); SmallString<40> Comments; raw_svector_ostream CommentStream(Comments); @@ -985,11 +1012,16 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { // Disassemble symbol by symbol. for (unsigned si = 0, se = Symbols.size(); si != se; ++si) { - uint64_t Start = Symbols[si].first; - // The end is either the section end or the beginning of the next symbol. - uint64_t End = (si == se - 1) ? SectSize : Symbols[si + 1].first; + uint64_t Start = Symbols[si].first - SectionAddr; + // The end is either the section end or the beginning of the next + // symbol. + uint64_t End = + (si == se - 1) ? SectSize : Symbols[si + 1].first - SectionAddr; + // Don't try to disassemble beyond the end of section contents. + if (End > SectSize) + End = SectSize; // If this symbol has the same address as the next symbol, then skip it. - if (Start == End) + if (Start >= End) continue; outs() << '\n' << Symbols[si].second << ":\n"; @@ -1003,6 +1035,45 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { for (Index = Start; Index < End; Index += Size) { MCInst Inst; + // AArch64 ELF binaries can interleave data and text in the + // same section. We rely on the markers introduced to + // understand what we need to dump. + if (Obj->isELF() && Obj->getArch() == Triple::aarch64) { + uint64_t Stride = 0; + + auto DAI = std::lower_bound(DataMappingSymsAddr.begin(), + DataMappingSymsAddr.end(), Index); + if (DAI != DataMappingSymsAddr.end() && *DAI == Index) { + // Switch to data. + while (Index < End) { + outs() << format("%8" PRIx64 ":", SectionAddr + Index); + outs() << "\t"; + if (Index + 4 <= End) { + Stride = 4; + dumpBytes(Bytes.slice(Index, 4), outs()); + outs() << "\t.word"; + } else if (Index + 2 <= End) { + Stride = 2; + dumpBytes(Bytes.slice(Index, 2), outs()); + outs() << "\t.short"; + } else { + Stride = 1; + dumpBytes(Bytes.slice(Index, 1), outs()); + outs() << "\t.byte"; + } + Index += Stride; + outs() << "\n"; + auto TAI = std::lower_bound(TextMappingSymsAddr.begin(), + TextMappingSymsAddr.end(), Index); + if (TAI != TextMappingSymsAddr.end() && *TAI == Index) + break; + } + } + } + + if (Index >= End) + break; + if (DisAsm->getInstruction(Inst, Size, Bytes.slice(Index), SectionAddr + Index, DebugOut, CommentStream)) { @@ -1011,26 +1082,55 @@ static void DisassembleObject(const ObjectFile *Obj, bool InlineRelocs) { SectionAddr + Index, outs(), "", *STI); outs() << CommentStream.str(); Comments.clear(); + + // Try to resolve the target of a call, tail call, etc. to a specific + // symbol. if (MIA && (MIA->isCall(Inst) || MIA->isUnconditionalBranch(Inst) || MIA->isConditionalBranch(Inst))) { uint64_t Target; if (MIA->evaluateBranch(Inst, SectionAddr + Index, Size, Target)) { - auto TargetSym = std::upper_bound( - AllSymbols.begin(), AllSymbols.end(), Target, - [](uint64_t LHS, const std::pair &RHS) { - return LHS < RHS.first; - }); - if (TargetSym != AllSymbols.begin()) - --TargetSym; - else - TargetSym = AllSymbols.end(); - - if (TargetSym != AllSymbols.end()) { - outs() << " <" << TargetSym->second; - uint64_t Disp = Target - TargetSym->first; - if (Disp) - outs() << '+' << utohexstr(Disp); - outs() << '>'; + // In a relocatable object, the target's section must reside in + // the same section as the call instruction or it is accessed + // through a relocation. + // + // In a non-relocatable object, the target may be in any section. + // + // N.B. We don't walk the relocations in the relocatable case yet. + auto *TargetSectionSymbols = &Symbols; + if (!Obj->isRelocatableObject()) { + auto SectionAddress = std::upper_bound( + SectionAddresses.begin(), SectionAddresses.end(), Target, + [](uint64_t LHS, + const std::pair &RHS) { + return LHS < RHS.first; + }); + if (SectionAddress != SectionAddresses.begin()) { + --SectionAddress; + TargetSectionSymbols = &AllSymbols[SectionAddress->second]; + } else { + TargetSectionSymbols = nullptr; + } + } + + // Find the first symbol in the section whose offset is less than + // or equal to the target. + if (TargetSectionSymbols) { + auto TargetSym = std::upper_bound( + TargetSectionSymbols->begin(), TargetSectionSymbols->end(), + Target, [](uint64_t LHS, + const std::pair &RHS) { + return LHS < RHS.first; + }); + if (TargetSym != TargetSectionSymbols->begin()) { + --TargetSym; + uint64_t TargetAddress = std::get<0>(*TargetSym); + StringRef TargetName = std::get<1>(*TargetSym); + outs() << " <" << TargetName; + uint64_t Disp = Target - TargetAddress; + if (Disp) + outs() << '+' << utohexstr(Disp); + outs() << '>'; + } } } } @@ -1225,8 +1325,9 @@ void llvm::PrintSymbolTable(const ObjectFile *o) { uint64_t Address = *AddressOrError; SymbolRef::Type Type = Symbol.getType(); uint32_t Flags = Symbol.getFlags(); - section_iterator Section = o->section_end(); - error(Symbol.getSection(Section)); + ErrorOr SectionOrErr = Symbol.getSection(); + error(SectionOrErr.getError()); + section_iterator Section = *SectionOrErr; StringRef Name; if (Type == SymbolRef::ST_Debug && Section != o->section_end()) { Section->getName(Name); @@ -1491,7 +1592,10 @@ static void DumpObject(const ObjectFile *o) { /// @brief Dump each object file in \a a; static void DumpArchive(const Archive *a) { - for (const Archive::Child &C : a->children()) { + for (auto &ErrorOrChild : a->children()) { + if (std::error_code EC = ErrorOrChild.getError()) + report_error(a->getFileName(), EC); + const Archive::Child &C = *ErrorOrChild; ErrorOr> ChildOrErr = C.getAsBinary(); if (std::error_code EC = ChildOrErr.getError()) if (EC != object_error::invalid_file_type) @@ -1505,9 +1609,6 @@ static void DumpArchive(const Archive *a) { /// @brief Open file and figure out how to dump it. static void DumpInput(StringRef file) { - // If file isn't stdin, check that it exists. - if (file != "-" && !sys::fs::exists(file)) - report_error(file, errc::no_such_file_or_directory); // If we are using the Mach-O specific object file parser, then let it parse // the file and process the command line options. So the -arch flags can @@ -1540,7 +1641,6 @@ int main(int argc, char **argv) { // Initialize targets and assembly printers/parsers. llvm::InitializeAllTargetInfos(); llvm::InitializeAllTargetMCs(); - llvm::InitializeAllAsmParsers(); llvm::InitializeAllDisassemblers(); // Register the target printer for --version.