blob: 579ffc2bb744c0f9599d4da8d31caeaa9155148c [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"
Frederic Riss65f0abf2015-07-24 06:41:04 +000016#include "llvm/Object/MachO.h"
Frederic Riss43988502015-01-05 21:29:28 +000017#include "llvm/Support/raw_ostream.h"
18
19namespace llvm {
20namespace dsymutil {
21
Frederic Risseb85c8f2015-07-24 06:41:11 +000022static std::vector<MemoryBufferRef>
23getMachOFatMemoryBuffers(StringRef Filename, MemoryBuffer &Mem,
24 object::MachOUniversalBinary &Fat) {
25 std::vector<MemoryBufferRef> Buffers;
26 StringRef FatData = Fat.getData();
27 for (auto It = Fat.begin_objects(), End = Fat.end_objects(); It != End;
28 ++It) {
29 StringRef ObjData = FatData.substr(It->getOffset(), It->getSize());
30 Buffers.emplace_back(ObjData, Filename);
31 }
32 return Buffers;
33}
34
Frederic Riss93884062015-07-24 06:40:59 +000035void BinaryHolder::changeBackingMemoryBuffer(
36 std::unique_ptr<MemoryBuffer> &&Buf) {
Frederic Risseb85c8f2015-07-24 06:41:11 +000037 CurrentArchives.clear();
38 CurrentObjectFiles.clear();
39 CurrentFatBinary.reset();
Frederic Riss93884062015-07-24 06:40:59 +000040
41 CurrentMemoryBuffer = std::move(Buf);
42}
43
Frederic Risseb85c8f2015-07-24 06:41:11 +000044ErrorOr<std::vector<MemoryBufferRef>>
45BinaryHolder::GetMemoryBuffersForFile(StringRef Filename,
46 sys::TimeValue Timestamp) {
Frederic Riss43988502015-01-05 21:29:28 +000047 if (Verbose)
48 outs() << "trying to open '" << Filename << "'\n";
49
50 // Try that first as it doesn't involve any filesystem access.
Frederic Risseb85c8f2015-07-24 06:41:11 +000051 if (auto ErrOrArchiveMembers = GetArchiveMemberBuffers(Filename, Timestamp))
52 return *ErrOrArchiveMembers;
Frederic Riss43988502015-01-05 21:29:28 +000053
54 // If the name ends with a closing paren, there is a huge chance
55 // it is an archive member specification.
56 if (Filename.endswith(")"))
Frederic Risseb85c8f2015-07-24 06:41:11 +000057 if (auto ErrOrArchiveMembers =
58 MapArchiveAndGetMemberBuffers(Filename, Timestamp))
59 return *ErrOrArchiveMembers;
Frederic Riss43988502015-01-05 21:29:28 +000060
61 // Otherwise, just try opening a standard file. If this is an
62 // archive member specifiaction and any of the above didn't handle it
63 // (either because the archive is not there anymore, or because the
64 // archive doesn't contain the requested member), this will still
65 // provide a sensible error message.
66 auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(Filename);
67 if (auto Err = ErrOrFile.getError())
68 return Err;
69
Frederic Riss93884062015-07-24 06:40:59 +000070 changeBackingMemoryBuffer(std::move(*ErrOrFile));
Frederic Riss43988502015-01-05 21:29:28 +000071 if (Verbose)
72 outs() << "\tloaded file.\n";
Frederic Risseb85c8f2015-07-24 06:41:11 +000073
74 auto ErrOrFat = object::MachOUniversalBinary::create(
75 CurrentMemoryBuffer->getMemBufferRef());
Kevin Enderby10519092016-06-27 21:39:39 +000076 if (!ErrOrFat) {
77 consumeError(ErrOrFat.takeError());
Frederic Risseb85c8f2015-07-24 06:41:11 +000078 // Not a fat binary must be a standard one. Return a one element vector.
79 return std::vector<MemoryBufferRef>{CurrentMemoryBuffer->getMemBufferRef()};
80 }
81
82 CurrentFatBinary = std::move(*ErrOrFat);
Frederic Riss98f489c2016-05-09 14:44:14 +000083 CurrentFatBinaryName = Filename;
84 return getMachOFatMemoryBuffers(CurrentFatBinaryName, *CurrentMemoryBuffer,
Frederic Risseb85c8f2015-07-24 06:41:11 +000085 *CurrentFatBinary);
Frederic Riss43988502015-01-05 21:29:28 +000086}
87
Frederic Risseb85c8f2015-07-24 06:41:11 +000088ErrorOr<std::vector<MemoryBufferRef>>
89BinaryHolder::GetArchiveMemberBuffers(StringRef Filename,
90 sys::TimeValue Timestamp) {
91 if (CurrentArchives.empty())
Frederic Riss43988502015-01-05 21:29:28 +000092 return make_error_code(errc::no_such_file_or_directory);
93
Frederic Risseb85c8f2015-07-24 06:41:11 +000094 StringRef CurArchiveName = CurrentArchives.front()->getFileName();
Frederic Riss43988502015-01-05 21:29:28 +000095 if (!Filename.startswith(Twine(CurArchiveName, "(").str()))
96 return make_error_code(errc::no_such_file_or_directory);
97
98 // Remove the archive name and the parens around the archive member name.
99 Filename = Filename.substr(CurArchiveName.size() + 1).drop_back();
100
Frederic Risseb85c8f2015-07-24 06:41:11 +0000101 std::vector<MemoryBufferRef> Buffers;
102 Buffers.reserve(CurrentArchives.size());
103
104 for (const auto &CurrentArchive : CurrentArchives) {
Lang Hamesfc209622016-07-14 02:24:01 +0000105 Error Err;
106 for (auto Child : CurrentArchive->children(Err)) {
Frederic Risseb85c8f2015-07-24 06:41:11 +0000107 if (auto NameOrErr = Child.getName()) {
108 if (*NameOrErr == Filename) {
Vedant Kumar4031d9f2016-08-03 19:02:50 +0000109 Expected<sys::TimeValue> ModTimeOrErr = Child.getLastModified();
110 if (!ModTimeOrErr)
111 return errorToErrorCode(ModTimeOrErr.takeError());
Frederic Risseb85c8f2015-07-24 06:41:11 +0000112 if (Timestamp != sys::TimeValue::PosixZeroTime() &&
Vedant Kumar4031d9f2016-08-03 19:02:50 +0000113 Timestamp != ModTimeOrErr.get()) {
Frederic Risseb85c8f2015-07-24 06:41:11 +0000114 if (Verbose)
115 outs() << "\tmember had timestamp mismatch.\n";
116 continue;
117 }
Frederic Riss9ccfddc2015-07-22 23:24:00 +0000118 if (Verbose)
Frederic Risseb85c8f2015-07-24 06:41:11 +0000119 outs() << "\tfound member in current archive.\n";
120 auto ErrOrMem = Child.getMemoryBufferRef();
Kevin Enderbyf4586032016-07-29 17:44:13 +0000121 if (!ErrOrMem)
122 return errorToErrorCode(ErrOrMem.takeError());
Frederic Risseb85c8f2015-07-24 06:41:11 +0000123 Buffers.push_back(*ErrOrMem);
Frederic Riss9ccfddc2015-07-22 23:24:00 +0000124 }
Frederic Riss43988502015-01-05 21:29:28 +0000125 }
Frederic Risseb85c8f2015-07-24 06:41:11 +0000126 }
Lang Hamesfc209622016-07-14 02:24:01 +0000127 if (Err)
128 return errorToErrorCode(std::move(Err));
Frederic Riss43988502015-01-05 21:29:28 +0000129 }
130
Frederic Risseb85c8f2015-07-24 06:41:11 +0000131 if (Buffers.empty())
132 return make_error_code(errc::no_such_file_or_directory);
133 return Buffers;
Frederic Riss43988502015-01-05 21:29:28 +0000134}
135
Frederic Risseb85c8f2015-07-24 06:41:11 +0000136ErrorOr<std::vector<MemoryBufferRef>>
137BinaryHolder::MapArchiveAndGetMemberBuffers(StringRef Filename,
138 sys::TimeValue Timestamp) {
Frederic Riss43988502015-01-05 21:29:28 +0000139 StringRef ArchiveFilename = Filename.substr(0, Filename.find('('));
140
141 auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename);
142 if (auto Err = ErrOrBuff.getError())
143 return Err;
144
145 if (Verbose)
146 outs() << "\topened new archive '" << ArchiveFilename << "'\n";
Frederic Riss93884062015-07-24 06:40:59 +0000147
148 changeBackingMemoryBuffer(std::move(*ErrOrBuff));
Frederic Risseb85c8f2015-07-24 06:41:11 +0000149 std::vector<MemoryBufferRef> ArchiveBuffers;
150 auto ErrOrFat = object::MachOUniversalBinary::create(
151 CurrentMemoryBuffer->getMemBufferRef());
Kevin Enderby10519092016-06-27 21:39:39 +0000152 if (!ErrOrFat) {
153 consumeError(ErrOrFat.takeError());
Frederic Risseb85c8f2015-07-24 06:41:11 +0000154 // Not a fat binary must be a standard one.
155 ArchiveBuffers.push_back(CurrentMemoryBuffer->getMemBufferRef());
156 } else {
157 CurrentFatBinary = std::move(*ErrOrFat);
Frederic Riss98f489c2016-05-09 14:44:14 +0000158 CurrentFatBinaryName = ArchiveFilename;
Frederic Risseb85c8f2015-07-24 06:41:11 +0000159 ArchiveBuffers = getMachOFatMemoryBuffers(
Frederic Riss98f489c2016-05-09 14:44:14 +0000160 CurrentFatBinaryName, *CurrentMemoryBuffer, *CurrentFatBinary);
Frederic Risseb85c8f2015-07-24 06:41:11 +0000161 }
Frederic Riss43988502015-01-05 21:29:28 +0000162
Frederic Risseb85c8f2015-07-24 06:41:11 +0000163 for (auto MemRef : ArchiveBuffers) {
164 auto ErrOrArchive = object::Archive::create(MemRef);
Kevin Enderbyc60a3212016-06-29 20:35:44 +0000165 if (!ErrOrArchive)
166 return errorToErrorCode(ErrOrArchive.takeError());
Frederic Risseb85c8f2015-07-24 06:41:11 +0000167 CurrentArchives.push_back(std::move(*ErrOrArchive));
168 }
169 return GetArchiveMemberBuffers(Filename, Timestamp);
Frederic Riss43988502015-01-05 21:29:28 +0000170}
171
172ErrorOr<const object::ObjectFile &>
Frederic Risseb85c8f2015-07-24 06:41:11 +0000173BinaryHolder::getObjfileForArch(const Triple &T) {
174 for (const auto &Obj : CurrentObjectFiles) {
175 if (const auto *MachO = dyn_cast<object::MachOObjectFile>(Obj.get())) {
Tim Northover9e8eb412016-04-22 23:21:13 +0000176 if (MachO->getArchTriple().str() == T.str())
Frederic Risseb85c8f2015-07-24 06:41:11 +0000177 return *MachO;
178 } else if (Obj->getArch() == T.getArch())
179 return *Obj;
180 }
181
182 return make_error_code(object::object_error::arch_not_found);
183}
184
185ErrorOr<std::vector<const object::ObjectFile *>>
186BinaryHolder::GetObjectFiles(StringRef Filename, sys::TimeValue Timestamp) {
187 auto ErrOrMemBufferRefs = GetMemoryBuffersForFile(Filename, Timestamp);
188 if (auto Err = ErrOrMemBufferRefs.getError())
Frederic Riss43988502015-01-05 21:29:28 +0000189 return Err;
190
Frederic Risseb85c8f2015-07-24 06:41:11 +0000191 std::vector<const object::ObjectFile *> Objects;
192 Objects.reserve(ErrOrMemBufferRefs->size());
Frederic Riss43988502015-01-05 21:29:28 +0000193
Frederic Risseb85c8f2015-07-24 06:41:11 +0000194 CurrentObjectFiles.clear();
195 for (auto MemBuf : *ErrOrMemBufferRefs) {
196 auto ErrOrObjectFile = object::ObjectFile::createObjectFile(MemBuf);
Kevin Enderby3fcdf6a2016-04-06 22:14:09 +0000197 if (!ErrOrObjectFile)
198 return errorToErrorCode(ErrOrObjectFile.takeError());
Frederic Risseb85c8f2015-07-24 06:41:11 +0000199
200 Objects.push_back(ErrOrObjectFile->get());
201 CurrentObjectFiles.push_back(std::move(*ErrOrObjectFile));
202 }
203
204 return std::move(Objects);
Frederic Riss43988502015-01-05 21:29:28 +0000205}
206}
207}