Coverage Report

Created: 2019-05-19 14:56

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/lib/ReaderWriter/FileArchive.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- lib/ReaderWriter/FileArchive.cpp -----------------------------------===//
2
//
3
// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions.
4
// See https://llvm.org/LICENSE.txt for license information.
5
// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception
6
//
7
//===----------------------------------------------------------------------===//
8
9
#include "lld/Common/LLVM.h"
10
#include "lld/Core/ArchiveLibraryFile.h"
11
#include "lld/Core/File.h"
12
#include "lld/Core/Reader.h"
13
#include "llvm/ADT/STLExtras.h"
14
#include "llvm/ADT/StringRef.h"
15
#include "llvm/BinaryFormat/Magic.h"
16
#include "llvm/Object/Archive.h"
17
#include "llvm/Object/Error.h"
18
#include "llvm/Support/Debug.h"
19
#include "llvm/Support/ErrorOr.h"
20
#include "llvm/Support/FileSystem.h"
21
#include "llvm/Support/Format.h"
22
#include "llvm/Support/MemoryBuffer.h"
23
#include "llvm/Support/raw_ostream.h"
24
#include <memory>
25
#include <set>
26
#include <string>
27
#include <system_error>
28
#include <unordered_map>
29
#include <utility>
30
#include <vector>
31
32
using llvm::object::Archive;
33
using llvm::file_magic;
34
using llvm::identify_magic;
35
36
namespace lld {
37
38
namespace {
39
40
/// The FileArchive class represents an Archive Library file
41
class FileArchive : public lld::ArchiveLibraryFile {
42
public:
43
  FileArchive(std::unique_ptr<MemoryBuffer> mb, const Registry &reg,
44
              StringRef path, bool logLoading)
45
      : ArchiveLibraryFile(path), _mb(std::shared_ptr<MemoryBuffer>(mb.release())),
46
10
        _registry(reg), _logLoading(logLoading) {}
47
48
  /// Check if any member of the archive contains an Atom with the
49
  /// specified name and return the File object for that member, or nullptr.
50
11
  File *find(StringRef name) override {
51
11
    auto member = _symbolMemberMap.find(name);
52
11
    if (member == _symbolMemberMap.end())
53
6
      return nullptr;
54
5
    Archive::Child c = member->second;
55
5
56
5
    // Don't return a member already returned
57
5
    Expected<StringRef> buf = c.getBuffer();
58
5
    if (!buf) {
59
0
      // TODO: Actually report errors helpfully.
60
0
      consumeError(buf.takeError());
61
0
      return nullptr;
62
0
    }
63
5
    const char *memberStart = buf->data();
64
5
    if (_membersInstantiated.count(memberStart))
65
0
      return nullptr;
66
5
    _membersInstantiated.insert(memberStart);
67
5
68
5
    std::unique_ptr<File> result;
69
5
    if (instantiateMember(c, result))
70
0
      return nullptr;
71
5
72
5
    File *file = result.get();
73
5
    _filesReturned.push_back(std::move(result));
74
5
75
5
    // Give up the file pointer. It was stored and will be destroyed with destruction of FileArchive
76
5
    return file;
77
5
  }
78
79
  /// parse each member
80
  std::error_code
81
2
  parseAllMembers(std::vector<std::unique_ptr<File>> &result) override {
82
2
    if (std::error_code ec = parse())
83
0
      return ec;
84
2
    llvm::Error err = llvm::Error::success();
85
2
    for (auto mf = _archive->child_begin(err), me = _archive->child_end();
86
4
         mf != me; 
++mf2
) {
87
2
      std::unique_ptr<File> file;
88
2
      if (std::error_code ec = instantiateMember(*mf, file)) {
89
0
        // err is Success (or we wouldn't be in the loop body) but we can't
90
0
        // return without testing or consuming it.
91
0
        consumeError(std::move(err));
92
0
        return ec;
93
0
      }
94
2
      result.push_back(std::move(file));
95
2
    }
96
2
    if (err)
97
0
      return errorToErrorCode(std::move(err));
98
2
    return std::error_code();
99
2
  }
100
101
0
  const AtomRange<DefinedAtom> defined() const override {
102
0
    return _noDefinedAtoms;
103
0
  }
104
105
0
  const AtomRange<UndefinedAtom> undefined() const override {
106
0
    return _noUndefinedAtoms;
107
0
  }
108
109
0
  const AtomRange<SharedLibraryAtom> sharedLibrary() const override {
110
0
    return _noSharedLibraryAtoms;
111
0
  }
112
113
0
  const AtomRange<AbsoluteAtom> absolute() const override {
114
0
    return _noAbsoluteAtoms;
115
0
  }
116
117
8
  void clearAtoms() override {
118
8
    _noDefinedAtoms.clear();
119
8
    _noUndefinedAtoms.clear();
120
8
    _noSharedLibraryAtoms.clear();
121
8
    _noAbsoluteAtoms.clear();
122
8
  }
123
124
protected:
125
10
  std::error_code doParse() override {
126
10
    // Make Archive object which will be owned by FileArchive object.
127
10
    llvm::Error Err = llvm::Error::success();
128
10
    _archive.reset(new Archive(_mb->getMemBufferRef(), Err));
129
10
    if (Err)
130
0
      return errorToErrorCode(std::move(Err));
131
10
    std::error_code ec;
132
10
    if ((ec = buildTableOfContents()))
133
0
      return ec;
134
10
    return std::error_code();
135
10
  }
136
137
private:
138
  std::error_code instantiateMember(Archive::Child member,
139
7
                                    std::unique_ptr<File> &result) const {
140
7
    Expected<llvm::MemoryBufferRef> mbOrErr = member.getMemoryBufferRef();
141
7
    if (!mbOrErr)
142
0
      return errorToErrorCode(mbOrErr.takeError());
143
7
    llvm::MemoryBufferRef mb = mbOrErr.get();
144
7
    std::string memberPath = (_archive->getFileName() + "("
145
7
                           + mb.getBufferIdentifier() + ")").str();
146
7
147
7
    if (_logLoading)
148
0
      llvm::errs() << memberPath << "\n";
149
7
150
7
    std::unique_ptr<MemoryBuffer> memberMB(MemoryBuffer::getMemBuffer(
151
7
        mb.getBuffer(), mb.getBufferIdentifier(), false));
152
7
153
7
    ErrorOr<std::unique_ptr<File>> fileOrErr =
154
7
        _registry.loadFile(std::move(memberMB));
155
7
    if (std::error_code ec = fileOrErr.getError())
156
0
      return ec;
157
7
    result = std::move(fileOrErr.get());
158
7
    if (std::error_code ec = result->parse())
159
0
      return ec;
160
7
    result->setArchivePath(_archive->getFileName());
161
7
162
7
    // The memory buffer is co-owned by the archive file and the children,
163
7
    // so that the bufffer is deallocated when all the members are destructed.
164
7
    result->setSharedMemoryBuffer(_mb);
165
7
    return std::error_code();
166
7
  }
167
168
10
  std::error_code buildTableOfContents() {
169
10
    DEBUG_WITH_TYPE("FileArchive", llvm::dbgs()
170
10
                                       << "Table of contents for archive '"
171
10
                                       << _archive->getFileName() << "':\n");
172
10
    for (const Archive::Symbol &sym : _archive->symbols()) {
173
10
      StringRef name = sym.getName();
174
10
      Expected<Archive::Child> memberOrErr = sym.getMember();
175
10
      if (!memberOrErr)
176
0
        return errorToErrorCode(memberOrErr.takeError());
177
10
      Archive::Child member = memberOrErr.get();
178
10
      DEBUG_WITH_TYPE("FileArchive",
179
10
                      llvm::dbgs()
180
10
                          << llvm::format("0x%08llX ",
181
10
                                          member.getBuffer()->data())
182
10
                          << "'" << name << "'\n");
183
10
      _symbolMemberMap.insert(std::make_pair(name, member));
184
10
    }
185
10
    return std::error_code();
186
10
  }
187
188
  typedef std::unordered_map<StringRef, Archive::Child> MemberMap;
189
  typedef std::set<const char *> InstantiatedSet;
190
191
  std::shared_ptr<MemoryBuffer> _mb;
192
  const Registry &_registry;
193
  std::unique_ptr<Archive> _archive;
194
  MemberMap _symbolMemberMap;
195
  InstantiatedSet _membersInstantiated;
196
  bool _logLoading;
197
  std::vector<std::unique_ptr<MemoryBuffer>> _memberBuffers;
198
  std::vector<std::unique_ptr<File>> _filesReturned;
199
};
200
201
class ArchiveReader : public Reader {
202
public:
203
225
  ArchiveReader(bool logLoading) : _logLoading(logLoading) {}
204
205
294
  bool canParse(file_magic magic, MemoryBufferRef) const override {
206
294
    return magic == file_magic::archive;
207
294
  }
208
209
  ErrorOr<std::unique_ptr<File>> loadFile(std::unique_ptr<MemoryBuffer> mb,
210
10
                                          const Registry &reg) const override {
211
10
    StringRef path = mb->getBufferIdentifier();
212
10
    std::unique_ptr<File> ret =
213
10
        llvm::make_unique<FileArchive>(std::move(mb), reg, path, _logLoading);
214
10
    return std::move(ret);
215
10
  }
216
217
private:
218
  bool _logLoading;
219
};
220
221
} // anonymous namespace
222
223
225
void Registry::addSupportArchives(bool logLoading) {
224
225
  add(std::unique_ptr<Reader>(new ArchiveReader(logLoading)));
225
225
}
226
227
} // namespace lld