From 291f346efff3d66b797f00523390a3ba25b24548 Mon Sep 17 00:00:00 2001 From: Kevin Enderby Date: Thu, 4 Dec 2014 23:56:27 +0000 Subject: [PATCH] Re-add support to llvm-objdump for Mach-O universal files and archives with -macho with fixes. Includes the move of tests for llvm-objdump for universal files to an X86 directory. And the fix where it was failing on linux Rafael tracked down with asan. I had both Jim Grosbach and Adam Hemet look over the second fix since I could not set up asan to reproduce with the old version but not with the fix. llvm-svn: 223416 --- test/CodeGen/Thumb/iabs.ll | 2 +- .../macho-universal-archive.x86_64.i386 | Bin 0 -> 1656 bytes .../X86/Inputs/macho-universal.x86_64.i386 | Bin 0 -> 16624 bytes .../X86/macho-universal-x86_64.i386.test | 25 ++ tools/llvm-objdump/MachODump.cpp | 255 ++++++++++++++++-- tools/llvm-objdump/llvm-objdump.cpp | 2 +- 6 files changed, 266 insertions(+), 18 deletions(-) create mode 100644 test/tools/llvm-objdump/X86/Inputs/macho-universal-archive.x86_64.i386 create mode 100755 test/tools/llvm-objdump/X86/Inputs/macho-universal.x86_64.i386 create mode 100644 test/tools/llvm-objdump/X86/macho-universal-x86_64.i386.test diff --git a/test/CodeGen/Thumb/iabs.ll b/test/CodeGen/Thumb/iabs.ll index 76224bc5348..ecd4a6b96fa 100644 --- a/test/CodeGen/Thumb/iabs.ll +++ b/test/CodeGen/Thumb/iabs.ll @@ -1,5 +1,5 @@ ; RUN: llc < %s -mtriple=thumb-unknown-unknown -filetype=obj -o %t.o -; RUN: llvm-objdump -disassemble -arch=thumb %t.o | FileCheck %s +; RUN: llvm-objdump -disassemble -arch-name=thumb %t.o | FileCheck %s define i32 @test(i32 %a) { %tmp1neg = sub i32 0, %a diff --git a/test/tools/llvm-objdump/X86/Inputs/macho-universal-archive.x86_64.i386 b/test/tools/llvm-objdump/X86/Inputs/macho-universal-archive.x86_64.i386 new file mode 100644 index 0000000000000000000000000000000000000000..1660714c68ea8e4a638889b1a061153393b376a2 GIT binary patch literal 1656 zcmbVM&1(};5TDf8me`LRJSZrxDCj}cY+9QHMOsW`!HT6#p&rU>Y*SNclM+)J1fft6 z_aOKuc=YH|J%~`D#e@1sSm;5aM-i$1e*50brrL@+FgxEfZ|BXMce}4%i%45UqyzL2 zFewu4qz-6w(G0{P$Ze;u6l*i(tFbd~Un=Q@;Pz*;m(rbNNz3L4Z&x&zr}9eoO0Co^bI zH61IL78a_BD$~k`Z(nxtGZFqE{x$f~9Wo9Oa2)uE@&WM7=;Q1Pz{+e8F-j#ssd}kV z*SwYs`N={kTkf)9n2)h9K!em#S+zc-O3mD>*XApCjZ&$-`D~tUW4~d}XGERT3ZTeW zU0f>8)YWojWxg`2)JV{O>*5*4F?167*t1Pg)1EyQlq!|gT&=iR(gDAouWa%R8QL)U zj3`G$tV^I`@?*e{U=D*iD1HGHeliLq(8nTs_lIkv`@S&Y`CH!FXUBWYDzcIPPU1iK z>iNq%oXJE+}*GBV{j%oJqpp>;V27<8dV+w7h+#W{dS=Xi_RSTo?}JPOyv}K@M9tv}%re v&dI3pDTDI7t#3(thVRMB|3WAHt*LbcAiZ#Idr_F@quiXq;O>H34Cd!2$5XhC literal 0 HcmV?d00001 diff --git a/test/tools/llvm-objdump/X86/Inputs/macho-universal.x86_64.i386 b/test/tools/llvm-objdump/X86/Inputs/macho-universal.x86_64.i386 new file mode 100755 index 0000000000000000000000000000000000000000..36d5fc29d6819ec58acd0572ae720eadd75635a2 GIT binary patch literal 16624 zcmeHNK}%Fo6uwU_hcum{q9|&Tl2XxGWC#&tIiwUNrV&Bh)Oj)kI?BvQ8UzDTFR;bqP&F3T6BORB`bWVe}gEfV5n&7B) zXXILEuDjXKgZ<*#e1O;jMM_4rPTM1C*Fcva?`9<~gZZ7V3+TZQi%UhRPVImDqKe+zq|Phm5^kM4XK#_dqQ(3k2z&%a)1T!F<9 zl#fjf!>MFLf4rw5I@%wFP1z4+9#xH3A6LI>{Ql%c&FrHG@jFK_hm@2GY%^Np*_?wM z!+p7r-`_7hrwPh6=ImId*|TweDjn^ut*t*wQDv#43nB`b5+1iB_igmj~StCI!SY8@c^xqfDzOB?hc2LF{`B>vY6CU)I&9*- zS%)4+JihSEpbw+}6E$|ekMLC{zsBy>*Sp{Rh>f2QAluOPyUga+Ym<54dSN)&VTe10@b${|l TQ}YLh^XmP~!C&j&Xr2EzYYPxd literal 0 HcmV?d00001 diff --git a/test/tools/llvm-objdump/X86/macho-universal-x86_64.i386.test b/test/tools/llvm-objdump/X86/macho-universal-x86_64.i386.test new file mode 100644 index 00000000000..9f1b51365d9 --- /dev/null +++ b/test/tools/llvm-objdump/X86/macho-universal-x86_64.i386.test @@ -0,0 +1,25 @@ +RUN: llvm-objdump %p/Inputs/macho-universal.x86_64.i386 -d -m -no-show-raw-insn -full-leading-addr -print-imm-hex -arch all \ +RUN: | FileCheck %s -check-prefix UEXE-all +RUN: llvm-objdump %p/Inputs/macho-universal-archive.x86_64.i386 -d -m -no-show-raw-insn -full-leading-addr -print-imm-hex -arch i386 \ +RUN: | FileCheck %s -check-prefix UArchive-i386 + +UEXE-all: macho-universal.x86_64.i386 (architecture x86_64): +UEXE-all: (__TEXT,__text) section +UEXE-all: _main: +UEXE-all: 0000000100000f60 pushq %rbp +UEXE-all: 0000000100000f61 movq %rsp, %rbp +UEXE-all: macho-universal.x86_64.i386 (architecture i386): +UEXE-all: (__TEXT,__text) section +UEXE-all: _main: +UEXE-all: 00001fa0 pushl %ebp +UEXE-all: 00001fa1 movl %esp, %ebp + +UArchive-i386: Archive : {{.*}}/macho-universal-archive.x86_64.i386 +UArchive-i386: macho-universal-archive.x86_64.i386(foo.o): +UArchive-i386: (__TEXT,__text) section +UArchive-i386: _foo: +UArchive-i386: 00000000 pushl %ebp +UArchive-i386: 00000001 movl %esp, %ebp +UArchive-i386: 00000003 popl %ebp +UArchive-i386: 00000004 retl + diff --git a/tools/llvm-objdump/MachODump.cpp b/tools/llvm-objdump/MachODump.cpp index 7f97d8a314b..1539fc13419 100644 --- a/tools/llvm-objdump/MachODump.cpp +++ b/tools/llvm-objdump/MachODump.cpp @@ -28,6 +28,7 @@ #include "llvm/MC/MCRegisterInfo.h" #include "llvm/MC/MCSubtargetInfo.h" #include "llvm/Object/MachO.h" +#include "llvm/Object/MachOUniversal.h" #include "llvm/Support/Casting.h" #include "llvm/Support/CommandLine.h" #include "llvm/Support/Debug.h" @@ -65,6 +66,11 @@ static cl::opt PrintImmHex("print-imm-hex", cl::desc("Use hex format for immediate values")); +static cl::list + ArchFlags("arch", cl::desc("architecture(s) from a Mach-O file to dump"), + cl::ZeroOrMore); +bool ArchAll = false; + static std::string ThumbTripleName; static const Target *GetTarget(const MachOObjectFile *MachOObj, @@ -205,8 +211,12 @@ static void getSectionsAndSymbols(const MachO::mach_header Header, std::vector &Symbols, SmallVectorImpl &FoundFns, uint64_t &BaseSegmentAddress) { - for (const SymbolRef &Symbol : MachOObj->symbols()) - Symbols.push_back(Symbol); + for (const SymbolRef &Symbol : MachOObj->symbols()) { + StringRef SymName; + Symbol.getName(SymName); + if (!SymName.startswith("ltmp")) + Symbols.push_back(Symbol); + } for (const SectionRef &Section : MachOObj->sections()) { StringRef SectName; @@ -241,22 +251,210 @@ static void getSectionsAndSymbols(const MachO::mach_header Header, } } -static void DisassembleInputMachO2(StringRef Filename, - MachOObjectFile *MachOOF); +// checkMachOAndArchFlags() checks to see if the ObjectFile is a Mach-O file +// and if it is and there is a list of architecture flags is specified then +// check to make sure this Mach-O file is one of those architectures or all +// architectures were specified. If not then an error is generated and this +// routine returns false. Else it returns true. +static bool checkMachOAndArchFlags(ObjectFile *O, StringRef Filename) { + if (isa(O) && !ArchAll && ArchFlags.size() != 0) { + MachOObjectFile *MachO = dyn_cast(O); + bool ArchFound = false; + MachO::mach_header H; + MachO::mach_header_64 H_64; + Triple T; + if (MachO->is64Bit()) { + H_64 = MachO->MachOObjectFile::getHeader64(); + T = MachOObjectFile::getArch(H_64.cputype, H_64.cpusubtype); + } else { + H = MachO->MachOObjectFile::getHeader(); + T = MachOObjectFile::getArch(H.cputype, H.cpusubtype); + } + unsigned i; + for (i = 0; i < ArchFlags.size(); ++i) { + if (ArchFlags[i] == T.getArchName()) + ArchFound = true; + break; + } + if (!ArchFound) { + errs() << "llvm-objdump: file: " + Filename + " does not contain " + << "architecture: " + ArchFlags[i] + "\n"; + return false; + } + } + return true; +} + +static void DisassembleInputMachO2(StringRef Filename, MachOObjectFile *MachOOF, + StringRef ArchiveMemberName = StringRef(), + StringRef ArchitectureName = StringRef()); void llvm::DisassembleInputMachO(StringRef Filename) { - ErrorOr> BuffOrErr = - MemoryBuffer::getFileOrSTDIN(Filename); - if (std::error_code EC = BuffOrErr.getError()) { - errs() << "llvm-objdump: " << Filename << ": " << EC.message() << "\n"; + // Check for -arch all and verifiy the -arch flags are valid. + for (unsigned i = 0; i < ArchFlags.size(); ++i) { + if (ArchFlags[i] == "all") { + ArchAll = true; + } else { + if (!MachOObjectFile::isValidArch(ArchFlags[i])) { + errs() << "llvm-objdump: Unknown architecture named '" + ArchFlags[i] + + "'for the -arch option\n"; + return; + } + } + } + + // Attempt to open the binary. + ErrorOr> BinaryOrErr = createBinary(Filename); + if (std::error_code EC = BinaryOrErr.getError()) { + errs() << "llvm-objdump: '" << Filename << "': " << EC.message() << ".\n"; return; } - std::unique_ptr Buff = std::move(BuffOrErr.get()); + Binary &Bin = *BinaryOrErr.get().getBinary(); - std::unique_ptr MachOOF = std::move( - ObjectFile::createMachOObjectFile(Buff.get()->getMemBufferRef()).get()); - - DisassembleInputMachO2(Filename, MachOOF.get()); + if (Archive *A = dyn_cast(&Bin)) { + outs() << "Archive : " << Filename << "\n"; + for (Archive::child_iterator I = A->child_begin(), E = A->child_end(); + I != E; ++I) { + ErrorOr> ChildOrErr = I->getAsBinary(); + if (ChildOrErr.getError()) + continue; + if (MachOObjectFile *O = dyn_cast(&*ChildOrErr.get())) { + if (!checkMachOAndArchFlags(O, Filename)) + return; + DisassembleInputMachO2(Filename, O, O->getFileName()); + } + } + return; + } + if (MachOUniversalBinary *UB = dyn_cast(&Bin)) { + // If we have a list of architecture flags specified dump only those. + if (!ArchAll && ArchFlags.size() != 0) { + // Look for a slice in the universal binary that matches each ArchFlag. + bool ArchFound; + for (unsigned i = 0; i < ArchFlags.size(); ++i) { + ArchFound = false; + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + if (ArchFlags[i] == I->getArchTypeName()) { + ArchFound = true; + ErrorOr> ObjOrErr = + I->getAsObjectFile(); + std::unique_ptr A; + std::string ArchitectureName = ""; + if (ArchFlags.size() > 1) + ArchitectureName = I->getArchTypeName(); + if (ObjOrErr) { + ObjectFile &O = *ObjOrErr.get(); + if (MachOObjectFile *MachOOF = dyn_cast(&O)) + DisassembleInputMachO2(Filename, MachOOF, "", ArchitectureName); + } else if (!I->getAsArchive(A)) { + outs() << "Archive : " << Filename; + if (!ArchitectureName.empty()) + outs() << " (architecture " << ArchitectureName << ")"; + outs() << "\n"; + for (Archive::child_iterator AI = A->child_begin(), + AE = A->child_end(); + AI != AE; ++AI) { + ErrorOr> ChildOrErr = AI->getAsBinary(); + if (ChildOrErr.getError()) + continue; + if (MachOObjectFile *O = + dyn_cast(&*ChildOrErr.get())) + DisassembleInputMachO2(Filename, O, O->getFileName(), + ArchitectureName); + } + } + } + } + if (!ArchFound) { + errs() << "llvm-objdump: file: " + Filename + " does not contain " + << "architecture: " + ArchFlags[i] + "\n"; + return; + } + } + return; + } + // No architecture flags were specified so if this contains a slice that + // matches the host architecture dump only that. + if (!ArchAll) { + StringRef HostArchName = MachOObjectFile::getHostArch().getArchName(); + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + if (HostArchName == I->getArchTypeName()) { + ErrorOr> ObjOrErr = I->getAsObjectFile(); + std::unique_ptr A; + std::string ArchiveName; + ArchiveName.clear(); + if (ObjOrErr) { + ObjectFile &O = *ObjOrErr.get(); + if (MachOObjectFile *MachOOF = dyn_cast(&O)) + DisassembleInputMachO2(Filename, MachOOF); + } else if (!I->getAsArchive(A)) { + outs() << "Archive : " << Filename << "\n"; + for (Archive::child_iterator AI = A->child_begin(), + AE = A->child_end(); + AI != AE; ++AI) { + ErrorOr> ChildOrErr = AI->getAsBinary(); + if (ChildOrErr.getError()) + continue; + if (MachOObjectFile *O = + dyn_cast(&*ChildOrErr.get())) + DisassembleInputMachO2(Filename, O, O->getFileName()); + } + } + return; + } + } + } + // Either all architectures have been specified or none have been specified + // and this does not contain the host architecture so dump all the slices. + bool moreThanOneArch = UB->getNumberOfObjects() > 1; + for (MachOUniversalBinary::object_iterator I = UB->begin_objects(), + E = UB->end_objects(); + I != E; ++I) { + ErrorOr> ObjOrErr = I->getAsObjectFile(); + std::unique_ptr A; + std::string ArchitectureName = ""; + if (moreThanOneArch) + ArchitectureName = I->getArchTypeName(); + if (ObjOrErr) { + ObjectFile &Obj = *ObjOrErr.get(); + if (MachOObjectFile *MachOOF = dyn_cast(&Obj)) + DisassembleInputMachO2(Filename, MachOOF, "", ArchitectureName); + } else if (!I->getAsArchive(A)) { + outs() << "Archive : " << Filename; + if (!ArchitectureName.empty()) + outs() << " (architecture " << ArchitectureName << ")"; + outs() << "\n"; + for (Archive::child_iterator AI = A->child_begin(), AE = A->child_end(); + AI != AE; ++AI) { + ErrorOr> ChildOrErr = AI->getAsBinary(); + if (ChildOrErr.getError()) + continue; + if (MachOObjectFile *O = + dyn_cast(&*ChildOrErr.get())) { + if (MachOObjectFile *MachOOF = dyn_cast(O)) + DisassembleInputMachO2(Filename, MachOOF, MachOOF->getFileName(), + ArchitectureName); + } + } + } + } + return; + } + if (ObjectFile *O = dyn_cast(&Bin)) { + if (!checkMachOAndArchFlags(O, Filename)) + return; + if (MachOObjectFile *MachOOF = dyn_cast(&*O)) { + DisassembleInputMachO2(Filename, MachOOF); + } else + errs() << "llvm-objdump: '" << Filename << "': " + << "Object is not a Mach-O file type.\n"; + } else + errs() << "llvm-objdump: '" << Filename << "': " + << "Unrecognized file type.\n"; } typedef DenseMap SymbolAddressMap; @@ -1585,8 +1783,9 @@ static void emitComments(raw_svector_ostream &CommentStream, CommentStream.resync(); } -static void DisassembleInputMachO2(StringRef Filename, - MachOObjectFile *MachOOF) { +static void DisassembleInputMachO2(StringRef Filename, MachOObjectFile *MachOOF, + StringRef ArchiveMemberName, + StringRef ArchitectureName) { const char *McpuDefault = nullptr; const Target *ThumbTarget = nullptr; const Target *TheTarget = GetTarget(MachOOF, &McpuDefault, &ThumbTarget); @@ -1639,6 +1838,12 @@ static void DisassembleInputMachO2(StringRef Filename, // Comment stream and backing vector. SmallString<128> CommentsToEmit; raw_svector_ostream CommentStream(CommentsToEmit); + // FIXME: Setting the CommentStream in the InstPrinter is problematic in that + // if it is done then arm64 comments for string literals don't get printed + // and some constant get printed instead and not setting it causes intel + // (32-bit and 64-bit) comments printed with different spacing before the + // comment causing different diffs with the 'C' disassembler library API. + // IP->setCommentStream(CommentStream); if (!AsmInfo || !STI || !DisAsm || !IP) { errs() << "error: couldn't initialize disassembler for target " @@ -1687,7 +1892,12 @@ static void DisassembleInputMachO2(StringRef Filename, return; } - outs() << '\n' << Filename << ":\n\n"; + outs() << Filename; + if (!ArchiveMemberName.empty()) + outs() << '(' << ArchiveMemberName << ')'; + if (!ArchitectureName.empty()) + outs() << " (architecture " << ArchitectureName << ")"; + outs() << ":\n"; MachO::mach_header Header = MachOOF->getHeader(); @@ -1750,6 +1960,14 @@ static void DisassembleInputMachO2(StringRef Filename, diContext.reset(DIContext::getDWARFContext(*DbgObj)); } + // TODO: For now this only disassembles the (__TEXT,__text) section (see the + // checks in the code below at the top of this loop). It should allow a + // darwin otool(1) like -s option to disassemble any named segment & section + // that is marked as containing instructions with the attributes + // S_ATTR_PURE_INSTRUCTIONS or S_ATTR_SOME_INSTRUCTIONS in the flags field of + // the section structure. + outs() << "(__TEXT,__text) section\n"; + for (unsigned SectIdx = 0; SectIdx != Sections.size(); SectIdx++) { bool SectIsText = Sections[SectIdx].isText(); @@ -2013,6 +2231,11 @@ static void DisassembleInputMachO2(StringRef Filename, } } } + // The TripleName's need to be reset if we are called again for a different + // archtecture. + TripleName = ""; + ThumbTripleName = ""; + if (SymbolizerInfo.method != nullptr) free(SymbolizerInfo.method); if (SymbolizerInfo.demangled_name != nullptr) diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index c62922e4c5e..7316a4f8725 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -109,7 +109,7 @@ llvm::MCPU("mcpu", cl::init("")); cl::opt -llvm::ArchName("arch", cl::desc("Target arch to disassemble for, " +llvm::ArchName("arch-name", cl::desc("Target arch to disassemble for, " "see -version for available targets")); static cl::opt