diff options
Diffstat (limited to 'llvm/tools/llvm-objdump/MachODump.cpp')
-rw-r--r-- | llvm/tools/llvm-objdump/MachODump.cpp | 258 |
1 files changed, 258 insertions, 0 deletions
diff --git a/llvm/tools/llvm-objdump/MachODump.cpp b/llvm/tools/llvm-objdump/MachODump.cpp index 5ef7058ec9d..4edff8e6ae0 100644 --- a/llvm/tools/llvm-objdump/MachODump.cpp +++ b/llvm/tools/llvm-objdump/MachODump.cpp @@ -342,6 +342,264 @@ static void getSectionsAndSymbols(MachOObjectFile *MachOObj, } } +static void printRelocationTargetName(const MachOObjectFile *O, + const MachO::any_relocation_info &RE, + raw_string_ostream &Fmt) { + // Target of a scattered relocation is an address. In the interest of + // generating pretty output, scan through the symbol table looking for a + // symbol that aligns with that address. If we find one, print it. + // Otherwise, we just print the hex address of the target. + if (O->isRelocationScattered(RE)) { + uint32_t Val = O->getPlainRelocationSymbolNum(RE); + + for (const SymbolRef &Symbol : O->symbols()) { + Expected<uint64_t> Addr = Symbol.getAddress(); + if (!Addr) + report_error(O->getFileName(), Addr.takeError()); + if (*Addr != Val) + continue; + Expected<StringRef> Name = Symbol.getName(); + if (!Name) + report_error(O->getFileName(), Name.takeError()); + Fmt << *Name; + return; + } + + // If we couldn't find a symbol that this relocation refers to, try + // to find a section beginning instead. + for (const SectionRef &Section : ToolSectionFilter(*O)) { + std::error_code ec; + + StringRef Name; + uint64_t Addr = Section.getAddress(); + if (Addr != Val) + continue; + if ((ec = Section.getName(Name))) + report_error(O->getFileName(), ec); + Fmt << Name; + return; + } + + Fmt << format("0x%x", Val); + return; + } + + StringRef S; + bool isExtern = O->getPlainRelocationExternal(RE); + uint64_t Val = O->getPlainRelocationSymbolNum(RE); + + if (O->getAnyRelocationType(RE) == MachO::ARM64_RELOC_ADDEND) { + Fmt << format("0x%0" PRIx64, Val); + return; + } + + if (isExtern) { + symbol_iterator SI = O->symbol_begin(); + advance(SI, Val); + Expected<StringRef> SOrErr = SI->getName(); + if (!SOrErr) + report_error(O->getFileName(), SOrErr.takeError()); + S = *SOrErr; + } else { + section_iterator SI = O->section_begin(); + // Adjust for the fact that sections are 1-indexed. + if (Val == 0) { + Fmt << "0 (?,?)"; + return; + } + uint32_t I = Val - 1; + while (I != 0 && SI != O->section_end()) { + --I; + advance(SI, 1); + } + if (SI == O->section_end()) + Fmt << Val << " (?,?)"; + else + SI->getName(S); + } + + Fmt << S; +} + +std::error_code +llvm::getMachORelocationValueString(const MachOObjectFile *Obj, + const RelocationRef &RelRef, + SmallVectorImpl<char> &Result) { + DataRefImpl Rel = RelRef.getRawDataRefImpl(); + MachO::any_relocation_info RE = Obj->getRelocation(Rel); + + unsigned Arch = Obj->getArch(); + + std::string FmtBuf; + raw_string_ostream Fmt(FmtBuf); + unsigned Type = Obj->getAnyRelocationType(RE); + bool IsPCRel = Obj->getAnyRelocationPCRel(RE); + + // Determine any addends that should be displayed with the relocation. + // These require decoding the relocation type, which is triple-specific. + + // X86_64 has entirely custom relocation types. + if (Arch == Triple::x86_64) { + switch (Type) { + case MachO::X86_64_RELOC_GOT_LOAD: + case MachO::X86_64_RELOC_GOT: { + printRelocationTargetName(Obj, RE, Fmt); + Fmt << "@GOT"; + if (IsPCRel) + Fmt << "PCREL"; + break; + } + case MachO::X86_64_RELOC_SUBTRACTOR: { + DataRefImpl RelNext = Rel; + Obj->moveRelocationNext(RelNext); + MachO::any_relocation_info RENext = Obj->getRelocation(RelNext); + + // X86_64_RELOC_SUBTRACTOR must be followed by a relocation of type + // X86_64_RELOC_UNSIGNED. + // NOTE: Scattered relocations don't exist on x86_64. + unsigned RType = Obj->getAnyRelocationType(RENext); + if (RType != MachO::X86_64_RELOC_UNSIGNED) + report_error(Obj->getFileName(), "Expected X86_64_RELOC_UNSIGNED after " + "X86_64_RELOC_SUBTRACTOR."); + + // The X86_64_RELOC_UNSIGNED contains the minuend symbol; + // X86_64_RELOC_SUBTRACTOR contains the subtrahend. + printRelocationTargetName(Obj, RENext, Fmt); + Fmt << "-"; + printRelocationTargetName(Obj, RE, Fmt); + break; + } + case MachO::X86_64_RELOC_TLV: + printRelocationTargetName(Obj, RE, Fmt); + Fmt << "@TLV"; + if (IsPCRel) + Fmt << "P"; + break; + case MachO::X86_64_RELOC_SIGNED_1: + printRelocationTargetName(Obj, RE, Fmt); + Fmt << "-1"; + break; + case MachO::X86_64_RELOC_SIGNED_2: + printRelocationTargetName(Obj, RE, Fmt); + Fmt << "-2"; + break; + case MachO::X86_64_RELOC_SIGNED_4: + printRelocationTargetName(Obj, RE, Fmt); + Fmt << "-4"; + break; + default: + printRelocationTargetName(Obj, RE, Fmt); + break; + } + // X86 and ARM share some relocation types in common. + } else if (Arch == Triple::x86 || Arch == Triple::arm || + Arch == Triple::ppc) { + // Generic relocation types... + switch (Type) { + case MachO::GENERIC_RELOC_PAIR: // prints no info + return std::error_code(); + case MachO::GENERIC_RELOC_SECTDIFF: { + DataRefImpl RelNext = Rel; + Obj->moveRelocationNext(RelNext); + MachO::any_relocation_info RENext = Obj->getRelocation(RelNext); + + // X86 sect diff's must be followed by a relocation of type + // GENERIC_RELOC_PAIR. + unsigned RType = Obj->getAnyRelocationType(RENext); + + if (RType != MachO::GENERIC_RELOC_PAIR) + report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after " + "GENERIC_RELOC_SECTDIFF."); + + printRelocationTargetName(Obj, RE, Fmt); + Fmt << "-"; + printRelocationTargetName(Obj, RENext, Fmt); + break; + } + } + + if (Arch == Triple::x86 || Arch == Triple::ppc) { + switch (Type) { + case MachO::GENERIC_RELOC_LOCAL_SECTDIFF: { + DataRefImpl RelNext = Rel; + Obj->moveRelocationNext(RelNext); + MachO::any_relocation_info RENext = Obj->getRelocation(RelNext); + + // X86 sect diff's must be followed by a relocation of type + // GENERIC_RELOC_PAIR. + unsigned RType = Obj->getAnyRelocationType(RENext); + if (RType != MachO::GENERIC_RELOC_PAIR) + report_error(Obj->getFileName(), "Expected GENERIC_RELOC_PAIR after " + "GENERIC_RELOC_LOCAL_SECTDIFF."); + + printRelocationTargetName(Obj, RE, Fmt); + Fmt << "-"; + printRelocationTargetName(Obj, RENext, Fmt); + break; + } + case MachO::GENERIC_RELOC_TLV: { + printRelocationTargetName(Obj, RE, Fmt); + Fmt << "@TLV"; + if (IsPCRel) + Fmt << "P"; + break; + } + default: + printRelocationTargetName(Obj, RE, Fmt); + } + } else { // ARM-specific relocations + switch (Type) { + case MachO::ARM_RELOC_HALF: + case MachO::ARM_RELOC_HALF_SECTDIFF: { + // Half relocations steal a bit from the length field to encode + // whether this is an upper16 or a lower16 relocation. + bool isUpper = (Obj->getAnyRelocationLength(RE) & 0x1) == 1; + + if (isUpper) + Fmt << ":upper16:("; + else + Fmt << ":lower16:("; + printRelocationTargetName(Obj, RE, Fmt); + + DataRefImpl RelNext = Rel; + Obj->moveRelocationNext(RelNext); + MachO::any_relocation_info RENext = Obj->getRelocation(RelNext); + + // ARM half relocs must be followed by a relocation of type + // ARM_RELOC_PAIR. + unsigned RType = Obj->getAnyRelocationType(RENext); + if (RType != MachO::ARM_RELOC_PAIR) + report_error(Obj->getFileName(), "Expected ARM_RELOC_PAIR after " + "ARM_RELOC_HALF"); + + // NOTE: The half of the target virtual address is stashed in the + // address field of the secondary relocation, but we can't reverse + // engineer the constant offset from it without decoding the movw/movt + // instruction to find the other half in its immediate field. + + // ARM_RELOC_HALF_SECTDIFF encodes the second section in the + // symbol/section pointer of the follow-on relocation. + if (Type == MachO::ARM_RELOC_HALF_SECTDIFF) { + Fmt << "-"; + printRelocationTargetName(Obj, RENext, Fmt); + } + + Fmt << ")"; + break; + } + default: { + printRelocationTargetName(Obj, RE, Fmt); + } + } + } + } else + printRelocationTargetName(Obj, RE, Fmt); + + Fmt.flush(); + Result.append(FmtBuf.begin(), FmtBuf.end()); + return std::error_code(); +} + static void PrintIndirectSymbolTable(MachOObjectFile *O, bool verbose, uint32_t n, uint32_t count, uint32_t stride, uint64_t addr) { |