blob: 3f0c9b1126033f944d14dd851d3a0dbed955fc06 [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 Riss93884062015-07-24 06:40:59 +000031void BinaryHolder::changeBackingMemoryBuffer(
32 std::unique_ptr<MemoryBuffer> &&Buf) {
33 CurrentArchive.reset();
34 CurrentObjectFile.reset();
35
36 CurrentMemoryBuffer = std::move(Buf);
37}
38
Frederic Riss43988502015-01-05 21:29:28 +000039ErrorOr<MemoryBufferRef>
Frederic Riss9ccfddc2015-07-22 23:24:00 +000040BinaryHolder::GetMemoryBufferForFile(StringRef Filename,
41 sys::TimeValue Timestamp) {
Frederic Riss43988502015-01-05 21:29:28 +000042 if (Verbose)
43 outs() << "trying to open '" << Filename << "'\n";
44
45 // Try that first as it doesn't involve any filesystem access.
Frederic Riss9ccfddc2015-07-22 23:24:00 +000046 if (auto ErrOrArchiveMember = GetArchiveMemberBuffer(Filename, Timestamp))
Frederic Riss43988502015-01-05 21:29:28 +000047 return *ErrOrArchiveMember;
48
49 // If the name ends with a closing paren, there is a huge chance
50 // it is an archive member specification.
51 if (Filename.endswith(")"))
Frederic Riss9ccfddc2015-07-22 23:24:00 +000052 if (auto ErrOrArchiveMember =
53 MapArchiveAndGetMemberBuffer(Filename, Timestamp))
Frederic Riss43988502015-01-05 21:29:28 +000054 return *ErrOrArchiveMember;
55
56 // Otherwise, just try opening a standard file. If this is an
57 // archive member specifiaction and any of the above didn't handle it
58 // (either because the archive is not there anymore, or because the
59 // archive doesn't contain the requested member), this will still
60 // provide a sensible error message.
61 auto ErrOrFile = MemoryBuffer::getFileOrSTDIN(Filename);
62 if (auto Err = ErrOrFile.getError())
63 return Err;
64
Frederic Riss93884062015-07-24 06:40:59 +000065 changeBackingMemoryBuffer(std::move(*ErrOrFile));
Frederic Riss43988502015-01-05 21:29:28 +000066 if (Verbose)
67 outs() << "\tloaded file.\n";
Frederic Riss43988502015-01-05 21:29:28 +000068 return CurrentMemoryBuffer->getMemBufferRef();
69}
70
71ErrorOr<MemoryBufferRef>
Frederic Riss9ccfddc2015-07-22 23:24:00 +000072BinaryHolder::GetArchiveMemberBuffer(StringRef Filename,
73 sys::TimeValue Timestamp) {
Frederic Riss43988502015-01-05 21:29:28 +000074 if (!CurrentArchive)
75 return make_error_code(errc::no_such_file_or_directory);
76
77 StringRef CurArchiveName = CurrentArchive->getFileName();
78 if (!Filename.startswith(Twine(CurArchiveName, "(").str()))
79 return make_error_code(errc::no_such_file_or_directory);
80
81 // Remove the archive name and the parens around the archive member name.
82 Filename = Filename.substr(CurArchiveName.size() + 1).drop_back();
83
84 for (const auto &Child : CurrentArchive->children()) {
85 if (auto NameOrErr = Child.getName())
86 if (*NameOrErr == Filename) {
Frederic Riss9ccfddc2015-07-22 23:24:00 +000087 if (Timestamp != sys::TimeValue::PosixZeroTime() &&
88 Timestamp != Child.getLastModified()) {
89 if (Verbose)
90 outs() << "\tmember had timestamp mismatch.\n";
91 continue;
92 }
Frederic Riss43988502015-01-05 21:29:28 +000093 if (Verbose)
94 outs() << "\tfound member in current archive.\n";
95 return Child.getMemoryBufferRef();
96 }
97 }
98
99 return make_error_code(errc::no_such_file_or_directory);
100}
101
102ErrorOr<MemoryBufferRef>
Frederic Riss9ccfddc2015-07-22 23:24:00 +0000103BinaryHolder::MapArchiveAndGetMemberBuffer(StringRef Filename,
104 sys::TimeValue Timestamp) {
Frederic Riss43988502015-01-05 21:29:28 +0000105 StringRef ArchiveFilename = Filename.substr(0, Filename.find('('));
106
107 auto ErrOrBuff = MemoryBuffer::getFileOrSTDIN(ArchiveFilename);
108 if (auto Err = ErrOrBuff.getError())
109 return Err;
110
111 if (Verbose)
112 outs() << "\topened new archive '" << ArchiveFilename << "'\n";
Frederic Riss93884062015-07-24 06:40:59 +0000113
114 changeBackingMemoryBuffer(std::move(*ErrOrBuff));
115 auto ErrOrArchive =
116 object::Archive::create(CurrentMemoryBuffer->getMemBufferRef());
Frederic Riss43988502015-01-05 21:29:28 +0000117 if (auto Err = ErrOrArchive.getError())
118 return Err;
119
120 CurrentArchive = std::move(*ErrOrArchive);
Frederic Riss43988502015-01-05 21:29:28 +0000121
Frederic Riss9ccfddc2015-07-22 23:24:00 +0000122 return GetArchiveMemberBuffer(Filename, Timestamp);
Frederic Riss43988502015-01-05 21:29:28 +0000123}
124
125ErrorOr<const object::ObjectFile &>
Frederic Riss9ccfddc2015-07-22 23:24:00 +0000126BinaryHolder::GetObjectFile(StringRef Filename, sys::TimeValue Timestamp) {
127 auto ErrOrMemBufferRef = GetMemoryBufferForFile(Filename, Timestamp);
Frederic Riss43988502015-01-05 21:29:28 +0000128 if (auto Err = ErrOrMemBufferRef.getError())
129 return Err;
130
131 auto ErrOrObjectFile =
132 object::ObjectFile::createObjectFile(*ErrOrMemBufferRef);
133 if (auto Err = ErrOrObjectFile.getError())
134 return Err;
135
136 CurrentObjectFile = std::move(*ErrOrObjectFile);
137 return *CurrentObjectFile;
138}
139}
140}