Coverage Report

Created: 2019-07-24 05:18

/Users/buildslave/jenkins/workspace/clang-stage2-coverage-R/llvm/tools/lld/COFF/DebugTypes.cpp
Line
Count
Source (jump to first uncovered line)
1
//===- DebugTypes.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 "DebugTypes.h"
10
#include "Driver.h"
11
#include "InputFiles.h"
12
#include "lld/Common/ErrorHandler.h"
13
#include "llvm/DebugInfo/CodeView/TypeRecord.h"
14
#include "llvm/DebugInfo/PDB/GenericError.h"
15
#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
16
#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
17
#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
18
#include "llvm/Support/Path.h"
19
20
using namespace lld;
21
using namespace lld::coff;
22
using namespace llvm;
23
using namespace llvm::codeview;
24
25
namespace {
26
// The TypeServerSource class represents a PDB type server, a file referenced by
27
// OBJ files compiled with MSVC /Zi. A single PDB can be shared by several OBJ
28
// files, therefore there must be only once instance per OBJ lot. The file path
29
// is discovered from the dependent OBJ's debug type stream. The
30
// TypeServerSource object is then queued and loaded by the COFF Driver. The
31
// debug type stream for such PDB files will be merged first in the final PDB,
32
// before any dependent OBJ.
33
class TypeServerSource : public TpiSource {
34
public:
35
  explicit TypeServerSource(MemoryBufferRef m, llvm::pdb::NativeSession *s)
36
5
      : TpiSource(PDB, nullptr), session(s), mb(m) {}
37
38
  // Queue a PDB type server for loading in the COFF Driver
39
  static void enqueue(const ObjFile *dependentFile,
40
                      const TypeServer2Record &ts);
41
42
  // Create an instance
43
  static Expected<TypeServerSource *> getInstance(MemoryBufferRef m);
44
45
  // Fetch the PDB instance loaded for a corresponding dependent OBJ.
46
  static Expected<TypeServerSource *>
47
  findFromFile(const ObjFile *dependentFile);
48
49
  static std::map<std::string, std::pair<std::string, TypeServerSource *>>
50
      instances;
51
52
  // The interface to the PDB (if it was opened successfully)
53
  std::unique_ptr<llvm::pdb::NativeSession> session;
54
55
private:
56
  MemoryBufferRef mb;
57
};
58
59
// This class represents the debug type stream of an OBJ file that depends on a
60
// PDB type server (see TypeServerSource).
61
class UseTypeServerSource : public TpiSource {
62
public:
63
  UseTypeServerSource(const ObjFile *f, const TypeServer2Record *ts)
64
17
      : TpiSource(UsingPDB, f), typeServerDependency(*ts) {}
65
66
  // Information about the PDB type server dependency, that needs to be loaded
67
  // in before merging this OBJ.
68
  TypeServer2Record typeServerDependency;
69
};
70
71
// This class represents the debug type stream of a Microsoft precompiled
72
// headers OBJ (PCH OBJ). This OBJ kind needs to be merged first in the output
73
// PDB, before any other OBJs that depend on this. Note that only MSVC generate
74
// such files, clang does not.
75
class PrecompSource : public TpiSource {
76
public:
77
4
  PrecompSource(const ObjFile *f) : TpiSource(PCH, f) {}
78
};
79
80
// This class represents the debug type stream of an OBJ file that depends on a
81
// Microsoft precompiled headers OBJ (see PrecompSource).
82
class UsePrecompSource : public TpiSource {
83
public:
84
  UsePrecompSource(const ObjFile *f, const PrecompRecord *precomp)
85
8
      : TpiSource(UsingPCH, f), precompDependency(*precomp) {}
86
87
  // Information about the Precomp OBJ dependency, that needs to be loaded in
88
  // before merging this OBJ.
89
  PrecompRecord precompDependency;
90
};
91
} // namespace
92
93
static std::vector<std::unique_ptr<TpiSource>> GC;
94
95
93
TpiSource::TpiSource(TpiKind k, const ObjFile *f) : kind(k), file(f) {
96
93
  GC.push_back(std::unique_ptr<TpiSource>(this));
97
93
}
98
99
59
TpiSource *lld::coff::makeTpiSource(const ObjFile *f) {
100
59
  return new TpiSource(TpiSource::Regular, f);
101
59
}
102
103
TpiSource *lld::coff::makeUseTypeServerSource(const ObjFile *f,
104
17
                                              const TypeServer2Record *ts) {
105
17
  TypeServerSource::enqueue(f, *ts);
106
17
  return new UseTypeServerSource(f, ts);
107
17
}
108
109
4
TpiSource *lld::coff::makePrecompSource(const ObjFile *f) {
110
4
  return new PrecompSource(f);
111
4
}
112
113
TpiSource *lld::coff::makeUsePrecompSource(const ObjFile *f,
114
8
                                           const PrecompRecord *precomp) {
115
8
  return new UsePrecompSource(f, precomp);
116
8
}
117
118
namespace lld {
119
namespace coff {
120
template <>
121
16
const PrecompRecord &retrieveDependencyInfo(const TpiSource *source) {
122
16
  assert(source->kind == TpiSource::UsingPCH);
123
16
  return ((const UsePrecompSource *)source)->precompDependency;
124
16
}
125
126
template <>
127
17
const TypeServer2Record &retrieveDependencyInfo(const TpiSource *source) {
128
17
  assert(source->kind == TpiSource::UsingPDB);
129
17
  return ((const UseTypeServerSource *)source)->typeServerDependency;
130
17
}
131
} // namespace coff
132
} // namespace lld
133
134
std::map<std::string, std::pair<std::string, TypeServerSource *>>
135
    TypeServerSource::instances;
136
137
// Make a PDB path assuming the PDB is in the same folder as the OBJ
138
28
static std::string getPdbBaseName(const ObjFile *file, StringRef tSPath) {
139
28
  StringRef localPath =
140
28
      !file->parentName.empty() ? 
file->parentName0
: file->getName();
141
28
  SmallString<128> path = sys::path::parent_path(localPath);
142
28
143
28
  // Currently, type server PDBs are only created by MSVC cl, which only runs
144
28
  // on Windows, so we can assume type server paths are Windows style.
145
28
  sys::path::append(path, sys::path::filename(tSPath, sys::path::Style::windows));
146
28
  return path.str();
147
28
}
148
149
// The casing of the PDB path stamped in the OBJ can differ from the actual path
150
// on disk. With this, we ensure to always use lowercase as a key for the
151
// PDBInputFile::Instances map, at least on Windows.
152
20
static std::string normalizePdbPath(StringRef path) {
153
#if defined(_WIN32)
154
  return path.lower();
155
#else // LINUX
156
  return path;
157
20
#endif
158
20
}
159
160
// If existing, return the actual PDB path on disk.
161
static Optional<std::string> findPdbPath(StringRef pdbPath,
162
34
                                         const ObjFile *dependentFile) {
163
34
  // Ensure the file exists before anything else. In some cases, if the path
164
34
  // points to a removable device, Driver::enqueuePath() would fail with an
165
34
  // error (EAGAIN, "resource unavailable try again") which we want to skip
166
34
  // silently.
167
34
  if (llvm::sys::fs::exists(pdbPath))
168
6
    return normalizePdbPath(pdbPath);
169
28
  std::string ret = getPdbBaseName(dependentFile, pdbPath);
170
28
  if (llvm::sys::fs::exists(ret))
171
8
    return normalizePdbPath(ret);
172
20
  return None;
173
20
}
174
175
// Fetch the PDB instance that was already loaded by the COFF Driver.
176
Expected<TypeServerSource *>
177
17
TypeServerSource::findFromFile(const ObjFile *dependentFile) {
178
17
  const TypeServer2Record &ts =
179
17
      retrieveDependencyInfo<TypeServer2Record>(dependentFile->debugTypesObj);
180
17
181
17
  Optional<std::string> p = findPdbPath(ts.Name, dependentFile);
182
17
  if (!p)
183
10
    return createFileError(ts.Name, errorCodeToError(std::error_code(
184
10
                                        ENOENT, std::generic_category())));
185
7
186
7
  auto it = TypeServerSource::instances.find(*p);
187
7
  // The PDB file exists on disk, at this point we expect it to have been
188
7
  // inserted in the map by TypeServerSource::loadPDB()
189
7
  assert(it != TypeServerSource::instances.end());
190
7
191
7
  std::pair<std::string, TypeServerSource *> &pdb = it->second;
192
7
193
7
  if (!pdb.second)
194
1
    return createFileError(
195
1
        *p, createStringError(inconvertibleErrorCode(), pdb.first.c_str()));
196
6
197
6
  pdb::PDBFile &pdbFile = (pdb.second)->session->getPDBFile();
198
6
  pdb::InfoStream &info = cantFail(pdbFile.getPDBInfoStream());
199
6
200
6
  // Just because a file with a matching name was found doesn't mean it can be
201
6
  // used. The GUID must match between the PDB header and the OBJ
202
6
  // TypeServer2 record. The 'Age' is used by MSVC incremental compilation.
203
6
  if (info.getGuid() != ts.getGuid())
204
1
    return createFileError(
205
1
        ts.Name,
206
1
        make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date));
207
5
208
5
  return pdb.second;
209
5
}
210
211
// FIXME: Temporary interface until PDBLinker::maybeMergeTypeServerPDB() is
212
// moved here.
213
Expected<llvm::pdb::NativeSession *>
214
17
lld::coff::findTypeServerSource(const ObjFile *f) {
215
17
  Expected<TypeServerSource *> ts = TypeServerSource::findFromFile(f);
216
17
  if (!ts)
217
12
    return ts.takeError();
218
5
  return ts.get()->session.get();
219
5
}
220
221
// Queue a PDB type server for loading in the COFF Driver
222
void TypeServerSource::enqueue(const ObjFile *dependentFile,
223
17
                               const TypeServer2Record &ts) {
224
17
  // Start by finding where the PDB is located (either the record path or next
225
17
  // to the OBJ file)
226
17
  Optional<std::string> p = findPdbPath(ts.Name, dependentFile);
227
17
  if (!p)
228
10
    return;
229
7
  auto it = TypeServerSource::instances.emplace(
230
7
      *p, std::pair<std::string, TypeServerSource *>{});
231
7
  if (!it.second)
232
1
    return; // another OBJ already scheduled this PDB for load
233
6
234
6
  driver->enqueuePath(*p, false);
235
6
}
236
237
// Create an instance of TypeServerSource or an error string if the PDB couldn't
238
// be loaded. The error message will be displayed later, when the referring OBJ
239
// will be merged in. NOTE - a PDB load failure is not a link error: some
240
// debug info will simply be missing from the final PDB - that is the default
241
// accepted behavior.
242
6
void lld::coff::loadTypeServerSource(llvm::MemoryBufferRef m) {
243
6
  std::string path = normalizePdbPath(m.getBufferIdentifier());
244
6
245
6
  Expected<TypeServerSource *> ts = TypeServerSource::getInstance(m);
246
6
  if (!ts)
247
1
    TypeServerSource::instances[path] = {toString(ts.takeError()), nullptr};
248
5
  else
249
5
    TypeServerSource::instances[path] = {{}, *ts};
250
6
}
251
252
6
Expected<TypeServerSource *> TypeServerSource::getInstance(MemoryBufferRef m) {
253
6
  std::unique_ptr<llvm::pdb::IPDBSession> iSession;
254
6
  Error err = pdb::NativeSession::createFromPdb(
255
6
      MemoryBuffer::getMemBuffer(m, false), iSession);
256
6
  if (err)
257
1
    return std::move(err);
258
5
259
5
  std::unique_ptr<llvm::pdb::NativeSession> session(
260
5
      static_cast<pdb::NativeSession *>(iSession.release()));
261
5
262
5
  pdb::PDBFile &pdbFile = session->getPDBFile();
263
5
  Expected<pdb::InfoStream &> info = pdbFile.getPDBInfoStream();
264
5
  // All PDB Files should have an Info stream.
265
5
  if (!info)
266
0
    return info.takeError();
267
5
  return new TypeServerSource(m, session.release());
268
5
}