diff --git a/llvm/test/tools/dsymutil/archive-timestamp.test b/llvm/test/tools/dsymutil/archive-timestamp.test new file mode 100644 index 000000000000..11add6d0b72c --- /dev/null +++ b/llvm/test/tools/dsymutil/archive-timestamp.test @@ -0,0 +1,24 @@ +# RUN: llvm-dsymutil -no-output -v -oso-prepend-path=%p -y %s 2>&1 | FileCheck %s + +# This is the archive member part of basic-archive.macho.x86_64 debug map with corrupted timestamps. + +# CHECK: warning: {{.*}}libbasic.a(basic2.macho.x86_64.o): {{[Nn]o}} such file +# CHECK: warning: {{.*}}libbasic.a(basic3.macho.x86_64.o): {{[Nn]o}} such file + +--- +triple: 'x86_64-unknown-unknown-macho' +objects: + - filename: '/Inputs/libbasic.a(basic2.macho.x86_64.o)' + timestamp: 141869239 + symbols: + - { sym: _foo, objAddr: 0x0000000000000020, binAddr: 0x0000000100000ED0, size: 0x00000050 } + - { sym: _private_int, objAddr: 0x0000000000000560, binAddr: 0x0000000100001004, size: 0x00000000 } + - { sym: _inc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000F20, size: 0x00000017 } + - { sym: _baz, objAddr: 0x0000000000000310, binAddr: 0x0000000100001000, size: 0x00000000 } + - filename: '/Inputs/libbasic.a(basic3.macho.x86_64.o)' + timestamp: 418692393 + symbols: + - { sym: _val, objAddr: 0x0000000000000004, binAddr: 0x0000000100001008, size: 0x00000000 } + - { sym: _bar, objAddr: 0x0000000000000020, binAddr: 0x0000000100000F40, size: 0x00000050 } + - { sym: _inc, objAddr: 0x0000000000000070, binAddr: 0x0000000100000F90, size: 0x00000019 } +... diff --git a/llvm/test/tools/dsymutil/yaml-object-address-rewrite.test b/llvm/test/tools/dsymutil/yaml-object-address-rewrite.test index dcb39be891cd..73697d4a6e5b 100644 --- a/llvm/test/tools/dsymutil/yaml-object-address-rewrite.test +++ b/llvm/test/tools/dsymutil/yaml-object-address-rewrite.test @@ -8,9 +8,11 @@ # CHECK-NEXT: triple:{{.*}}'x86_64-unknown-unknown-macho' # CHECK-NEXT: objects: # CHECK-NEXT: filename:{{.*}}/Inputs/basic1.macho.x86_64.o +# CHECK-NEXT: timestamp: 0 # CHECK-NEXT: symbols: # CHECK-NEXT: sym: _main, objAddr: 0x0000000000000000, binAddr: 0x0000000100000EA0, size: 0x00000024 # CHECK-NEXT: filename:{{.*}}/Inputs/./libbasic.a(basic2.macho.x86_64.o)' +# CHECK-NEXT: timestamp: 0 # CHECK-NEXT: symbols: # CHECK-DAG: sym: _foo, objAddr: 0x0000000000000020, binAddr: 0x0000000100000ED0, size: 0x00000050 # CHECK-DAG: sym: _private_int, objAddr: 0x0000000000000560, binAddr: 0x0000000100001004, size: 0x00000000 @@ -18,6 +20,7 @@ # CHECK-DAG: sym: _baz, objAddr: 0x0000000000000310, binAddr: 0x0000000100001000, size: 0x00000000 # CHECK-NOT: { sym: # CHECK-NEXT: filename:{{.*}}/Inputs/./libbasic.a(basic3.macho.x86_64.o)' +# CHECK-NEXT: timestamp: 0 # CHECK-NEXT: symbols: # CHECK-DAG: sym: _val, objAddr: 0x0000000000000004, binAddr: 0x0000000100001008, size: 0x00000000 # CHECK-DAG: sym: _bar, objAddr: 0x0000000000000020, binAddr: 0x0000000100000F40, size: 0x00000050 diff --git a/llvm/tools/dsymutil/BinaryHolder.cpp b/llvm/tools/dsymutil/BinaryHolder.cpp index ad66105bc249..49fe901b4195 100644 --- a/llvm/tools/dsymutil/BinaryHolder.cpp +++ b/llvm/tools/dsymutil/BinaryHolder.cpp @@ -19,18 +19,20 @@ namespace llvm { namespace dsymutil { ErrorOr -BinaryHolder::GetMemoryBufferForFile(StringRef Filename) { +BinaryHolder::GetMemoryBufferForFile(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)) + if (auto ErrOrArchiveMember = GetArchiveMemberBuffer(Filename, Timestamp)) return *ErrOrArchiveMember; // 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)) + if (auto ErrOrArchiveMember = + MapArchiveAndGetMemberBuffer(Filename, Timestamp)) return *ErrOrArchiveMember; // Otherwise, just try opening a standard file. If this is an @@ -50,7 +52,8 @@ BinaryHolder::GetMemoryBufferForFile(StringRef Filename) { } ErrorOr -BinaryHolder::GetArchiveMemberBuffer(StringRef Filename) { +BinaryHolder::GetArchiveMemberBuffer(StringRef Filename, + sys::TimeValue Timestamp) { if (!CurrentArchive) return make_error_code(errc::no_such_file_or_directory); @@ -64,6 +67,12 @@ BinaryHolder::GetArchiveMemberBuffer(StringRef Filename) { 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() << "\tfound member in current archive.\n"; return Child.getMemoryBufferRef(); @@ -74,7 +83,8 @@ BinaryHolder::GetArchiveMemberBuffer(StringRef Filename) { } ErrorOr -BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename) { +BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename, + sys::TimeValue Timestamp) { StringRef ArchiveFilename = Filename.substr(0, Filename.find('(')); auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename); @@ -90,12 +100,12 @@ BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename) { CurrentArchive = std::move(*ErrOrArchive); CurrentMemoryBuffer = std::move(*ErrOrBuff); - return GetArchiveMemberBuffer(Filename); + return GetArchiveMemberBuffer(Filename, Timestamp); } ErrorOr -BinaryHolder::GetObjectFile(StringRef Filename) { - auto ErrOrMemBufferRef = GetMemoryBufferForFile(Filename); +BinaryHolder::GetObjectFile(StringRef Filename, sys::TimeValue Timestamp) { + auto ErrOrMemBufferRef = GetMemoryBufferForFile(Filename, Timestamp); if (auto Err = ErrOrMemBufferRef.getError()) return Err; diff --git a/llvm/tools/dsymutil/BinaryHolder.h b/llvm/tools/dsymutil/BinaryHolder.h index 04871b5d5855..84c07ce0c4bc 100644 --- a/llvm/tools/dsymutil/BinaryHolder.h +++ b/llvm/tools/dsymutil/BinaryHolder.h @@ -19,6 +19,7 @@ #include "llvm/Object/ObjectFile.h" #include "llvm/Support/Errc.h" #include "llvm/Support/ErrorOr.h" +#include "llvm/Support/TimeValue.h" namespace llvm { namespace dsymutil { @@ -46,12 +47,14 @@ class BinaryHolder { /// 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); + ErrorOr GetArchiveMemberBuffer(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); + ErrorOr + MapArchiveAndGetMemberBuffer(StringRef Filename, sys::TimeValue Timestamp); /// \brief Return the MemoryBufferRef that holds the memory /// mapping for the given \p Filename. This function will try to @@ -61,7 +64,8 @@ class BinaryHolder { /// The returned MemoryBufferRef 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); + ErrorOr GetMemoryBufferForFile(StringRef Filename, + sys::TimeValue Timestamp); public: BinaryHolder(bool Verbose) : Verbose(Verbose) {} @@ -72,11 +76,15 @@ public: /// /// Calling this function invalidates the previous mapping owned by /// the BinaryHolder. - ErrorOr GetObjectFile(StringRef Filename); + ErrorOr + GetObjectFile(StringRef Filename, + sys::TimeValue Timestamp = sys::TimeValue::PosixZeroTime()); /// \brief Wraps GetObjectFile() to return a derived ObjectFile type. template - ErrorOr GetFileAs(StringRef Filename) { + ErrorOr + GetFileAs(StringRef Filename, + sys::TimeValue Timestamp = sys::TimeValue::PosixZeroTime()) { auto ErrOrObjFile = GetObjectFile(Filename); if (auto Err = ErrOrObjFile.getError()) return Err; diff --git a/llvm/tools/dsymutil/DebugMap.cpp b/llvm/tools/dsymutil/DebugMap.cpp index e5cc87b3f318..24dedfcb673d 100644 --- a/llvm/tools/dsymutil/DebugMap.cpp +++ b/llvm/tools/dsymutil/DebugMap.cpp @@ -20,8 +20,9 @@ namespace dsymutil { using namespace llvm::object; -DebugMapObject::DebugMapObject(StringRef ObjectFilename) - : Filename(ObjectFilename) {} +DebugMapObject::DebugMapObject(StringRef ObjectFilename, + sys::TimeValue Timestamp) + : Filename(ObjectFilename), Timestamp(Timestamp) {} bool DebugMapObject::addSymbol(StringRef Name, uint64_t ObjectAddress, uint64_t LinkedAddress, uint32_t Size) { @@ -58,8 +59,9 @@ void DebugMapObject::print(raw_ostream &OS) const { void DebugMapObject::dump() const { print(errs()); } #endif -DebugMapObject &DebugMap::addDebugMapObject(StringRef ObjectFilePath) { - Objects.emplace_back(new DebugMapObject(ObjectFilePath)); +DebugMapObject &DebugMap::addDebugMapObject(StringRef ObjectFilePath, + sys::TimeValue Timestamp) { + Objects.emplace_back(new DebugMapObject(ObjectFilePath, Timestamp)); return *Objects.back(); } @@ -121,11 +123,12 @@ namespace yaml { // Normalize/Denormalize between YAML and a DebugMapObject. struct MappingTraits::YamlDMO { - YamlDMO(IO &io) {} + YamlDMO(IO &io) { Timestamp = 0; } YamlDMO(IO &io, dsymutil::DebugMapObject &Obj); dsymutil::DebugMapObject denormalize(IO &IO); std::string Filename; + sys::TimeValue::SecondsType Timestamp; std::vector Entries; }; @@ -141,6 +144,7 @@ void MappingTraits::mapping( IO &io, dsymutil::DebugMapObject &DMO) { MappingNormalization Norm(io, DMO); io.mapRequired("filename", Norm->Filename); + io.mapOptional("timestamp", Norm->Timestamp); io.mapRequired("symbols", Norm->Entries); } @@ -192,6 +196,7 @@ void MappingTraits>::mapping( MappingTraits::YamlDMO::YamlDMO( IO &io, dsymutil::DebugMapObject &Obj) { Filename = Obj.Filename; + Timestamp = Obj.getTimestamp().toEpochTime(); Entries.reserve(Obj.Symbols.size()); for (auto &Entry : Obj.Symbols) Entries.push_back(std::make_pair(Entry.getKey(), Entry.getValue())); @@ -224,7 +229,9 @@ MappingTraits::YamlDMO::denormalize(IO &IO) { } } - dsymutil::DebugMapObject Res(Path); + sys::TimeValue TV; + TV.fromEpochTime(Timestamp); + dsymutil::DebugMapObject Res(Path, TV); for (auto &Entry : Entries) { auto &Mapping = Entry.second; uint64_t ObjAddress = Mapping.ObjectAddress; diff --git a/llvm/tools/dsymutil/DebugMap.h b/llvm/tools/dsymutil/DebugMap.h index d0edbabb404b..29347ed0f505 100644 --- a/llvm/tools/dsymutil/DebugMap.h +++ b/llvm/tools/dsymutil/DebugMap.h @@ -29,6 +29,7 @@ #include "llvm/Support/ErrorOr.h" #include "llvm/Support/Format.h" #include "llvm/Support/Path.h" +#include "llvm/Support/TimeValue.h" #include "llvm/Support/YAMLTraits.h" #include @@ -89,7 +90,8 @@ public: /// This function adds an DebugMapObject to the list owned by this /// debug map. - DebugMapObject &addDebugMapObject(StringRef ObjectFilePath); + DebugMapObject &addDebugMapObject(StringRef ObjectFilePath, + sys::TimeValue Timestamp); const Triple &getTriple() const { return BinaryTriple; } @@ -139,6 +141,8 @@ public: llvm::StringRef getObjectFilename() const { return Filename; } + sys::TimeValue getTimestamp() const { return Timestamp; } + iterator_range::const_iterator> symbols() const { return make_range(Symbols.begin(), Symbols.end()); } @@ -150,9 +154,10 @@ public: private: friend class DebugMap; /// DebugMapObjects can only be constructed by the owning DebugMap. - DebugMapObject(StringRef ObjectFilename); + DebugMapObject(StringRef ObjectFilename, sys::TimeValue Timestamp); std::string Filename; + sys::TimeValue Timestamp; StringMap Symbols; DenseMap AddressToMapping; @@ -167,12 +172,14 @@ private: public: DebugMapObject &operator=(DebugMapObject RHS) { std::swap(Filename, RHS.Filename); + std::swap(Timestamp, RHS.Timestamp); std::swap(Symbols, RHS.Symbols); std::swap(AddressToMapping, RHS.AddressToMapping); return *this; } DebugMapObject(DebugMapObject &&RHS) { Filename = std::move(RHS.Filename); + Timestamp = std::move(RHS.Timestamp); Symbols = std::move(RHS.Symbols); AddressToMapping = std::move(RHS.AddressToMapping); } diff --git a/llvm/tools/dsymutil/DwarfLinker.cpp b/llvm/tools/dsymutil/DwarfLinker.cpp index bbe5cfbb1c1d..ba136d1d96fb 100644 --- a/llvm/tools/dsymutil/DwarfLinker.cpp +++ b/llvm/tools/dsymutil/DwarfLinker.cpp @@ -3027,7 +3027,8 @@ bool DwarfLinker::link(const DebugMap &Map) { if (Options.Verbose) outs() << "DEBUG MAP OBJECT: " << Obj->getObjectFilename() << "\n"; - auto ErrOrObj = BinHolder.GetObjectFile(Obj->getObjectFilename()); + auto ErrOrObj = + BinHolder.GetObjectFile(Obj->getObjectFilename(), Obj->getTimestamp()); if (std::error_code EC = ErrOrObj.getError()) { reportWarning(Twine(Obj->getObjectFilename()) + ": " + EC.message()); continue; diff --git a/llvm/tools/dsymutil/MachODebugMapParser.cpp b/llvm/tools/dsymutil/MachODebugMapParser.cpp index 6c9fa9b51325..8f3ca6ca0045 100644 --- a/llvm/tools/dsymutil/MachODebugMapParser.cpp +++ b/llvm/tools/dsymutil/MachODebugMapParser.cpp @@ -55,7 +55,7 @@ private: const char *CurrentFunctionName; uint64_t CurrentFunctionAddress; - void switchToNewDebugMapObject(StringRef Filename); + void switchToNewDebugMapObject(StringRef Filename, sys::TimeValue Timestamp); void resetParserState(); uint64_t getMainBinarySymbolAddress(StringRef Name); void loadMainBinarySymbols(); @@ -84,13 +84,15 @@ void MachODebugMapParser::resetParserState() { /// Create a new DebugMapObject. This function resets the state of the /// parser that was referring to the last object file and sets /// everything up to add symbols to the new one. -void MachODebugMapParser::switchToNewDebugMapObject(StringRef Filename) { +void MachODebugMapParser::switchToNewDebugMapObject(StringRef Filename, + sys::TimeValue Timestamp) { resetParserState(); SmallString<80> Path(PathPrefix); sys::path::append(Path, Filename); - auto MachOOrError = CurrentObjectHolder.GetFileAs(Path); + auto MachOOrError = + CurrentObjectHolder.GetFileAs(Path, Timestamp); if (auto Error = MachOOrError.getError()) { Warning(Twine("cannot open debug object \"") + Path.str() + "\": " + Error.message() + "\n"); @@ -98,7 +100,7 @@ void MachODebugMapParser::switchToNewDebugMapObject(StringRef Filename) { } loadCurrentObjectFileSymbols(); - CurrentDebugMapObject = &Result->addDebugMapObject(Path); + CurrentDebugMapObject = &Result->addDebugMapObject(Path, Timestamp); } static Triple getTriple(const object::MachOObjectFile &Obj) { @@ -144,8 +146,11 @@ void MachODebugMapParser::handleStabSymbolTableEntry(uint32_t StringIndex, const char *Name = &MainBinaryStrings.data()[StringIndex]; // An N_OSO entry represents the start of a new object file description. - if (Type == MachO::N_OSO) - return switchToNewDebugMapObject(Name); + if (Type == MachO::N_OSO) { + sys::TimeValue Timestamp; + Timestamp.fromEpochTime(Value); + return switchToNewDebugMapObject(Name, Timestamp); + } // If the last N_OSO object file wasn't found, // CurrentDebugMapObject will be null. Do not update anything