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 "Chunks.h"
11#include "Driver.h"
12#include "InputFiles.h"
13#include "TypeMerger.h"
14#include "lld/Common/ErrorHandler.h"
15#include "lld/Common/Memory.h"
16#include "llvm/DebugInfo/CodeView/TypeRecord.h"
17#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
18#include "llvm/DebugInfo/CodeView/TypeStreamMerger.h"
19#include "llvm/DebugInfo/PDB/GenericError.h"
20#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
21#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
22#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
23#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
24#include "llvm/Support/Path.h"
25
26using namespace llvm;
27using namespace llvm::codeview;
28using namespace lld;
29using namespace lld::coff;
30
31namespace {
32// The TypeServerSource class represents a PDB type server, a file referenced by
33// OBJ files compiled with MSVC /Zi. A single PDB can be shared by several OBJ
34// files, therefore there must be only once instance per OBJ lot. The file path
35// is discovered from the dependent OBJ's debug type stream. The
36// TypeServerSource object is then queued and loaded by the COFF Driver. The
37// debug type stream for such PDB files will be merged first in the final PDB,
38// before any dependent OBJ.
39class TypeServerSource : public TpiSource {
40public:
41  explicit TypeServerSource(PDBInputFile *f)
42      : TpiSource(PDB, nullptr), pdbInputFile(f) {
43    if (f->loadErr && *f->loadErr)
44      return;
45    pdb::PDBFile &file = f->session->getPDBFile();
46    auto expectedInfo = file.getPDBInfoStream();
47    if (!expectedInfo)
48      return;
49    auto it = mappings.emplace(expectedInfo->getGuid(), this);
50    assert(it.second);
51    (void)it;
52    tsIndexMap.isTypeServerMap = true;
53  }
54
55  Expected<const CVIndexMap *> mergeDebugT(TypeMerger *m,
56                                           CVIndexMap *indexMap) override;
57  bool isDependency() const override { return true; }
58
59  PDBInputFile *pdbInputFile = nullptr;
60
61  CVIndexMap tsIndexMap;
62
63  static std::map<codeview::GUID, TypeServerSource *> mappings;
64};
65
66// This class represents the debug type stream of an OBJ file that depends on a
67// PDB type server (see TypeServerSource).
68class UseTypeServerSource : public TpiSource {
69public:
70  UseTypeServerSource(ObjFile *f, TypeServer2Record ts)
71      : TpiSource(UsingPDB, f), typeServerDependency(ts) {}
72
73  Expected<const CVIndexMap *> mergeDebugT(TypeMerger *m,
74                                           CVIndexMap *indexMap) override;
75
76  // Information about the PDB type server dependency, that needs to be loaded
77  // in before merging this OBJ.
78  TypeServer2Record typeServerDependency;
79};
80
81// This class represents the debug type stream of a Microsoft precompiled
82// headers OBJ (PCH OBJ). This OBJ kind needs to be merged first in the output
83// PDB, before any other OBJs that depend on this. Note that only MSVC generate
84// such files, clang does not.
85class PrecompSource : public TpiSource {
86public:
87  PrecompSource(ObjFile *f) : TpiSource(PCH, f) {
88    if (!f->pchSignature || !*f->pchSignature)
89      fatal(toString(f) +
90            " claims to be a PCH object, but does not have a valid signature");
91    auto it = mappings.emplace(*f->pchSignature, this);
92    if (!it.second)
93      fatal("a PCH object with the same signature has already been provided (" +
94            toString(it.first->second->file) + " and " + toString(file) + ")");
95    precompIndexMap.isPrecompiledTypeMap = true;
96  }
97
98  Expected<const CVIndexMap *> mergeDebugT(TypeMerger *m,
99                                           CVIndexMap *indexMap) override;
100  bool isDependency() const override { return true; }
101
102  CVIndexMap precompIndexMap;
103
104  static std::map<uint32_t, PrecompSource *> mappings;
105};
106
107// This class represents the debug type stream of an OBJ file that depends on a
108// Microsoft precompiled headers OBJ (see PrecompSource).
109class UsePrecompSource : public TpiSource {
110public:
111  UsePrecompSource(ObjFile *f, PrecompRecord precomp)
112      : TpiSource(UsingPCH, f), precompDependency(precomp) {}
113
114  Expected<const CVIndexMap *> mergeDebugT(TypeMerger *m,
115                                           CVIndexMap *indexMap) override;
116
117  // Information about the Precomp OBJ dependency, that needs to be loaded in
118  // before merging this OBJ.
119  PrecompRecord precompDependency;
120};
121} // namespace
122
123static std::vector<TpiSource *> gc;
124
125TpiSource::TpiSource(TpiKind k, ObjFile *f) : kind(k), file(f) {
126  gc.push_back(this);
127}
128
129// Vtable key method.
130TpiSource::~TpiSource() = default;
131
132TpiSource *lld::coff::makeTpiSource(ObjFile *file) {
133  return make<TpiSource>(TpiSource::Regular, file);
134}
135
136TpiSource *lld::coff::makeTypeServerSource(PDBInputFile *pdbInputFile) {
137  return make<TypeServerSource>(pdbInputFile);
138}
139
140TpiSource *lld::coff::makeUseTypeServerSource(ObjFile *file,
141                                              TypeServer2Record ts) {
142  return make<UseTypeServerSource>(file, ts);
143}
144
145TpiSource *lld::coff::makePrecompSource(ObjFile *file) {
146  return make<PrecompSource>(file);
147}
148
149TpiSource *lld::coff::makeUsePrecompSource(ObjFile *file,
150                                           PrecompRecord precomp) {
151  return make<UsePrecompSource>(file, precomp);
152}
153
154void TpiSource::forEachSource(llvm::function_ref<void(TpiSource *)> fn) {
155  for_each(gc, fn);
156}
157
158std::map<codeview::GUID, TypeServerSource *> TypeServerSource::mappings;
159
160std::map<uint32_t, PrecompSource *> PrecompSource::mappings;
161
162// A COFF .debug$H section is currently a clang extension.  This function checks
163// if a .debug$H section is in a format that we expect / understand, so that we
164// can ignore any sections which are coincidentally also named .debug$H but do
165// not contain a format we recognize.
166static bool canUseDebugH(ArrayRef<uint8_t> debugH) {
167  if (debugH.size() < sizeof(object::debug_h_header))
168    return false;
169  auto *header =
170      reinterpret_cast<const object::debug_h_header *>(debugH.data());
171  debugH = debugH.drop_front(sizeof(object::debug_h_header));
172  return header->Magic == COFF::DEBUG_HASHES_SECTION_MAGIC &&
173         header->Version == 0 &&
174         header->HashAlgorithm == uint16_t(GlobalTypeHashAlg::SHA1_8) &&
175         (debugH.size() % 8 == 0);
176}
177
178static Optional<ArrayRef<uint8_t>> getDebugH(ObjFile *file) {
179  SectionChunk *sec =
180      SectionChunk::findByName(file->getDebugChunks(), ".debug$H");
181  if (!sec)
182    return llvm::None;
183  ArrayRef<uint8_t> contents = sec->getContents();
184  if (!canUseDebugH(contents))
185    return None;
186  return contents;
187}
188
189static ArrayRef<GloballyHashedType>
190getHashesFromDebugH(ArrayRef<uint8_t> debugH) {
191  assert(canUseDebugH(debugH));
192
193  debugH = debugH.drop_front(sizeof(object::debug_h_header));
194  uint32_t count = debugH.size() / sizeof(GloballyHashedType);
195  return {reinterpret_cast<const GloballyHashedType *>(debugH.data()), count};
196}
197
198// Merge .debug$T for a generic object file.
199Expected<const CVIndexMap *> TpiSource::mergeDebugT(TypeMerger *m,
200                                                    CVIndexMap *indexMap) {
201  CVTypeArray types;
202  BinaryStreamReader reader(file->debugTypes, support::little);
203  cantFail(reader.readArray(types, reader.getLength()));
204
205  // When dealing with PCH.OBJ, some indices were already merged.
206  unsigned nbHeadIndices = indexMap->tpiMap.size();
207
208  if (config->debugGHashes) {
209    ArrayRef<GloballyHashedType> hashes;
210    std::vector<GloballyHashedType> ownedHashes;
211    if (Optional<ArrayRef<uint8_t>> debugH = getDebugH(file))
212      hashes = getHashesFromDebugH(*debugH);
213    else {
214      ownedHashes = GloballyHashedType::hashTypes(types);
215      hashes = ownedHashes;
216    }
217
218    if (auto err = mergeTypeAndIdRecords(m->globalIDTable, m->globalTypeTable,
219                                         indexMap->tpiMap, types, hashes,
220                                         file->pchSignature))
221      fatal("codeview::mergeTypeAndIdRecords failed: " +
222            toString(std::move(err)));
223  } else {
224    if (auto err =
225            mergeTypeAndIdRecords(m->idTable, m->typeTable, indexMap->tpiMap,
226                                  types, file->pchSignature))
227      fatal("codeview::mergeTypeAndIdRecords failed: " +
228            toString(std::move(err)));
229  }
230
231  if (config->showSummary) {
232    // Count how many times we saw each type record in our input. This
233    // calculation requires a second pass over the type records to classify each
234    // record as a type or index. This is slow, but this code executes when
235    // collecting statistics.
236    m->tpiCounts.resize(m->getTypeTable().size());
237    m->ipiCounts.resize(m->getIDTable().size());
238    uint32_t srcIdx = nbHeadIndices;
239    for (CVType &ty : types) {
240      TypeIndex dstIdx = indexMap->tpiMap[srcIdx++];
241      // Type merging may fail, so a complex source type may become the simple
242      // NotTranslated type, which cannot be used as an array index.
243      if (dstIdx.isSimple())
244        continue;
245      SmallVectorImpl<uint32_t> &counts =
246          isIdRecord(ty.kind()) ? m->ipiCounts : m->tpiCounts;
247      ++counts[dstIdx.toArrayIndex()];
248    }
249  }
250
251  return indexMap;
252}
253
254// Merge types from a type server PDB.
255Expected<const CVIndexMap *> TypeServerSource::mergeDebugT(TypeMerger *m,
256                                                           CVIndexMap *) {
257  pdb::PDBFile &pdbFile = pdbInputFile->session->getPDBFile();
258  Expected<pdb::TpiStream &> expectedTpi = pdbFile.getPDBTpiStream();
259  if (auto e = expectedTpi.takeError())
260    fatal("Type server does not have TPI stream: " + toString(std::move(e)));
261  pdb::TpiStream *maybeIpi = nullptr;
262  if (pdbFile.hasPDBIpiStream()) {
263    Expected<pdb::TpiStream &> expectedIpi = pdbFile.getPDBIpiStream();
264    if (auto e = expectedIpi.takeError())
265      fatal("Error getting type server IPI stream: " + toString(std::move(e)));
266    maybeIpi = &*expectedIpi;
267  }
268
269  if (config->debugGHashes) {
270    // PDBs do not actually store global hashes, so when merging a type server
271    // PDB we have to synthesize global hashes.  To do this, we first synthesize
272    // global hashes for the TPI stream, since it is independent, then we
273    // synthesize hashes for the IPI stream, using the hashes for the TPI stream
274    // as inputs.
275    auto tpiHashes = GloballyHashedType::hashTypes(expectedTpi->typeArray());
276    Optional<uint32_t> endPrecomp;
277    // Merge TPI first, because the IPI stream will reference type indices.
278    if (auto err =
279            mergeTypeRecords(m->globalTypeTable, tsIndexMap.tpiMap,
280                             expectedTpi->typeArray(), tpiHashes, endPrecomp))
281      fatal("codeview::mergeTypeRecords failed: " + toString(std::move(err)));
282
283    // Merge IPI.
284    if (maybeIpi) {
285      auto ipiHashes =
286          GloballyHashedType::hashIds(maybeIpi->typeArray(), tpiHashes);
287      if (auto err = mergeIdRecords(m->globalIDTable, tsIndexMap.tpiMap,
288                                    tsIndexMap.ipiMap, maybeIpi->typeArray(),
289                                    ipiHashes))
290        fatal("codeview::mergeIdRecords failed: " + toString(std::move(err)));
291    }
292  } else {
293    // Merge TPI first, because the IPI stream will reference type indices.
294    if (auto err = mergeTypeRecords(m->typeTable, tsIndexMap.tpiMap,
295                                    expectedTpi->typeArray()))
296      fatal("codeview::mergeTypeRecords failed: " + toString(std::move(err)));
297
298    // Merge IPI.
299    if (maybeIpi) {
300      if (auto err = mergeIdRecords(m->idTable, tsIndexMap.tpiMap,
301                                    tsIndexMap.ipiMap, maybeIpi->typeArray()))
302        fatal("codeview::mergeIdRecords failed: " + toString(std::move(err)));
303    }
304  }
305
306  if (config->showSummary) {
307    // Count how many times we saw each type record in our input. If a
308    // destination type index is present in the source to destination type index
309    // map, that means we saw it once in the input. Add it to our histogram.
310    m->tpiCounts.resize(m->getTypeTable().size());
311    m->ipiCounts.resize(m->getIDTable().size());
312    for (TypeIndex ti : tsIndexMap.tpiMap)
313      if (!ti.isSimple())
314        ++m->tpiCounts[ti.toArrayIndex()];
315    for (TypeIndex ti : tsIndexMap.ipiMap)
316      if (!ti.isSimple())
317        ++m->ipiCounts[ti.toArrayIndex()];
318  }
319
320  return &tsIndexMap;
321}
322
323Expected<const CVIndexMap *>
324UseTypeServerSource::mergeDebugT(TypeMerger *m, CVIndexMap *indexMap) {
325  const codeview::GUID &tsId = typeServerDependency.getGuid();
326  StringRef tsPath = typeServerDependency.getName();
327
328  TypeServerSource *tsSrc;
329  auto it = TypeServerSource::mappings.find(tsId);
330  if (it != TypeServerSource::mappings.end()) {
331    tsSrc = it->second;
332  } else {
333    // The file failed to load, lookup by name
334    PDBInputFile *pdb = PDBInputFile::findFromRecordPath(tsPath, file);
335    if (!pdb)
336      return createFileError(tsPath, errorCodeToError(std::error_code(
337                                         ENOENT, std::generic_category())));
338    // If an error occurred during loading, throw it now
339    if (pdb->loadErr && *pdb->loadErr)
340      return createFileError(tsPath, std::move(*pdb->loadErr));
341
342    tsSrc = (TypeServerSource *)pdb->debugTypesObj;
343  }
344
345  pdb::PDBFile &pdbSession = tsSrc->pdbInputFile->session->getPDBFile();
346  auto expectedInfo = pdbSession.getPDBInfoStream();
347  if (!expectedInfo)
348    return &tsSrc->tsIndexMap;
349
350  // Just because a file with a matching name was found and it was an actual
351  // PDB file doesn't mean it matches.  For it to match the InfoStream's GUID
352  // must match the GUID specified in the TypeServer2 record.
353  if (expectedInfo->getGuid() != typeServerDependency.getGuid())
354    return createFileError(
355        tsPath,
356        make_error<pdb::PDBError>(pdb::pdb_error_code::signature_out_of_date));
357
358  return &tsSrc->tsIndexMap;
359}
360
361static bool equalsPath(StringRef path1, StringRef path2) {
362#if defined(_WIN32)
363  return path1.equals_lower(path2);
364#else
365  return path1.equals(path2);
366#endif
367}
368
369// Find by name an OBJ provided on the command line
370static PrecompSource *findObjByName(StringRef fileNameOnly) {
371  SmallString<128> currentPath;
372  for (auto kv : PrecompSource::mappings) {
373    StringRef currentFileName = sys::path::filename(kv.second->file->getName(),
374                                                    sys::path::Style::windows);
375
376    // Compare based solely on the file name (link.exe behavior)
377    if (equalsPath(currentFileName, fileNameOnly))
378      return kv.second;
379  }
380  return nullptr;
381}
382
383Expected<const CVIndexMap *> findPrecompMap(ObjFile *file, PrecompRecord &pr) {
384  // Cross-compile warning: given that Clang doesn't generate LF_PRECOMP
385  // records, we assume the OBJ comes from a Windows build of cl.exe. Thusly,
386  // the paths embedded in the OBJs are in the Windows format.
387  SmallString<128> prFileName =
388      sys::path::filename(pr.getPrecompFilePath(), sys::path::Style::windows);
389
390  PrecompSource *precomp;
391  auto it = PrecompSource::mappings.find(pr.getSignature());
392  if (it != PrecompSource::mappings.end()) {
393    precomp = it->second;
394  } else {
395    // Lookup by name
396    precomp = findObjByName(prFileName);
397  }
398
399  if (!precomp)
400    return createFileError(
401        prFileName,
402        make_error<pdb::PDBError>(pdb::pdb_error_code::no_matching_pch));
403
404  if (pr.getSignature() != file->pchSignature)
405    return createFileError(
406        toString(file),
407        make_error<pdb::PDBError>(pdb::pdb_error_code::no_matching_pch));
408
409  if (pr.getSignature() != *precomp->file->pchSignature)
410    return createFileError(
411        toString(precomp->file),
412        make_error<pdb::PDBError>(pdb::pdb_error_code::no_matching_pch));
413
414  return &precomp->precompIndexMap;
415}
416
417/// Merges a precompiled headers TPI map into the current TPI map. The
418/// precompiled headers object will also be loaded and remapped in the
419/// process.
420static Expected<const CVIndexMap *>
421mergeInPrecompHeaderObj(ObjFile *file, CVIndexMap *indexMap,
422                        PrecompRecord &precomp) {
423  auto e = findPrecompMap(file, precomp);
424  if (!e)
425    return e.takeError();
426
427  const CVIndexMap *precompIndexMap = *e;
428  assert(precompIndexMap->isPrecompiledTypeMap);
429
430  if (precompIndexMap->tpiMap.empty())
431    return precompIndexMap;
432
433  assert(precomp.getStartTypeIndex() == TypeIndex::FirstNonSimpleIndex);
434  assert(precomp.getTypesCount() <= precompIndexMap->tpiMap.size());
435  // Use the previously remapped index map from the precompiled headers.
436  indexMap->tpiMap.append(precompIndexMap->tpiMap.begin(),
437                          precompIndexMap->tpiMap.begin() +
438                              precomp.getTypesCount());
439  return indexMap;
440}
441
442Expected<const CVIndexMap *>
443UsePrecompSource::mergeDebugT(TypeMerger *m, CVIndexMap *indexMap) {
444  // This object was compiled with /Yu, so process the corresponding
445  // precompiled headers object (/Yc) first. Some type indices in the current
446  // object are referencing data in the precompiled headers object, so we need
447  // both to be loaded.
448  auto e = mergeInPrecompHeaderObj(file, indexMap, precompDependency);
449  if (!e)
450    return e.takeError();
451
452  // Drop LF_PRECOMP record from the input stream, as it has been replaced
453  // with the precompiled headers Type stream in the mergeInPrecompHeaderObj()
454  // call above. Note that we can't just call Types.drop_front(), as we
455  // explicitly want to rebase the stream.
456  CVTypeArray types;
457  BinaryStreamReader reader(file->debugTypes, support::little);
458  cantFail(reader.readArray(types, reader.getLength()));
459  auto firstType = types.begin();
460  file->debugTypes = file->debugTypes.drop_front(firstType->RecordData.size());
461
462  return TpiSource::mergeDebugT(m, indexMap);
463}
464
465Expected<const CVIndexMap *> PrecompSource::mergeDebugT(TypeMerger *m,
466                                                        CVIndexMap *) {
467  // Note that we're not using the provided CVIndexMap. Instead, we use our
468  // local one. Precompiled headers objects need to save the index map for
469  // further reference by other objects which use the precompiled headers.
470  return TpiSource::mergeDebugT(m, &precompIndexMap);
471}
472
473uint32_t TpiSource::countTypeServerPDBs() {
474  return TypeServerSource::mappings.size();
475}
476
477uint32_t TpiSource::countPrecompObjs() {
478  return PrecompSource::mappings.size();
479}
480
481void TpiSource::clear() {
482  gc.clear();
483  TypeServerSource::mappings.clear();
484  PrecompSource::mappings.clear();
485}
486