From f759032ccd3709dcd7362b0ed51760ee4e47025a Mon Sep 17 00:00:00 2001 From: Kevin Enderby Date: Mon, 18 Aug 2014 20:21:02 +0000 Subject: [PATCH] Make llvm-objdump handle both arm and thumb disassembly from the same Mach-O file with -macho, the Mach-O specific object file parser option. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After some discussion I chose to do this implementation contained in the logic of llvm-objdump’s MachODump.cpp using a second disassembler for thumb when needed and with updates mostly contained in the MachOObjectFile class. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@215931 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Object/MachO.h | 8 +- include/llvm/Object/SymbolicFile.h | 3 +- lib/Object/MachOObjectFile.cpp | 85 +++++++++++++++++- .../llvm-objdump/ARM/macho-arm-and-thumb.test | 15 ++++ tools/llvm-objdump/MachODump.cpp | 87 ++++++++++++++++--- 5 files changed, 185 insertions(+), 13 deletions(-) create mode 100644 test/tools/llvm-objdump/ARM/macho-arm-and-thumb.test diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h index 539f1569a05..3319b789942 100644 --- a/include/llvm/Object/MachO.h +++ b/include/llvm/Object/MachO.h @@ -137,6 +137,7 @@ public: StringRef getFileFormatName() const override; unsigned getArch() const override; + Triple getArch(const char **McpuDefault, Triple *ThumbTriple) const; relocation_iterator section_rel_begin(unsigned Index) const; relocation_iterator section_rel_end(unsigned Index) const; @@ -215,7 +216,12 @@ public: StringRef &Suffix); static Triple::ArchType getArch(uint32_t CPUType); - static Triple getArch(uint32_t CPUType, uint32_t CPUSubType); + static Triple getArch(uint32_t CPUType, uint32_t CPUSubType, + const char **McpuDefault = nullptr); + static Triple getThumbArch(uint32_t CPUType, uint32_t CPUSubType, + const char **McpuDefault = nullptr); + static Triple getArch(uint32_t CPUType, uint32_t CPUSubType, + const char **McpuDefault, Triple *ThumbTriple); static bool isValidArch(StringRef ArchFlag); static Triple getHostArch(); diff --git a/include/llvm/Object/SymbolicFile.h b/include/llvm/Object/SymbolicFile.h index 61570de2239..0057ed23abc 100644 --- a/include/llvm/Object/SymbolicFile.h +++ b/include/llvm/Object/SymbolicFile.h @@ -87,8 +87,9 @@ public: SF_Absolute = 1U << 3, // Absolute symbol SF_Common = 1U << 4, // Symbol has common linkage SF_Indirect = 1U << 5, // Symbol is an alias to another symbol - SF_FormatSpecific = 1U << 6 // Specific to the object file format + SF_FormatSpecific = 1U << 6, // Specific to the object file format // (e.g. section symbols) + SF_Thumb = 1U << 7 // Thumb symbol in a 32-bit ARM binary }; BasicSymbolRef() : OwningObject(nullptr) { } diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index afc729f9f82..5bcb4bae8ea 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -439,6 +439,9 @@ uint32_t MachOObjectFile::getSymbolFlags(DataRefImpl DRI) const { if (MachOFlags & (MachO::N_WEAK_REF | MachO::N_WEAK_DEF)) Result |= SymbolRef::SF_Weak; + if (MachOFlags & (MachO::N_ARM_THUMB_DEF)) + Result |= SymbolRef::SF_Thumb; + if ((MachOType & MachO::N_TYPE) == MachO::N_ABS) Result |= SymbolRef::SF_Absolute; @@ -1293,7 +1296,11 @@ Triple::ArchType MachOObjectFile::getArch(uint32_t CPUType) { } } -Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) { +Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType, + const char **McpuDefault) { + if (McpuDefault) + *McpuDefault = nullptr; + switch (CPUType) { case MachO::CPU_TYPE_I386: switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { @@ -1322,14 +1329,20 @@ Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) { case MachO::CPU_SUBTYPE_ARM_V6: return Triple("armv6-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V6M: + if (McpuDefault) + *McpuDefault = "cortex-m0"; return Triple("armv6m-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V7: return Triple("armv7-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V7EM: + if (McpuDefault) + *McpuDefault = "cortex-m4"; return Triple("armv7em-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V7K: return Triple("armv7k-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V7M: + if (McpuDefault) + *McpuDefault = "cortex-m3"; return Triple("armv7m-apple-darwin"); case MachO::CPU_SUBTYPE_ARM_V7S: return Triple("armv7s-apple-darwin"); @@ -1362,6 +1375,57 @@ Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType) { } } +Triple MachOObjectFile::getThumbArch(uint32_t CPUType, uint32_t CPUSubType, + const char **McpuDefault) { + if (McpuDefault) + *McpuDefault = nullptr; + + switch (CPUType) { + case MachO::CPU_TYPE_ARM: + switch (CPUSubType & ~MachO::CPU_SUBTYPE_MASK) { + case MachO::CPU_SUBTYPE_ARM_V4T: + return Triple("thumbv4t-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V5TEJ: + return Triple("thumbv5e-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_XSCALE: + return Triple("xscale-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V6: + return Triple("thumbv6-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V6M: + if (McpuDefault) + *McpuDefault = "cortex-m0"; + return Triple("thumbv6m-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7: + return Triple("thumbv7-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7EM: + if (McpuDefault) + *McpuDefault = "cortex-m4"; + return Triple("thumbv7em-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7K: + return Triple("thumbv7k-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7M: + if (McpuDefault) + *McpuDefault = "cortex-m3"; + return Triple("thumbv7m-apple-darwin"); + case MachO::CPU_SUBTYPE_ARM_V7S: + return Triple("thumbv7s-apple-darwin"); + default: + return Triple(); + } + default: + return Triple(); + } +} + +Triple MachOObjectFile::getArch(uint32_t CPUType, uint32_t CPUSubType, + const char **McpuDefault, + Triple *ThumbTriple) { + Triple T = MachOObjectFile::getArch(CPUType, CPUSubType, McpuDefault); + *ThumbTriple = MachOObjectFile::getThumbArch(CPUType, CPUSubType, + McpuDefault); + return T; +} + Triple MachOObjectFile::getHostArch() { return Triple(sys::getDefaultTargetTriple()); } @@ -1390,6 +1454,25 @@ unsigned MachOObjectFile::getArch() const { return getArch(getCPUType(this)); } +Triple MachOObjectFile::getArch(const char **McpuDefault, + Triple *ThumbTriple) const { + Triple T; + if (is64Bit()) { + MachO::mach_header_64 H_64; + H_64 = getHeader64(); + T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype, McpuDefault); + *ThumbTriple = MachOObjectFile::getThumbArch(H_64.cputype, H_64.cpusubtype, + McpuDefault); + } else { + MachO::mach_header H; + H = getHeader(); + T = MachOObjectFile::getArch(H.cputype, H.cpusubtype, McpuDefault); + *ThumbTriple = MachOObjectFile::getThumbArch(H.cputype, H.cpusubtype, + McpuDefault); + } + return T; +} + relocation_iterator MachOObjectFile::section_rel_begin(unsigned Index) const { DataRefImpl DRI; DRI.d.a = Index; diff --git a/test/tools/llvm-objdump/ARM/macho-arm-and-thumb.test b/test/tools/llvm-objdump/ARM/macho-arm-and-thumb.test new file mode 100644 index 00000000000..720b78fa89e --- /dev/null +++ b/test/tools/llvm-objdump/ARM/macho-arm-and-thumb.test @@ -0,0 +1,15 @@ +@ RUN: llvm-mc < %s -triple armv7-apple-darwin -filetype=obj | llvm-objdump -m -d - | FileCheck %s + +.thumb +.thumb_func _t +_t: +nop +nop +.align 2 +.arm +_a: +nop + +@ CHECK: 00 bf nop +@ CHECK-NEXT: 00 bf nop +@ CHECK: 00 f0 20 e3 nop diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index e6c505d1b3b..1cf92360054 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -50,22 +50,36 @@ static cl::opt static cl::opt DSYMFile("dsym", cl::desc("Use .dSYM file for debug info")); -static const Target *GetTarget(const MachOObjectFile *MachOObj) { +static std::string ThumbTripleName; + +static const Target *GetTarget(const MachOObjectFile *MachOObj, + const char **McpuDefault, + const Target **ThumbTarget) { // Figure out the target triple. if (TripleName.empty()) { llvm::Triple TT("unknown-unknown-unknown"); - TT.setArch(Triple::ArchType(MachOObj->getArch())); + llvm::Triple ThumbTriple = Triple(); + TT = MachOObj->getArch(McpuDefault, &ThumbTriple); TripleName = TT.str(); + ThumbTripleName = ThumbTriple.str(); } // Get the target specific parser. std::string Error; const Target *TheTarget = TargetRegistry::lookupTarget(TripleName, Error); - if (TheTarget) + if (TheTarget && ThumbTripleName.empty()) return TheTarget; - errs() << "llvm-objdump: error: unable to get target for '" << TripleName - << "', see --version and --triple.\n"; + *ThumbTarget = TargetRegistry::lookupTarget(ThumbTripleName, Error); + if (*ThumbTarget) + return TheTarget; + + errs() << "llvm-objdump: error: unable to get target for '"; + if (!TheTarget) + errs() << TripleName; + else + errs() << ThumbTripleName; + errs() << "', see --version and --triple.\n"; return nullptr; } @@ -211,14 +225,26 @@ void llvm::DisassembleInputMachO(StringRef Filename) { static void DisassembleInputMachO2(StringRef Filename, MachOObjectFile *MachOOF) { - const Target *TheTarget = GetTarget(MachOOF); + const char *McpuDefault = nullptr; + const Target *ThumbTarget = nullptr; + const Target *TheTarget = GetTarget(MachOOF, &McpuDefault, &ThumbTarget); if (!TheTarget) { // GetTarget prints out stuff. return; } + if (MCPU.empty() && McpuDefault) + MCPU = McpuDefault; + std::unique_ptr InstrInfo(TheTarget->createMCInstrInfo()); std::unique_ptr InstrAnalysis( TheTarget->createMCInstrAnalysis(InstrInfo.get())); + std::unique_ptr ThumbInstrInfo; + std::unique_ptr ThumbInstrAnalysis; + if (ThumbTarget) { + ThumbInstrInfo.reset(ThumbTarget->createMCInstrInfo()); + ThumbInstrAnalysis.reset( + ThumbTarget->createMCInstrAnalysis(ThumbInstrInfo.get())); + } // Package up features to be passed to target/subtarget std::string FeaturesStr; @@ -238,7 +264,7 @@ static void DisassembleInputMachO2(StringRef Filename, TheTarget->createMCSubtargetInfo(TripleName, MCPU, FeaturesStr)); MCContext Ctx(AsmInfo.get(), MRI.get(), nullptr); std::unique_ptr DisAsm( - TheTarget->createMCDisassembler(*STI, Ctx)); + TheTarget->createMCDisassembler(*STI, Ctx)); int AsmPrinterVariant = AsmInfo->getAssemblerDialect(); std::unique_ptr IP(TheTarget->createMCInstPrinter( AsmPrinterVariant, *AsmInfo, *InstrInfo, *MRI, *STI)); @@ -249,6 +275,34 @@ static void DisassembleInputMachO2(StringRef Filename, return; } + // Set up thumb disassembler. + std::unique_ptr ThumbMRI; + std::unique_ptr ThumbAsmInfo; + std::unique_ptr ThumbSTI; + std::unique_ptr ThumbDisAsm; + std::unique_ptr ThumbIP; + std::unique_ptr ThumbCtx; + if (ThumbTarget) { + ThumbMRI.reset(ThumbTarget->createMCRegInfo(ThumbTripleName)); + ThumbAsmInfo.reset( + ThumbTarget->createMCAsmInfo(*ThumbMRI, ThumbTripleName)); + ThumbSTI.reset( + ThumbTarget->createMCSubtargetInfo(ThumbTripleName, MCPU, FeaturesStr)); + ThumbCtx.reset(new MCContext(ThumbAsmInfo.get(), ThumbMRI.get(), nullptr)); + ThumbDisAsm.reset(ThumbTarget->createMCDisassembler(*ThumbSTI, *ThumbCtx)); + int ThumbAsmPrinterVariant = ThumbAsmInfo->getAssemblerDialect(); + ThumbIP.reset(ThumbTarget->createMCInstPrinter( + ThumbAsmPrinterVariant, *ThumbAsmInfo, *ThumbInstrInfo, *ThumbMRI, + *ThumbSTI)); + } + + if (ThumbTarget && (!ThumbInstrAnalysis || !ThumbAsmInfo || !ThumbSTI || + !ThumbDisAsm || !ThumbIP)) { + errs() << "error: couldn't initialize disassembler for target " + << ThumbTripleName << '\n'; + return; + } + outs() << '\n' << Filename << ":\n\n"; MachO::mach_header Header = MachOOF->getHeader(); @@ -396,6 +450,10 @@ static void DisassembleInputMachO2(StringRef Filename, symbolTableWorked = true; + DataRefImpl Symb = Symbols[SymIdx].getRawDataRefImpl(); + bool isThumb = + (MachOOF->getSymbolFlags(Symb) & SymbolRef::SF_Thumb) && ThumbTarget; + outs() << SymName << ":\n"; DILineInfo lastLine; for (uint64_t Index = Start; Index < End; Index += Size) { @@ -422,10 +480,19 @@ static void DisassembleInputMachO2(StringRef Filename, continue; } - if (DisAsm->getInstruction(Inst, Size, memoryObject, Index, - DebugOut, nulls())) { + bool gotInst; + if (isThumb) + gotInst = ThumbDisAsm->getInstruction(Inst, Size, memoryObject, Index, + DebugOut, nulls()); + else + gotInst = DisAsm->getInstruction(Inst, Size, memoryObject, Index, + DebugOut, nulls()); + if (gotInst) { DumpBytes(StringRef(Bytes.data() + Index, Size)); - IP->printInst(&Inst, outs(), ""); + if (isThumb) + ThumbIP->printInst(&Inst, outs(), ""); + else + IP->printInst(&Inst, outs(), ""); // Print debug info. if (diContext) {