summaryrefslogtreecommitdiffstats
path: root/llvm/tools/llvm-objdump/MachODump.cpp
diff options
context:
space:
mode:
Diffstat (limited to 'llvm/tools/llvm-objdump/MachODump.cpp')
-rw-r--r--llvm/tools/llvm-objdump/MachODump.cpp258
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) {
OpenPOWER on IntegriCloud