1 //===- InputFile.cpp ------------------------------------------ *- C++ --*-===//
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
7 //===----------------------------------------------------------------------===//
11 #include "FormatUtil.h"
12 #include "LinePrinter.h"
14 #include "llvm/BinaryFormat/Magic.h"
15 #include "llvm/DebugInfo/CodeView/CodeView.h"
16 #include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
17 #include "llvm/DebugInfo/CodeView/StringsAndChecksums.h"
18 #include "llvm/DebugInfo/PDB/Native/DbiStream.h"
19 #include "llvm/DebugInfo/PDB/Native/NativeSession.h"
20 #include "llvm/DebugInfo/PDB/Native/PDBFile.h"
21 #include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
22 #include "llvm/DebugInfo/PDB/Native/RawError.h"
23 #include "llvm/DebugInfo/PDB/Native/TpiStream.h"
24 #include "llvm/DebugInfo/PDB/PDB.h"
25 #include "llvm/Object/COFF.h"
26 #include "llvm/Support/FileSystem.h"
27 #include "llvm/Support/FormatVariadic.h"
30 using namespace llvm::codeview
;
31 using namespace llvm::object
;
32 using namespace llvm::pdb
;
34 InputFile::InputFile() {}
35 InputFile::~InputFile() {}
37 static Expected
<ModuleDebugStreamRef
>
38 getModuleDebugStream(PDBFile
&File
, StringRef
&ModuleName
, uint32_t Index
) {
39 ExitOnError
Err("Unexpected error: ");
41 auto &Dbi
= Err(File
.getPDBDbiStream());
42 const auto &Modules
= Dbi
.modules();
43 if (Index
>= Modules
.getModuleCount())
44 return make_error
<RawError
>(raw_error_code::index_out_of_bounds
,
45 "Invalid module index");
47 auto Modi
= Modules
.getModuleDescriptor(Index
);
49 ModuleName
= Modi
.getModuleName();
51 uint16_t ModiStream
= Modi
.getModuleStreamIndex();
52 if (ModiStream
== kInvalidStreamIndex
)
53 return make_error
<RawError
>(raw_error_code::no_stream
,
54 "Module stream not present");
56 auto ModStreamData
= File
.createIndexedStream(ModiStream
);
58 ModuleDebugStreamRef
ModS(Modi
, std::move(ModStreamData
));
59 if (auto EC
= ModS
.reload())
60 return make_error
<RawError
>(raw_error_code::corrupt_file
,
61 "Invalid module stream");
63 return std::move(ModS
);
66 static inline bool isCodeViewDebugSubsection(object::SectionRef Section
,
68 BinaryStreamReader
&Reader
) {
69 if (Expected
<StringRef
> NameOrErr
= Section
.getName()) {
70 if (*NameOrErr
!= Name
)
73 consumeError(NameOrErr
.takeError());
77 Expected
<StringRef
> ContentsOrErr
= Section
.getContents();
79 consumeError(ContentsOrErr
.takeError());
83 Reader
= BinaryStreamReader(*ContentsOrErr
, support::little
);
85 if (Reader
.bytesRemaining() < sizeof(uint32_t))
87 cantFail(Reader
.readInteger(Magic
));
88 if (Magic
!= COFF::DEBUG_SECTION_MAGIC
)
93 static inline bool isDebugSSection(object::SectionRef Section
,
94 DebugSubsectionArray
&Subsections
) {
95 BinaryStreamReader Reader
;
96 if (!isCodeViewDebugSubsection(Section
, ".debug$S", Reader
))
99 cantFail(Reader
.readArray(Subsections
, Reader
.bytesRemaining()));
103 static bool isDebugTSection(SectionRef Section
, CVTypeArray
&Types
) {
104 BinaryStreamReader Reader
;
105 if (!isCodeViewDebugSubsection(Section
, ".debug$T", Reader
) &&
106 !isCodeViewDebugSubsection(Section
, ".debug$P", Reader
))
108 cantFail(Reader
.readArray(Types
, Reader
.bytesRemaining()));
112 static std::string
formatChecksumKind(FileChecksumKind Kind
) {
114 RETURN_CASE(FileChecksumKind
, None
, "None");
115 RETURN_CASE(FileChecksumKind
, MD5
, "MD5");
116 RETURN_CASE(FileChecksumKind
, SHA1
, "SHA-1");
117 RETURN_CASE(FileChecksumKind
, SHA256
, "SHA-256");
119 return formatUnknownEnum(Kind
);
122 template <typename
... Args
>
123 static void formatInternal(LinePrinter
&Printer
, bool Append
, Args
&&... args
) {
125 Printer
.format(std::forward
<Args
>(args
)...);
127 Printer
.formatLine(std::forward
<Args
>(args
)...);
130 SymbolGroup::SymbolGroup(InputFile
*File
, uint32_t GroupIndex
) : File(File
) {
135 initializeForPdb(GroupIndex
);
139 for (const auto &S
: File
->obj().sections()) {
140 DebugSubsectionArray SS
;
141 if (!isDebugSSection(S
, SS
))
144 if (!SC
.hasChecksums() || !SC
.hasStrings())
150 if (SC
.hasChecksums() && SC
.hasStrings())
153 rebuildChecksumMap();
157 StringRef
SymbolGroup::name() const { return Name
; }
159 void SymbolGroup::updateDebugS(const codeview::DebugSubsectionArray
&SS
) {
163 void SymbolGroup::updatePdbModi(uint32_t Modi
) { initializeForPdb(Modi
); }
165 void SymbolGroup::initializeForPdb(uint32_t Modi
) {
166 assert(File
&& File
->isPdb());
168 // PDB always uses the same string table, but each module has its own
169 // checksums. So we only set the strings if they're not already set.
170 if (!SC
.hasStrings()) {
171 auto StringTable
= File
->pdb().getStringTable();
173 SC
.setStrings(StringTable
->getStringTable());
175 consumeError(StringTable
.takeError());
179 auto MDS
= getModuleDebugStream(File
->pdb(), Name
, Modi
);
181 consumeError(MDS
.takeError());
185 DebugStream
= std::make_shared
<ModuleDebugStreamRef
>(std::move(*MDS
));
186 Subsections
= DebugStream
->getSubsectionsArray();
187 SC
.initialize(Subsections
);
188 rebuildChecksumMap();
191 void SymbolGroup::rebuildChecksumMap() {
192 if (!SC
.hasChecksums())
195 for (const auto &Entry
: SC
.checksums()) {
196 auto S
= SC
.strings().getString(Entry
.FileNameOffset
);
199 ChecksumsByFile
[*S
] = Entry
;
203 const ModuleDebugStreamRef
&SymbolGroup::getPdbModuleStream() const {
204 assert(File
&& File
->isPdb() && DebugStream
);
208 Expected
<StringRef
> SymbolGroup::getNameFromStringTable(uint32_t Offset
) const {
209 return SC
.strings().getString(Offset
);
212 void SymbolGroup::formatFromFileName(LinePrinter
&Printer
, StringRef File
,
214 auto FC
= ChecksumsByFile
.find(File
);
215 if (FC
== ChecksumsByFile
.end()) {
216 formatInternal(Printer
, Append
, "- (no checksum) {0}", File
);
220 formatInternal(Printer
, Append
, "- ({0}: {1}) {2}",
221 formatChecksumKind(FC
->getValue().Kind
),
222 toHex(FC
->getValue().Checksum
), File
);
225 void SymbolGroup::formatFromChecksumsOffset(LinePrinter
&Printer
,
228 if (!SC
.hasChecksums()) {
229 formatInternal(Printer
, Append
, "(unknown file name offset {0})", Offset
);
233 auto Iter
= SC
.checksums().getArray().at(Offset
);
234 if (Iter
== SC
.checksums().getArray().end()) {
235 formatInternal(Printer
, Append
, "(unknown file name offset {0})", Offset
);
239 uint32_t FO
= Iter
->FileNameOffset
;
240 auto ExpectedFile
= getNameFromStringTable(FO
);
242 formatInternal(Printer
, Append
, "(unknown file name offset {0})", Offset
);
243 consumeError(ExpectedFile
.takeError());
246 if (Iter
->Kind
== FileChecksumKind::None
) {
247 formatInternal(Printer
, Append
, "{0} (no checksum)", *ExpectedFile
);
249 formatInternal(Printer
, Append
, "{0} ({1}: {2})", *ExpectedFile
,
250 formatChecksumKind(Iter
->Kind
), toHex(Iter
->Checksum
));
254 Expected
<InputFile
> InputFile::open(StringRef Path
, bool AllowUnknownFile
) {
256 if (!llvm::sys::fs::exists(Path
))
257 return make_error
<StringError
>(formatv("File {0} not found", Path
),
258 inconvertibleErrorCode());
261 if (auto EC
= identify_magic(Path
, Magic
))
262 return make_error
<StringError
>(
263 formatv("Unable to identify file type for file {0}", Path
), EC
);
265 if (Magic
== file_magic::coff_object
) {
266 Expected
<OwningBinary
<Binary
>> BinaryOrErr
= createBinary(Path
);
268 return BinaryOrErr
.takeError();
270 IF
.CoffObject
= std::move(*BinaryOrErr
);
271 IF
.PdbOrObj
= llvm::cast
<COFFObjectFile
>(IF
.CoffObject
.getBinary());
272 return std::move(IF
);
275 if (Magic
== file_magic::pdb
) {
276 std::unique_ptr
<IPDBSession
> Session
;
277 if (auto Err
= loadDataForPDB(PDB_ReaderType::Native
, Path
, Session
))
278 return std::move(Err
);
280 IF
.PdbSession
.reset(static_cast<NativeSession
*>(Session
.release()));
281 IF
.PdbOrObj
= &IF
.PdbSession
->getPDBFile();
283 return std::move(IF
);
286 if (!AllowUnknownFile
)
287 return make_error
<StringError
>(
288 formatv("File {0} is not a supported file type", Path
),
289 inconvertibleErrorCode());
291 auto Result
= MemoryBuffer::getFile(Path
, -1LL, false);
293 return make_error
<StringError
>(
294 formatv("File {0} could not be opened", Path
), Result
.getError());
296 IF
.UnknownFile
= std::move(*Result
);
297 IF
.PdbOrObj
= IF
.UnknownFile
.get();
298 return std::move(IF
);
301 PDBFile
&InputFile::pdb() {
303 return *PdbOrObj
.get
<PDBFile
*>();
306 const PDBFile
&InputFile::pdb() const {
308 return *PdbOrObj
.get
<PDBFile
*>();
311 object::COFFObjectFile
&InputFile::obj() {
313 return *PdbOrObj
.get
<object::COFFObjectFile
*>();
316 const object::COFFObjectFile
&InputFile::obj() const {
318 return *PdbOrObj
.get
<object::COFFObjectFile
*>();
321 MemoryBuffer
&InputFile::unknown() {
323 return *PdbOrObj
.get
<MemoryBuffer
*>();
326 const MemoryBuffer
&InputFile::unknown() const {
328 return *PdbOrObj
.get
<MemoryBuffer
*>();
331 StringRef
InputFile::getFilePath() const {
333 return pdb().getFilePath();
335 return obj().getFileName();
337 return unknown().getBufferIdentifier();
340 bool InputFile::hasTypes() const {
342 return pdb().hasPDBTpiStream();
344 for (const auto &Section
: obj().sections()) {
346 if (isDebugTSection(Section
, Types
))
352 bool InputFile::hasIds() const {
355 return pdb().hasPDBIpiStream();
358 bool InputFile::isPdb() const { return PdbOrObj
.is
<PDBFile
*>(); }
360 bool InputFile::isObj() const {
361 return PdbOrObj
.is
<object::COFFObjectFile
*>();
364 bool InputFile::isUnknown() const { return PdbOrObj
.is
<MemoryBuffer
*>(); }
366 codeview::LazyRandomTypeCollection
&
367 InputFile::getOrCreateTypeCollection(TypeCollectionKind Kind
) {
368 if (Types
&& Kind
== kTypes
)
370 if (Ids
&& Kind
== kIds
)
374 assert(isPdb() && pdb().hasPDBIpiStream());
377 // If the collection was already initialized, we should have just returned it
380 TypeCollectionPtr
&Collection
= (Kind
== kIds
) ? Ids
: Types
;
381 auto &Stream
= cantFail((Kind
== kIds
) ? pdb().getPDBIpiStream()
382 : pdb().getPDBTpiStream());
384 auto &Array
= Stream
.typeArray();
385 uint32_t Count
= Stream
.getNumTypeRecords();
386 auto Offsets
= Stream
.getTypeIndexOffsets();
388 std::make_unique
<LazyRandomTypeCollection
>(Array
, Count
, Offsets
);
393 assert(Kind
== kTypes
);
396 for (const auto &Section
: obj().sections()) {
398 if (!isDebugTSection(Section
, Records
))
401 Types
= std::make_unique
<LazyRandomTypeCollection
>(Records
, 100);
405 Types
= std::make_unique
<LazyRandomTypeCollection
>(100);
409 codeview::LazyRandomTypeCollection
&InputFile::types() {
410 return getOrCreateTypeCollection(kTypes
);
413 codeview::LazyRandomTypeCollection
&InputFile::ids() {
414 // Object files have only one type stream that contains both types and ids.
415 // Similarly, some PDBs don't contain an IPI stream, and for those both types
416 // and IDs are in the same stream.
417 if (isObj() || !pdb().hasPDBIpiStream())
420 return getOrCreateTypeCollection(kIds
);
423 iterator_range
<SymbolGroupIterator
> InputFile::symbol_groups() {
424 return make_range
<SymbolGroupIterator
>(symbol_groups_begin(),
425 symbol_groups_end());
428 SymbolGroupIterator
InputFile::symbol_groups_begin() {
429 return SymbolGroupIterator(*this);
432 SymbolGroupIterator
InputFile::symbol_groups_end() {
433 return SymbolGroupIterator();
436 SymbolGroupIterator::SymbolGroupIterator() : Value(nullptr) {}
438 SymbolGroupIterator::SymbolGroupIterator(InputFile
&File
) : Value(&File
) {
440 SectionIter
= File
.obj().section_begin();
445 bool SymbolGroupIterator::operator==(const SymbolGroupIterator
&R
) const {
451 if (Value
.File
!= R
.Value
.File
)
453 return Index
== R
.Index
;
456 const SymbolGroup
&SymbolGroupIterator::operator*() const {
460 SymbolGroup
&SymbolGroupIterator::operator*() {
465 SymbolGroupIterator
&SymbolGroupIterator::operator++() {
466 assert(Value
.File
&& !isEnd());
471 if (Value
.File
->isPdb()) {
472 Value
.updatePdbModi(Index
);
480 void SymbolGroupIterator::scanToNextDebugS() {
481 assert(SectionIter
.hasValue());
482 auto End
= Value
.File
->obj().section_end();
483 auto &Iter
= *SectionIter
;
486 while (++Iter
!= End
) {
487 DebugSubsectionArray SS
;
488 SectionRef SR
= *Iter
;
489 if (!isDebugSSection(SR
, SS
))
492 Value
.updateDebugS(SS
);
497 bool SymbolGroupIterator::isEnd() const {
500 if (Value
.File
->isPdb()) {
501 auto &Dbi
= cantFail(Value
.File
->pdb().getPDBDbiStream());
502 uint32_t Count
= Dbi
.modules().getModuleCount();
503 assert(Index
<= Count
);
504 return Index
== Count
;
507 assert(SectionIter
.hasValue());
508 return *SectionIter
== Value
.File
->obj().section_end();