1 //===-- BinaryHolder.cpp --------------------------------------------------===//
3 // The LLVM Compiler Infrastructure
5 // This file is distributed under the University of Illinois Open Source
6 // License. See LICENSE.TXT for details.
8 //===----------------------------------------------------------------------===//
10 // This program is a utility that aims to be a dropin replacement for
13 //===----------------------------------------------------------------------===//
15 #include "BinaryHolder.h"
16 #include "llvm/Support/raw_ostream.h"
21 ErrorOr<MemoryBufferRef>
22 BinaryHolder::GetMemoryBufferForFile(StringRef Filename,
23 sys::TimeValue Timestamp) {
25 outs() << "trying to open '" << Filename << "'\n";
27 // Try that first as it doesn't involve any filesystem access.
28 if (auto ErrOrArchiveMember = GetArchiveMemberBuffer(Filename, Timestamp))
29 return *ErrOrArchiveMember;
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;
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())
48 outs() << "\tloaded file.\n";
49 CurrentArchive.reset();
50 CurrentMemoryBuffer = std::move(ErrOrFile.get());
51 return CurrentMemoryBuffer->getMemBufferRef();
54 ErrorOr<MemoryBufferRef>
55 BinaryHolder::GetArchiveMemberBuffer(StringRef Filename,
56 sys::TimeValue Timestamp) {
58 return make_error_code(errc::no_such_file_or_directory);
60 StringRef CurArchiveName = CurrentArchive->getFileName();
61 if (!Filename.startswith(Twine(CurArchiveName, "(").str()))
62 return make_error_code(errc::no_such_file_or_directory);
64 // Remove the archive name and the parens around the archive member name.
65 Filename = Filename.substr(CurArchiveName.size() + 1).drop_back();
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()) {
73 outs() << "\tmember had timestamp mismatch.\n";
77 outs() << "\tfound member in current archive.\n";
78 return Child.getMemoryBufferRef();
82 return make_error_code(errc::no_such_file_or_directory);
85 ErrorOr<MemoryBufferRef>
86 BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename,
87 sys::TimeValue Timestamp) {
88 StringRef ArchiveFilename = Filename.substr(0, Filename.find('('));
90 auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename);
91 if (auto Err = ErrOrBuff.getError())
95 outs() << "\topened new archive '" << ArchiveFilename << "'\n";
96 auto ErrOrArchive = object::Archive::create((*ErrOrBuff)->getMemBufferRef());
97 if (auto Err = ErrOrArchive.getError())
100 CurrentArchive = std::move(*ErrOrArchive);
101 CurrentMemoryBuffer = std::move(*ErrOrBuff);
103 return GetArchiveMemberBuffer(Filename, Timestamp);
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())
112 auto ErrOrObjectFile =
113 object::ObjectFile::createObjectFile(*ErrOrMemBufferRef);
114 if (auto Err = ErrOrObjectFile.getError())
117 CurrentObjectFile = std::move(*ErrOrObjectFile);
118 return *CurrentObjectFile;