blob: 49fe901b41950112b5d3f0722ed51c9309246c11 [file] [log] [blame]
Frederic Riss43988502015-01-05 21:29:28 +00001//===-- 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
18namespace llvm {
19namespace dsymutil {
20
21ErrorOr<MemoryBufferRef>
Frederic Riss9ccfddc2015-07-22 23:24:00 +000022BinaryHolder::GetMemoryBufferForFile(StringRef Filename,
23 sys::TimeValue Timestamp) {
Frederic Riss43988502015-01-05 21:29:28 +000024 if (Verbose)
25 outs() << "trying to open '" << Filename << "'\n";
26
27 // Try that first as it doesn't involve any filesystem access.
Frederic Riss9ccfddc2015-07-22 23:24:00 +000028 if (auto ErrOrArchiveMember = GetArchiveMemberBuffer(Filename, Timestamp))
Frederic Riss43988502015-01-05 21:29:28 +000029 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(")"))
Frederic Riss9ccfddc2015-07-22 23:24:00 +000034 if (auto ErrOrArchiveMember =
35 MapArchiveAndGetMemberBuffer(Filename, Timestamp))
Frederic Riss43988502015-01-05 21:29:28 +000036 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
54ErrorOr<MemoryBufferRef>
Frederic Riss9ccfddc2015-07-22 23:24:00 +000055BinaryHolder::GetArchiveMemberBuffer(StringRef Filename,
56 sys::TimeValue Timestamp) {
Frederic Riss43988502015-01-05 21:29:28 +000057 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) {
Frederic Riss9ccfddc2015-07-22 23:24:00 +000070 if (Timestamp != sys::TimeValue::PosixZeroTime() &&
71 Timestamp != Child.getLastModified()) {
72 if (Verbose)
73 outs() << "\tmember had timestamp mismatch.\n";
74 continue;
75 }
Frederic Riss43988502015-01-05 21:29:28 +000076 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
85ErrorOr<MemoryBufferRef>
Frederic Riss9ccfddc2015-07-22 23:24:00 +000086BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename,
87 sys::TimeValue Timestamp) {
Frederic Riss43988502015-01-05 21:29:28 +000088 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
Frederic Riss9ccfddc2015-07-22 23:24:00 +0000103 return GetArchiveMemberBuffer(Filename, Timestamp);
Frederic Riss43988502015-01-05 21:29:28 +0000104}
105
106ErrorOr<const object::ObjectFile &>
Frederic Riss9ccfddc2015-07-22 23:24:00 +0000107BinaryHolder::GetObjectFile(StringRef Filename, sys::TimeValue Timestamp) {
108 auto ErrOrMemBufferRef = GetMemoryBufferForFile(Filename, Timestamp);
Frederic Riss43988502015-01-05 21:29:28 +0000109 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}