[dsymutil] Check archive members timestamps.
[oota-llvm.git] / tools / dsymutil / BinaryHolder.cpp
1 //===-- BinaryHolder.cpp --------------------------------------------------===//
2 //
3 //                     The LLVM Compiler Infrastructure
4 //
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
7 //
8 //===----------------------------------------------------------------------===//
9 //
10 // This program is a utility that aims to be a dropin replacement for
11 // Darwin's dsymutil.
12 //
13 //===----------------------------------------------------------------------===//
14
15 #include "BinaryHolder.h"
16 #include "llvm/Support/raw_ostream.h"
17
18 namespace llvm {
19 namespace dsymutil {
20
21 ErrorOr<MemoryBufferRef>
22 BinaryHolder::GetMemoryBufferForFile(StringRef Filename,
23                                      sys::TimeValue Timestamp) {
24   if (Verbose)
25     outs() << "trying to open '" << Filename << "'\n";
26
27   // Try that first as it doesn't involve any filesystem access.
28   if (auto ErrOrArchiveMember = GetArchiveMemberBuffer(Filename, Timestamp))
29     return *ErrOrArchiveMember;
30
31   // If the name ends with a closing paren, there is a huge chance
32   // it is an archive member specification.
33   if (Filename.endswith(")"))
34     if (auto ErrOrArchiveMember =
35             MapArchiveAndGetMemberBuffer(Filename, Timestamp))
36       return *ErrOrArchiveMember;
37
38   // Otherwise, just try opening a standard file. If this is an
39   // archive member specifiaction and any of the above didn't handle it
40   // (either because the archive is not there anymore, or because the
41   // archive doesn't contain the requested member), this will still
42   // provide a sensible error message.
43   auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(Filename);
44   if (auto Err = ErrOrFile.getError())
45     return Err;
46
47   if (Verbose)
48     outs() << "\tloaded file.\n";
49   CurrentArchive.reset();
50   CurrentMemoryBuffer = std::move(ErrOrFile.get());
51   return CurrentMemoryBuffer->getMemBufferRef();
52 }
53
54 ErrorOr<MemoryBufferRef>
55 BinaryHolder::GetArchiveMemberBuffer(StringRef Filename,
56                                      sys::TimeValue Timestamp) {
57   if (!CurrentArchive)
58     return make_error_code(errc::no_such_file_or_directory);
59
60   StringRef CurArchiveName = CurrentArchive->getFileName();
61   if (!Filename.startswith(Twine(CurArchiveName, "(").str()))
62     return make_error_code(errc::no_such_file_or_directory);
63
64   // Remove the archive name and the parens around the archive member name.
65   Filename = Filename.substr(CurArchiveName.size() + 1).drop_back();
66
67   for (const auto &Child : CurrentArchive->children()) {
68     if (auto NameOrErr = Child.getName())
69       if (*NameOrErr == Filename) {
70         if (Timestamp != sys::TimeValue::PosixZeroTime() &&
71             Timestamp != Child.getLastModified()) {
72           if (Verbose)
73             outs() << "\tmember had timestamp mismatch.\n";
74           continue;
75         }
76         if (Verbose)
77           outs() << "\tfound member in current archive.\n";
78         return Child.getMemoryBufferRef();
79       }
80   }
81
82   return make_error_code(errc::no_such_file_or_directory);
83 }
84
85 ErrorOr<MemoryBufferRef>
86 BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename,
87                                            sys::TimeValue Timestamp) {
88   StringRef ArchiveFilename = Filename.substr(0, Filename.find('('));
89
90   auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename);
91   if (auto Err = ErrOrBuff.getError())
92     return Err;
93
94   if (Verbose)
95     outs() << "\topened new archive '" << ArchiveFilename << "'\n";
96   auto ErrOrArchive = object::Archive::create((*ErrOrBuff)->getMemBufferRef());
97   if (auto Err = ErrOrArchive.getError())
98     return Err;
99
100   CurrentArchive = std::move(*ErrOrArchive);
101   CurrentMemoryBuffer = std::move(*ErrOrBuff);
102
103   return GetArchiveMemberBuffer(Filename, Timestamp);
104 }
105
106 ErrorOr<const object::ObjectFile &>
107 BinaryHolder::GetObjectFile(StringRef Filename, sys::TimeValue Timestamp) {
108   auto ErrOrMemBufferRef = GetMemoryBufferForFile(Filename, Timestamp);
109   if (auto Err = ErrOrMemBufferRef.getError())
110     return Err;
111
112   auto ErrOrObjectFile =
113       object::ObjectFile::createObjectFile(*ErrOrMemBufferRef);
114   if (auto Err = ErrOrObjectFile.getError())
115     return Err;
116
117   CurrentObjectFile = std::move(*ErrOrObjectFile);
118   return *CurrentObjectFile;
119 }
120 }
121 }