blob: 4c2c1d195c3ca5a55a33648b4c21dbdba28a30fd [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 Riss65f0abf2015-07-24 06:41:04 +000022Triple BinaryHolder::getTriple(const object::MachOObjectFile &Obj) {
23 // If a ThumbTriple is returned, use it instead of the standard
24 // one. This is because the thumb triple always allows to create a
25 // target, whereas the non-thumb one might not.
26 Triple ThumbTriple;
27 Triple T = Obj.getArch(nullptr, &ThumbTriple);
28 return ThumbTriple.getArch() ? ThumbTriple : T;
29}
30
Frederic Risseb85c8f2015-07-24 06:41:11 +000031static std::vector<MemoryBufferRef>
32getMachOFatMemoryBuffers(StringRef Filename, MemoryBuffer &Mem,
33 object::MachOUniversalBinary &Fat) {
34 std::vector<MemoryBufferRef> Buffers;
35 StringRef FatData = Fat.getData();
36 for (auto It = Fat.begin_objects(), End = Fat.end_objects(); It != End;
37 ++It) {
38 StringRef ObjData = FatData.substr(It->getOffset(), It->getSize());
39 Buffers.emplace_back(ObjData, Filename);
40 }
41 return Buffers;
42}
43
Frederic Riss93884062015-07-24 06:40:59 +000044void BinaryHolder::changeBackingMemoryBuffer(
45 std::unique_ptr<MemoryBuffer> &&Buf) {
Frederic Risseb85c8f2015-07-24 06:41:11 +000046 CurrentArchives.clear();
47 CurrentObjectFiles.clear();
48 CurrentFatBinary.reset();
Frederic Riss93884062015-07-24 06:40:59 +000049
50 CurrentMemoryBuffer = std::move(Buf);
51}
52
Frederic Risseb85c8f2015-07-24 06:41:11 +000053ErrorOr<std::vector<MemoryBufferRef>>
54BinaryHolder::GetMemoryBuffersForFile(StringRef Filename,
55 sys::TimeValue Timestamp) {
Frederic Riss43988502015-01-05 21:29:28 +000056 if (Verbose)
57 outs() << "trying to open '" << Filename << "'\n";
58
59 // Try that first as it doesn't involve any filesystem access.
Frederic Risseb85c8f2015-07-24 06:41:11 +000060 if (auto ErrOrArchiveMembers = GetArchiveMemberBuffers(Filename, Timestamp))
61 return *ErrOrArchiveMembers;
Frederic Riss43988502015-01-05 21:29:28 +000062
63 // If the name ends with a closing paren, there is a huge chance
64 // it is an archive member specification.
65 if (Filename.endswith(")"))
Frederic Risseb85c8f2015-07-24 06:41:11 +000066 if (auto ErrOrArchiveMembers =
67 MapArchiveAndGetMemberBuffers(Filename, Timestamp))
68 return *ErrOrArchiveMembers;
Frederic Riss43988502015-01-05 21:29:28 +000069
70 // Otherwise, just try opening a standard file. If this is an
71 // archive member specifiaction and any of the above didn't handle it
72 // (either because the archive is not there anymore, or because the
73 // archive doesn't contain the requested member), this will still
74 // provide a sensible error message.
75 auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(Filename);
76 if (auto Err = ErrOrFile.getError())
77 return Err;
78
Frederic Riss93884062015-07-24 06:40:59 +000079 changeBackingMemoryBuffer(std::move(*ErrOrFile));
Frederic Riss43988502015-01-05 21:29:28 +000080 if (Verbose)
81 outs() << "\tloaded file.\n";
Frederic Risseb85c8f2015-07-24 06:41:11 +000082
83 auto ErrOrFat = object::MachOUniversalBinary::create(
84 CurrentMemoryBuffer->getMemBufferRef());
85 if (ErrOrFat.getError()) {
86 // Not a fat binary must be a standard one. Return a one element vector.
87 return std::vector<MemoryBufferRef>{CurrentMemoryBuffer->getMemBufferRef()};
88 }
89
90 CurrentFatBinary = std::move(*ErrOrFat);
91 return getMachOFatMemoryBuffers(Filename, *CurrentMemoryBuffer,
92 *CurrentFatBinary);
Frederic Riss43988502015-01-05 21:29:28 +000093}
94
Frederic Risseb85c8f2015-07-24 06:41:11 +000095ErrorOr<std::vector<MemoryBufferRef>>
96BinaryHolder::GetArchiveMemberBuffers(StringRef Filename,
97 sys::TimeValue Timestamp) {
98 if (CurrentArchives.empty())
Frederic Riss43988502015-01-05 21:29:28 +000099 return make_error_code(errc::no_such_file_or_directory);
100
Frederic Risseb85c8f2015-07-24 06:41:11 +0000101 StringRef CurArchiveName = CurrentArchives.front()->getFileName();
Frederic Riss43988502015-01-05 21:29:28 +0000102 if (!Filename.startswith(Twine(CurArchiveName, "(").str()))
103 return make_error_code(errc::no_such_file_or_directory);
104
105 // Remove the archive name and the parens around the archive member name.
106 Filename = Filename.substr(CurArchiveName.size() + 1).drop_back();
107
Frederic Risseb85c8f2015-07-24 06:41:11 +0000108 std::vector<MemoryBufferRef> Buffers;
109 Buffers.reserve(CurrentArchives.size());
110
111 for (const auto &CurrentArchive : CurrentArchives) {
Kevin Enderby7a969422015-11-05 19:24:56 +0000112 for (auto ChildOrErr : CurrentArchive->children()) {
113 if (std::error_code Err = ChildOrErr.getError())
114 return Err;
115 const auto &Child = *ChildOrErr;
Frederic Risseb85c8f2015-07-24 06:41:11 +0000116 if (auto NameOrErr = Child.getName()) {
117 if (*NameOrErr == Filename) {
118 if (Timestamp != sys::TimeValue::PosixZeroTime() &&
119 Timestamp != Child.getLastModified()) {
120 if (Verbose)
121 outs() << "\tmember had timestamp mismatch.\n";
122 continue;
123 }
Frederic Riss9ccfddc2015-07-22 23:24:00 +0000124 if (Verbose)
Frederic Risseb85c8f2015-07-24 06:41:11 +0000125 outs() << "\tfound member in current archive.\n";
126 auto ErrOrMem = Child.getMemoryBufferRef();
127 if (auto Err = ErrOrMem.getError())
128 return Err;
129 Buffers.push_back(*ErrOrMem);
Frederic Riss9ccfddc2015-07-22 23:24:00 +0000130 }
Frederic Riss43988502015-01-05 21:29:28 +0000131 }
Frederic Risseb85c8f2015-07-24 06:41:11 +0000132 }
Frederic Riss43988502015-01-05 21:29:28 +0000133 }
134
Frederic Risseb85c8f2015-07-24 06:41:11 +0000135 if (Buffers.empty())
136 return make_error_code(errc::no_such_file_or_directory);
137 return Buffers;
Frederic Riss43988502015-01-05 21:29:28 +0000138}
139
Frederic Risseb85c8f2015-07-24 06:41:11 +0000140ErrorOr<std::vector<MemoryBufferRef>>
141BinaryHolder::MapArchiveAndGetMemberBuffers(StringRef Filename,
142 sys::TimeValue Timestamp) {
Frederic Riss43988502015-01-05 21:29:28 +0000143 StringRef ArchiveFilename = Filename.substr(0, Filename.find('('));
144
145 auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename);
146 if (auto Err = ErrOrBuff.getError())
147 return Err;
148
149 if (Verbose)
150 outs() << "\topened new archive '" << ArchiveFilename << "'\n";
Frederic Riss93884062015-07-24 06:40:59 +0000151
152 changeBackingMemoryBuffer(std::move(*ErrOrBuff));
Frederic Risseb85c8f2015-07-24 06:41:11 +0000153 std::vector<MemoryBufferRef> ArchiveBuffers;
154 auto ErrOrFat = object::MachOUniversalBinary::create(
155 CurrentMemoryBuffer->getMemBufferRef());
156 if (ErrOrFat.getError()) {
157 // Not a fat binary must be a standard one.
158 ArchiveBuffers.push_back(CurrentMemoryBuffer->getMemBufferRef());
159 } else {
160 CurrentFatBinary = std::move(*ErrOrFat);
161 ArchiveBuffers = getMachOFatMemoryBuffers(
162 ArchiveFilename, *CurrentMemoryBuffer, *CurrentFatBinary);
163 }
Frederic Riss43988502015-01-05 21:29:28 +0000164
Frederic Risseb85c8f2015-07-24 06:41:11 +0000165 for (auto MemRef : ArchiveBuffers) {
166 auto ErrOrArchive = object::Archive::create(MemRef);
167 if (auto Err = ErrOrArchive.getError())
168 return Err;
169 CurrentArchives.push_back(std::move(*ErrOrArchive));
170 }
171 return GetArchiveMemberBuffers(Filename, Timestamp);
Frederic Riss43988502015-01-05 21:29:28 +0000172}
173
174ErrorOr<const object::ObjectFile &>
Frederic Risseb85c8f2015-07-24 06:41:11 +0000175BinaryHolder::getObjfileForArch(const Triple &T) {
176 for (const auto &Obj : CurrentObjectFiles) {
177 if (const auto *MachO = dyn_cast<object::MachOObjectFile>(Obj.get())) {
178 if (getTriple(*MachO).str() == T.str())
179 return *MachO;
180 } else if (Obj->getArch() == T.getArch())
181 return *Obj;
182 }
183
184 return make_error_code(object::object_error::arch_not_found);
185}
186
187ErrorOr<std::vector<const object::ObjectFile *>>
188BinaryHolder::GetObjectFiles(StringRef Filename, sys::TimeValue Timestamp) {
189 auto ErrOrMemBufferRefs = GetMemoryBuffersForFile(Filename, Timestamp);
190 if (auto Err = ErrOrMemBufferRefs.getError())
Frederic Riss43988502015-01-05 21:29:28 +0000191 return Err;
192
Frederic Risseb85c8f2015-07-24 06:41:11 +0000193 std::vector<const object::ObjectFile *> Objects;
194 Objects.reserve(ErrOrMemBufferRefs->size());
Frederic Riss43988502015-01-05 21:29:28 +0000195
Frederic Risseb85c8f2015-07-24 06:41:11 +0000196 CurrentObjectFiles.clear();
197 for (auto MemBuf : *ErrOrMemBufferRefs) {
198 auto ErrOrObjectFile = object::ObjectFile::createObjectFile(MemBuf);
199 if (auto Err = ErrOrObjectFile.getError())
200 return Err;
201
202 Objects.push_back(ErrOrObjectFile->get());
203 CurrentObjectFiles.push_back(std::move(*ErrOrObjectFile));
204 }
205
206 return std::move(Objects);
Frederic Riss43988502015-01-05 21:29:28 +0000207}
208}
209}