From 2dcf00e5cfee8a92b0a7651d00cf55698d6db64a Mon Sep 17 00:00:00 2001 From: Frederic Riss Date: Fri, 24 Jul 2015 06:41:11 +0000 Subject: [PATCH] [dsymutil] Implement support for universal mach-o object files. This patch allows llvm-dsymutil to read universal (aka fat) macho object files and archives. The patch touches nearly everything in the BinaryHolder, but it is fairly mechinical: the methods that returned MemoryBufferRefs or ObjectFiles now return a vector of those, and the high-level access function takes a triple argument to select the architecture. There is no support yet for handling fat executables and thus no support for writing fat object files. llvm-svn: 243096 --- .../dsymutil/ARM/fat-arch-not-found.test | 13 ++ test/tools/dsymutil/ARM/lit.local.cfg | 2 + test/tools/dsymutil/Inputs/fat-test.c | 17 ++ test/tools/dsymutil/Inputs/fat-test.o | Bin 0 -> 5000 bytes test/tools/dsymutil/Inputs/libfat-test.a | Bin 0 -> 5136 bytes .../dsymutil/X86/fat-archive-input-i386.test | 16 ++ .../dsymutil/X86/fat-object-input-x86_64.test | 16 ++ .../X86/fat-object-input-x86_64h.test | 16 ++ tools/dsymutil/BinaryHolder.cpp | 158 +++++++++++++----- tools/dsymutil/BinaryHolder.h | 99 ++++++----- tools/dsymutil/DebugMap.cpp | 10 +- tools/dsymutil/DwarfLinker.cpp | 25 ++- tools/dsymutil/MachODebugMapParser.cpp | 35 ++-- 13 files changed, 300 insertions(+), 107 deletions(-) create mode 100644 test/tools/dsymutil/ARM/fat-arch-not-found.test create mode 100644 test/tools/dsymutil/ARM/lit.local.cfg create mode 100644 test/tools/dsymutil/Inputs/fat-test.c create mode 100644 test/tools/dsymutil/Inputs/fat-test.o create mode 100644 test/tools/dsymutil/Inputs/libfat-test.a create mode 100644 test/tools/dsymutil/X86/fat-archive-input-i386.test create mode 100644 test/tools/dsymutil/X86/fat-object-input-x86_64.test create mode 100644 test/tools/dsymutil/X86/fat-object-input-x86_64h.test diff --git a/test/tools/dsymutil/ARM/fat-arch-not-found.test b/test/tools/dsymutil/ARM/fat-arch-not-found.test new file mode 100644 index 00000000000..89b518cd16f --- /dev/null +++ b/test/tools/dsymutil/ARM/fat-arch-not-found.test @@ -0,0 +1,13 @@ +# REQUIRES: object-emission +# RUN: llvm-dsymutil -oso-prepend-path=%p/../Inputs -y %s -o - 2>&1 | FileCheck %s + +--- +triple: 'armv7-apple-darwin' +objects: + - filename: libfat-test.a(fat-test.o) + symbols: + - { sym: _armv7_var, objAddr: 0x0, binAddr: 0x1000, size: 0x4 } +... + +# CHECK: libfat-test.a(fat-test.o): No object file for requested architecture + diff --git a/test/tools/dsymutil/ARM/lit.local.cfg b/test/tools/dsymutil/ARM/lit.local.cfg new file mode 100644 index 00000000000..c8625f4d9d2 --- /dev/null +++ b/test/tools/dsymutil/ARM/lit.local.cfg @@ -0,0 +1,2 @@ +if not 'X86' in config.root.targets: + config.unsupported = True diff --git a/test/tools/dsymutil/Inputs/fat-test.c b/test/tools/dsymutil/Inputs/fat-test.c new file mode 100644 index 00000000000..42c1fce1ec3 --- /dev/null +++ b/test/tools/dsymutil/Inputs/fat-test.c @@ -0,0 +1,17 @@ +/* Compile with: + clang -c -g -arch x86_64h -arch x86_64 -arch i386 fat-test.c + libtool -static -o libfat-test.a fat-test.o + + To reduce the size of the fat .o: + lipo -thin i386 -o fat-test.i386.o fat-test.o + lipo -thin x86_64 -o fat-test.x86_64.o fat-test.o + lipo -thin x86_64h -o fat-test.x86_64h.o fat-test.o + lipo -create -arch x86_64h fat-test.x86_64h.o -arch x86_64 fat-test.x86_64.o -arch i386 fat-test.i386.o -o fat-test.o -segalign i386 8 -segalign x86_64 8 -segalign x86_64h 8 + */ +#ifdef __x86_64h__ +int x86_64h_var; +#elif defined(__x86_64__) +int x86_64_var; +#else +int i386_var; +#endif diff --git a/test/tools/dsymutil/Inputs/fat-test.o b/test/tools/dsymutil/Inputs/fat-test.o new file mode 100644 index 0000000000000000000000000000000000000000..8159cc749772abe9914b1a0830d743002955025d GIT binary patch literal 5000 zcmdT|&1(}u6rXKA8cht93RV0dLPe!E1{;m2SSo&0ZB?|W;9*VMZ5xS6NY+w8Bzh7Q zJb3ZoK}9_2AE02*(u3BM2SsX6UIfots=v20lP;6pWTS%d!OMK?yx+WeGxL6(&Mdy1 zW{mkX##*UlEcgX_pVwvIiZc2_wsBPNN8bZ6j=lZeE=5oL(B9NgF@CoL)3PW zcVq;4D8|S(IYkUT* z%2MHoS2By%2o>+1usbQr9*=n0{D>poyugvgO^kymXz@ZN9> zmf`C}$Nq4beBKOgVH@$QX+NSX@T<{$P>qeH&2G~unQ?wq`siTB1_sU!#wLwoDU;8| zQt?DQ5!*77#p&-(CD4fPOvQI>wVQ4~nk!r}OKfWQE`3*WLZ3_*Ste(){xg03Vk#>G z%Z$nU__p}X8-uiNS}yf(fRfm4sjb@ngfu#a@K+HSghHyZAj$yqTYJk`qI@e%A*UeI zSgMO#Q){YLz>qr_Ep{-4dc#jQuG;eHJ*fxKTI1^7y&&Q{#BH{0}G8{3`JzKh^h-+=cxB^tJ~Kw|CA5*ps~XfZ@g+-Y{(W81t!oK^Vjp(vMl}iwLGIrnNbu0~^^1 zjP@G2T-R-WIPk(=fsyin;l>3zFo*{(2#mQJYjMl}PlX?kYxqHHb$XM0gAL5t0?G(V z`uqNGzDX#h@J;d4G?+tV4OV%RB+#vCZ2{}1`tTo@=FRt+9y~}Id5m;?+SyABZl=cw tMVR)2;!ei`;_Wdab}q7ou_vw8Zn8&o7XkF-o@mo~rYe-bRrE^C*e@I33YGu> literal 0 HcmV?d00001 diff --git a/test/tools/dsymutil/Inputs/libfat-test.a b/test/tools/dsymutil/Inputs/libfat-test.a new file mode 100644 index 0000000000000000000000000000000000000000..6b34b0fd6f90004bcc4cda6295704ad477562ddb GIT binary patch literal 5136 zcmdT{&u<$=6rS~uxV0Uts7Qc7XsZOJP;l3dDeA9S7{f_S)c&|0rH?P}$r{}6|d-0`(E9d<~-1jA= z3BgPF2W!0cM#EJH@idN}^Pciow^4`U)z{a1%`N)>Py009(+VIiUaND>-Mt{*TMFl_ zs=rnC{gIaY8f9Ov-nriF58C&c!qL^ABmJ#+yX~gkslQ3M0e>}~wl6N;#`^2-h6Mfn zRT(y|>eKKuAc6hx+1IT%f_Rha9BaH+V&XYByP^J;6y618)UAoQrBqXK$%<3Uca@`F=val zqGcX;dYhd$%yOlCx@tWsyfD-dCoguon@(SB*Q$24VsF)ZqSbMP@qqC};b=NpI5P2Q z0T-(xl7)*$=ksTB&*l>FCpitpxm=FM*HGk6A9C%@iz#JXkv&yBDkz4LIqZe8M@_47nHdYAo*q8mcc}WRG{o^PU|6I0%bN_QM^P9o{u;fQCviV;BI2F zbdC*hEHTJ8aWJBI<__lbihU5*ju39i;7k$Yn-~~Td~yO97l3hRD8_IO=>dcM@zfCR zpq*j7v8ML0jhdluJb0ru3*tBkYcPt+bCklO(4{F>5RWx1Gz{Z#+PzH4d9-3O#zVi% z&GQP46JyYPI!dRw#gG}4xQyX(MxG!jk~3^?{r|Ul4-z +getMachOFatMemoryBuffers(StringRef Filename, MemoryBuffer &Mem, + object::MachOUniversalBinary &Fat) { + std::vector Buffers; + StringRef FatData = Fat.getData(); + for (auto It = Fat.begin_objects(), End = Fat.end_objects(); It != End; + ++It) { + StringRef ObjData = FatData.substr(It->getOffset(), It->getSize()); + Buffers.emplace_back(ObjData, Filename); + } + return Buffers; +} + void BinaryHolder::changeBackingMemoryBuffer( std::unique_ptr &&Buf) { - CurrentArchive.reset(); - CurrentObjectFile.reset(); + CurrentArchives.clear(); + CurrentObjectFiles.clear(); + CurrentFatBinary.reset(); CurrentMemoryBuffer = std::move(Buf); } -ErrorOr -BinaryHolder::GetMemoryBufferForFile(StringRef Filename, - sys::TimeValue Timestamp) { +ErrorOr> +BinaryHolder::GetMemoryBuffersForFile(StringRef Filename, + sys::TimeValue Timestamp) { if (Verbose) outs() << "trying to open '" << Filename << "'\n"; // Try that first as it doesn't involve any filesystem access. - if (auto ErrOrArchiveMember = GetArchiveMemberBuffer(Filename, Timestamp)) - return *ErrOrArchiveMember; + if (auto ErrOrArchiveMembers = GetArchiveMemberBuffers(Filename, Timestamp)) + return *ErrOrArchiveMembers; // If the name ends with a closing paren, there is a huge chance // it is an archive member specification. if (Filename.endswith(")")) - if (auto ErrOrArchiveMember = - MapArchiveAndGetMemberBuffer(Filename, Timestamp)) - return *ErrOrArchiveMember; + if (auto ErrOrArchiveMembers = + MapArchiveAndGetMemberBuffers(Filename, Timestamp)) + return *ErrOrArchiveMembers; // Otherwise, just try opening a standard file. If this is an // archive member specifiaction and any of the above didn't handle it @@ -65,43 +79,64 @@ BinaryHolder::GetMemoryBufferForFile(StringRef Filename, changeBackingMemoryBuffer(std::move(*ErrOrFile)); if (Verbose) outs() << "\tloaded file.\n"; - return CurrentMemoryBuffer->getMemBufferRef(); + + auto ErrOrFat = object::MachOUniversalBinary::create( + CurrentMemoryBuffer->getMemBufferRef()); + if (ErrOrFat.getError()) { + // Not a fat binary must be a standard one. Return a one element vector. + return std::vector{CurrentMemoryBuffer->getMemBufferRef()}; + } + + CurrentFatBinary = std::move(*ErrOrFat); + return getMachOFatMemoryBuffers(Filename, *CurrentMemoryBuffer, + *CurrentFatBinary); } -ErrorOr -BinaryHolder::GetArchiveMemberBuffer(StringRef Filename, - sys::TimeValue Timestamp) { - if (!CurrentArchive) +ErrorOr> +BinaryHolder::GetArchiveMemberBuffers(StringRef Filename, + sys::TimeValue Timestamp) { + if (CurrentArchives.empty()) return make_error_code(errc::no_such_file_or_directory); - StringRef CurArchiveName = CurrentArchive->getFileName(); + StringRef CurArchiveName = CurrentArchives.front()->getFileName(); if (!Filename.startswith(Twine(CurArchiveName, "(").str())) return make_error_code(errc::no_such_file_or_directory); // Remove the archive name and the parens around the archive member name. Filename = Filename.substr(CurArchiveName.size() + 1).drop_back(); - for (const auto &Child : CurrentArchive->children()) { - if (auto NameOrErr = Child.getName()) - if (*NameOrErr == Filename) { - if (Timestamp != sys::TimeValue::PosixZeroTime() && - Timestamp != Child.getLastModified()) { + std::vector Buffers; + Buffers.reserve(CurrentArchives.size()); + + for (const auto &CurrentArchive : CurrentArchives) { + for (const auto &Child : CurrentArchive->children()) { + if (auto NameOrErr = Child.getName()) { + if (*NameOrErr == Filename) { + if (Timestamp != sys::TimeValue::PosixZeroTime() && + Timestamp != Child.getLastModified()) { + if (Verbose) + outs() << "\tmember had timestamp mismatch.\n"; + continue; + } if (Verbose) - outs() << "\tmember had timestamp mismatch.\n"; - continue; + outs() << "\tfound member in current archive.\n"; + auto ErrOrMem = Child.getMemoryBufferRef(); + if (auto Err = ErrOrMem.getError()) + return Err; + Buffers.push_back(*ErrOrMem); } - if (Verbose) - outs() << "\tfound member in current archive.\n"; - return Child.getMemoryBufferRef(); } + } } - return make_error_code(errc::no_such_file_or_directory); + if (Buffers.empty()) + return make_error_code(errc::no_such_file_or_directory); + return Buffers; } -ErrorOr -BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename, - sys::TimeValue Timestamp) { +ErrorOr> +BinaryHolder::MapArchiveAndGetMemberBuffers(StringRef Filename, + sys::TimeValue Timestamp) { StringRef ArchiveFilename = Filename.substr(0, Filename.find('(')); auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename); @@ -112,29 +147,60 @@ BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename, outs() << "\topened new archive '" << ArchiveFilename << "'\n"; changeBackingMemoryBuffer(std::move(*ErrOrBuff)); - auto ErrOrArchive = - object::Archive::create(CurrentMemoryBuffer->getMemBufferRef()); - if (auto Err = ErrOrArchive.getError()) - return Err; + std::vector ArchiveBuffers; + auto ErrOrFat = object::MachOUniversalBinary::create( + CurrentMemoryBuffer->getMemBufferRef()); + if (ErrOrFat.getError()) { + // Not a fat binary must be a standard one. + ArchiveBuffers.push_back(CurrentMemoryBuffer->getMemBufferRef()); + } else { + CurrentFatBinary = std::move(*ErrOrFat); + ArchiveBuffers = getMachOFatMemoryBuffers( + ArchiveFilename, *CurrentMemoryBuffer, *CurrentFatBinary); + } - CurrentArchive = std::move(*ErrOrArchive); - - return GetArchiveMemberBuffer(Filename, Timestamp); + for (auto MemRef : ArchiveBuffers) { + auto ErrOrArchive = object::Archive::create(MemRef); + if (auto Err = ErrOrArchive.getError()) + return Err; + CurrentArchives.push_back(std::move(*ErrOrArchive)); + } + return GetArchiveMemberBuffers(Filename, Timestamp); } ErrorOr -BinaryHolder::GetObjectFile(StringRef Filename, sys::TimeValue Timestamp) { - auto ErrOrMemBufferRef = GetMemoryBufferForFile(Filename, Timestamp); - if (auto Err = ErrOrMemBufferRef.getError()) +BinaryHolder::getObjfileForArch(const Triple &T) { + for (const auto &Obj : CurrentObjectFiles) { + if (const auto *MachO = dyn_cast(Obj.get())) { + if (getTriple(*MachO).str() == T.str()) + return *MachO; + } else if (Obj->getArch() == T.getArch()) + return *Obj; + } + + return make_error_code(object::object_error::arch_not_found); +} + +ErrorOr> +BinaryHolder::GetObjectFiles(StringRef Filename, sys::TimeValue Timestamp) { + auto ErrOrMemBufferRefs = GetMemoryBuffersForFile(Filename, Timestamp); + if (auto Err = ErrOrMemBufferRefs.getError()) return Err; - auto ErrOrObjectFile = - object::ObjectFile::createObjectFile(*ErrOrMemBufferRef); - if (auto Err = ErrOrObjectFile.getError()) - return Err; + std::vector Objects; + Objects.reserve(ErrOrMemBufferRefs->size()); - CurrentObjectFile = std::move(*ErrOrObjectFile); - return *CurrentObjectFile; + CurrentObjectFiles.clear(); + for (auto MemBuf : *ErrOrMemBufferRefs) { + auto ErrOrObjectFile = object::ObjectFile::createObjectFile(MemBuf); + if (auto Err = ErrOrObjectFile.getError()) + return Err; + + Objects.push_back(ErrOrObjectFile->get()); + CurrentObjectFiles.push_back(std::move(*ErrOrObjectFile)); + } + + return std::move(Objects); } } } diff --git a/tools/dsymutil/BinaryHolder.h b/tools/dsymutil/BinaryHolder.h index e4558580f9a..9d7b4bd8787 100644 --- a/tools/dsymutil/BinaryHolder.h +++ b/tools/dsymutil/BinaryHolder.h @@ -17,6 +17,7 @@ #include "llvm/ADT/Triple.h" #include "llvm/Object/Archive.h" #include "llvm/Object/Error.h" +#include "llvm/Object/MachOUniversal.h" #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Errc.h" #include "llvm/Support/ErrorOr.h" @@ -37,77 +38,95 @@ namespace dsymutil { /// meaning that a mapping request will invalidate the previous memory /// mapping. class BinaryHolder { - std::unique_ptr CurrentArchive; + std::vector> CurrentArchives; std::unique_ptr CurrentMemoryBuffer; - std::unique_ptr CurrentObjectFile; + std::vector> CurrentObjectFiles; + std::unique_ptr CurrentFatBinary; bool Verbose; - /// \brief Get the MemoryBufferRef for the file specification in \p - /// Filename from the current archive. + /// Get the MemoryBufferRefs for the file specification in \p + /// Filename from the current archive. Multiple buffers are returned + /// when there are multiple architectures available for the + /// requested file. /// /// This function performs no system calls, it just looks up a /// potential match for the given \p Filename in the currently /// mapped archive if there is one. - ErrorOr GetArchiveMemberBuffer(StringRef Filename, - sys::TimeValue Timestamp); + ErrorOr> + GetArchiveMemberBuffers(StringRef Filename, sys::TimeValue Timestamp); - /// \brief Interpret Filename as an archive member specification, - /// map the corresponding archive to memory and return the - /// MemoryBufferRef corresponding to the described member. - ErrorOr - MapArchiveAndGetMemberBuffer(StringRef Filename, sys::TimeValue Timestamp); + /// Interpret Filename as an archive member specification map the + /// corresponding archive to memory and return the MemoryBufferRefs + /// corresponding to the described member. Multiple buffers are + /// returned when there are multiple architectures available for the + /// requested file. + ErrorOr> + MapArchiveAndGetMemberBuffers(StringRef Filename, sys::TimeValue Timestamp); - /// \brief Return the MemoryBufferRef that holds the memory - /// mapping for the given \p Filename. This function will try to - /// parse archive member specifications of the form - /// /path/to/archive.a(member.o). + /// Return the MemoryBufferRef that holds the memory mapping for the + /// given \p Filename. This function will try to parse archive + /// member specifications of the form /path/to/archive.a(member.o). /// - /// The returned MemoryBufferRef points to a buffer owned by this + /// The returned MemoryBufferRefs points to a buffer owned by this /// object. The buffer is valid until the next call to /// GetMemoryBufferForFile() on this object. - ErrorOr GetMemoryBufferForFile(StringRef Filename, - sys::TimeValue Timestamp); + /// Multiple buffers are returned when there are multiple + /// architectures available for the requested file. + ErrorOr> + GetMemoryBuffersForFile(StringRef Filename, sys::TimeValue Timestamp); void changeBackingMemoryBuffer(std::unique_ptr &&MemBuf); + ErrorOr getObjfileForArch(const Triple &T); public: BinaryHolder(bool Verbose) : Verbose(Verbose) {} - /// \brief Get the ObjectFile designated by the \p Filename. This + /// Get the ObjectFiles designated by the \p Filename. This /// might be an archive member specification of the form /// /path/to/archive.a(member.o). /// /// Calling this function invalidates the previous mapping owned by - /// the BinaryHolder. - ErrorOr - GetObjectFile(StringRef Filename, - sys::TimeValue Timestamp = sys::TimeValue::PosixZeroTime()); + /// the BinaryHolder. Multiple buffers are returned when there are + /// multiple architectures available for the requested file. + ErrorOr> + GetObjectFiles(StringRef Filename, + sys::TimeValue Timestamp = sys::TimeValue::PosixZeroTime()); - /// \brief Wraps GetObjectFile() to return a derived ObjectFile type. + /// Wraps GetObjectFiles() to return a derived ObjectFile type. template - ErrorOr - GetFileAs(StringRef Filename, - sys::TimeValue Timestamp = sys::TimeValue::PosixZeroTime()) { - auto ErrOrObjFile = GetObjectFile(Filename); + ErrorOr> + GetFilesAs(StringRef Filename, + sys::TimeValue Timestamp = sys::TimeValue::PosixZeroTime()) { + auto ErrOrObjFile = GetObjectFiles(Filename, Timestamp); if (auto Err = ErrOrObjFile.getError()) return Err; - if (const auto *Derived = dyn_cast(CurrentObjectFile.get())) - return *Derived; - return make_error_code(object::object_error::invalid_file_type); + + std::vector Objects; + Objects.reserve((*ErrOrObjFile).size()); + for (const auto &Obj : *ErrOrObjFile) { + const auto *Derived = dyn_cast(Obj); + if (!Derived) + return make_error_code(object::object_error::invalid_file_type); + Objects.push_back(Derived); + } + return std::move(Objects); } - /// \brief Access the currently owned ObjectFile. As successfull - /// call to GetObjectFile() or GetFileAs() must have been performed - /// before calling this. - const object::ObjectFile &Get() { - assert(CurrentObjectFile); - return *CurrentObjectFile; + /// Access the currently owned ObjectFile with architecture \p T. As + /// successfull call to GetObjectFiles() or GetFilesAs() must have + /// been performed before calling this. + ErrorOr Get(const Triple &T) { + return getObjfileForArch(T); } - /// \brief Access to a derived version of the currently owned + /// Access to a derived version of the currently owned /// ObjectFile. The conversion must be known to be valid. - template const ObjectFileType &GetAs() { - return cast(*CurrentObjectFile); + template + ErrorOr GetAs(const Triple &T) { + auto ErrOrObj = Get(T); + if (auto Err = ErrOrObj.getError()) + return Err; + return cast(*ErrOrObj); } static Triple getTriple(const object::MachOObjectFile &Obj); diff --git a/tools/dsymutil/DebugMap.cpp b/tools/dsymutil/DebugMap.cpp index 24dedfcb673..e29c885b5ac 100644 --- a/tools/dsymutil/DebugMap.cpp +++ b/tools/dsymutil/DebugMap.cpp @@ -178,9 +178,9 @@ SequenceTraits>>::element( void MappingTraits::mapping(IO &io, dsymutil::DebugMap &DM) { io.mapRequired("triple", DM.BinaryTriple); - io.mapOptional("objects", DM.Objects); if (void *Ctxt = io.getContext()) reinterpret_cast(Ctxt)->BinaryTriple = DM.BinaryTriple; + io.mapOptional("objects", DM.Objects); } void MappingTraits>::mapping( @@ -188,9 +188,9 @@ void MappingTraits>::mapping( if (!DM) DM.reset(new DebugMap()); io.mapRequired("triple", DM->BinaryTriple); - io.mapOptional("objects", DM->Objects); if (void *Ctxt = io.getContext()) reinterpret_cast(Ctxt)->BinaryTriple = DM->BinaryTriple; + io.mapOptional("objects", DM->Objects); } MappingTraits::YamlDMO::YamlDMO( @@ -210,11 +210,11 @@ MappingTraits::YamlDMO::denormalize(IO &IO) { StringMap SymbolAddresses; sys::path::append(Path, Filename); - auto ErrOrObjectFile = BinHolder.GetObjectFile(Path); - if (auto EC = ErrOrObjectFile.getError()) { + auto ErrOrObjectFiles = BinHolder.GetObjectFiles(Path); + if (auto EC = ErrOrObjectFiles.getError()) { llvm::errs() << "warning: Unable to open " << Path << " " << EC.message() << '\n'; - } else { + } else if (auto ErrOrObjectFile = BinHolder.Get(Ctxt.BinaryTriple)) { // Rewrite the object file symbol addresses in the debug map. The // YAML input is mainly used to test llvm-dsymutil without // requiring binaries checked-in. If we generate the object files diff --git a/tools/dsymutil/DwarfLinker.cpp b/tools/dsymutil/DwarfLinker.cpp index ba136d1d96f..484c86aa5df 100644 --- a/tools/dsymutil/DwarfLinker.cpp +++ b/tools/dsymutil/DwarfLinker.cpp @@ -1410,6 +1410,11 @@ private: const DWARFDebugInfoEntryMinimal *DIE = nullptr) const; bool createStreamer(Triple TheTriple, StringRef OutputFilename); + + /// \brief Attempt to load a debug object from disk. + ErrorOr loadObject(BinaryHolder &BinaryHolder, + DebugMapObject &Obj, + const DebugMap &Map); /// @} private: @@ -3008,6 +3013,19 @@ void DwarfLinker::patchFrameInfoForObject(const DebugMapObject &DMO, } } +ErrorOr +DwarfLinker::loadObject(BinaryHolder &BinaryHolder, DebugMapObject &Obj, + const DebugMap &Map) { + auto ErrOrObjs = + BinaryHolder.GetObjectFiles(Obj.getObjectFilename(), Obj.getTimestamp()); + if (std::error_code EC = ErrOrObjs.getError()) + reportWarning(Twine(Obj.getObjectFilename()) + ": " + EC.message()); + auto ErrOrObj = BinaryHolder.Get(Map.getTriple()); + if (std::error_code EC = ErrOrObj.getError()) + reportWarning(Twine(Obj.getObjectFilename()) + ": " + EC.message()); + return ErrOrObj; +} + bool DwarfLinker::link(const DebugMap &Map) { if (Map.begin() == Map.end()) { @@ -3027,12 +3045,9 @@ bool DwarfLinker::link(const DebugMap &Map) { if (Options.Verbose) outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n"; - auto ErrOrObj = - BinHolder.GetObjectFile(Obj->getObjectFilename(), Obj->getTimestamp()); - if (std::error_code EC = ErrOrObj.getError()) { - reportWarning(Twine(Obj->getObjectFilename()) + ": " + EC.message()); + auto ErrOrObj = loadObject(BinHolder, *Obj, Map); + if (!ErrOrObj) continue; - } // Look for relocations that correspond to debug map entries. if (!findValidRelocsInDebugInfo(*ErrOrObj, *Obj)) { diff --git a/tools/dsymutil/MachODebugMapParser.cpp b/tools/dsymutil/MachODebugMapParser.cpp index cda43494b9b..33554f12122 100644 --- a/tools/dsymutil/MachODebugMapParser.cpp +++ b/tools/dsymutil/MachODebugMapParser.cpp @@ -58,8 +58,8 @@ private: void switchToNewDebugMapObject(StringRef Filename, sys::TimeValue Timestamp); void resetParserState(); uint64_t getMainBinarySymbolAddress(StringRef Name); - void loadMainBinarySymbols(); - void loadCurrentObjectFileSymbols(); + void loadMainBinarySymbols(const MachOObjectFile &MainBinary); + void loadCurrentObjectFileSymbols(const object::MachOObjectFile &Obj); void handleStabSymbolTableEntry(uint32_t StringIndex, uint8_t Type, uint8_t SectionIndex, uint16_t Flags, uint64_t Value); @@ -92,27 +92,38 @@ void MachODebugMapParser::switchToNewDebugMapObject(StringRef Filename, sys::path::append(Path, Filename); auto MachOOrError = - CurrentObjectHolder.GetFileAs(Path, Timestamp); + CurrentObjectHolder.GetFilesAs(Path, Timestamp); if (auto Error = MachOOrError.getError()) { Warning(Twine("cannot open debug object \"") + Path.str() + "\": " + Error.message() + "\n"); return; } - loadCurrentObjectFileSymbols(); + auto ErrOrAchObj = + CurrentObjectHolder.GetAs(Result->getTriple()); + if (auto Err = ErrOrAchObj.getError()) { + return Warning(Twine("cannot open debug object \"") + Path.str() + "\": " + + Err.message() + "\n"); + } + CurrentDebugMapObject = &Result->addDebugMapObject(Path, Timestamp); + loadCurrentObjectFileSymbols(*ErrOrAchObj); } /// This main parsing routine tries to open the main binary and if /// successful iterates over the STAB entries. The real parsing is /// done in handleStabSymbolTableEntry. ErrorOr> MachODebugMapParser::parse() { - auto MainBinOrError = MainBinaryHolder.GetFileAs(BinaryPath); + auto MainBinOrError = + MainBinaryHolder.GetFilesAs(BinaryPath); if (auto Error = MainBinOrError.getError()) return Error; - const MachOObjectFile &MainBinary = *MainBinOrError; - loadMainBinarySymbols(); + if (MainBinOrError->size() != 1) + return make_error_code(object::object_error::invalid_file_type); + + const MachOObjectFile &MainBinary = *MainBinOrError->front(); + loadMainBinarySymbols(MainBinary); Result = make_unique(BinaryHolder::getTriple(MainBinary)); MainBinaryStrings = MainBinary.getStringTableData(); for (const SymbolRef &Symbol : MainBinary.symbols()) { @@ -189,10 +200,11 @@ void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex, } /// Load the current object file symbols into CurrentObjectAddresses. -void MachODebugMapParser::loadCurrentObjectFileSymbols() { +void MachODebugMapParser::loadCurrentObjectFileSymbols( + const object::MachOObjectFile &Obj) { CurrentObjectAddresses.clear(); - for (auto Sym : CurrentObjectHolder.Get().symbols()) { + for (auto Sym : Obj.symbols()) { uint64_t Addr = Sym.getValue(); ErrorOr Name = Sym.getName(); if (!Name) @@ -213,9 +225,10 @@ uint64_t MachODebugMapParser::getMainBinarySymbolAddress(StringRef Name) { /// Load the interesting main binary symbols' addresses into /// MainBinarySymbolAddresses. -void MachODebugMapParser::loadMainBinarySymbols() { - const MachOObjectFile &MainBinary = MainBinaryHolder.GetAs(); +void MachODebugMapParser::loadMainBinarySymbols( + const MachOObjectFile &MainBinary) { section_iterator Section = MainBinary.section_end(); + MainBinarySymbolAddresses.clear(); for (const auto &Sym : MainBinary.symbols()) { SymbolRef::Type Type = Sym.getType(); // Skip undefined and STAB entries.