003 File Manager
Current Path:
/usr/src/contrib/llvm-project/llvm/lib/DebugInfo/CodeView
usr
/
src
/
contrib
/
llvm-project
/
llvm
/
lib
/
DebugInfo
/
CodeView
/
📁
..
📄
AppendingTypeTableBuilder.cpp
(3.51 KB)
📄
CVSymbolVisitor.cpp
(2.78 KB)
📄
CVTypeVisitor.cpp
(9.14 KB)
📄
CodeViewError.cpp
(1.89 KB)
📄
CodeViewRecordIO.cpp
(11.73 KB)
📄
ContinuationRecordBuilder.cpp
(9.18 KB)
📄
DebugChecksumsSubsection.cpp
(3.89 KB)
📄
DebugCrossExSubsection.cpp
(1.74 KB)
📄
DebugCrossImpSubsection.cpp
(3.29 KB)
📄
DebugFrameDataSubsection.cpp
(2.02 KB)
📄
DebugInlineeLinesSubsection.cpp
(3.85 KB)
📄
DebugLinesSubsection.cpp
(5.52 KB)
📄
DebugStringTableSubsection.cpp
(3.21 KB)
📄
DebugSubsection.cpp
(538 B)
📄
DebugSubsectionRecord.cpp
(3.4 KB)
📄
DebugSubsectionVisitor.cpp
(3.34 KB)
📄
DebugSymbolRVASubsection.cpp
(1.28 KB)
📄
DebugSymbolsSubsection.cpp
(1.02 KB)
📄
EnumTables.cpp
(21.1 KB)
📄
Formatters.cpp
(1.47 KB)
📄
GlobalTypeTableBuilder.cpp
(4.43 KB)
📄
LazyRandomTypeCollection.cpp
(8.94 KB)
📄
Line.cpp
(748 B)
📄
MergingTypeTableBuilder.cpp
(4.81 KB)
📄
RecordName.cpp
(10.4 KB)
📄
RecordSerialization.cpp
(4.86 KB)
📄
SimpleTypeSerializer.cpp
(2.4 KB)
📄
StringsAndChecksums.cpp
(2.58 KB)
📄
SymbolDumper.cpp
(25.61 KB)
📄
SymbolRecordHelpers.cpp
(2.82 KB)
📄
SymbolRecordMapping.cpp
(16.92 KB)
📄
SymbolSerializer.cpp
(1.83 KB)
📄
TypeDumpVisitor.cpp
(21.43 KB)
📄
TypeHashing.cpp
(3.03 KB)
📄
TypeIndex.cpp
(3.84 KB)
📄
TypeIndexDiscovery.cpp
(16.54 KB)
📄
TypeRecordHelpers.cpp
(1.59 KB)
📄
TypeRecordMapping.cpp
(24.67 KB)
📄
TypeStreamMerger.cpp
(18.42 KB)
📄
TypeTableCollection.cpp
(1.96 KB)
Editing: TypeStreamMerger.cpp
//===-- TypeStreamMerger.cpp ------------------------------------*- C++ -*-===// // // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. // See https://llvm.org/LICENSE.txt for license information. // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception // //===----------------------------------------------------------------------===// #include "llvm/DebugInfo/CodeView/TypeStreamMerger.h" #include "llvm/ADT/SmallString.h" #include "llvm/ADT/StringExtras.h" #include "llvm/DebugInfo/CodeView/GlobalTypeTableBuilder.h" #include "llvm/DebugInfo/CodeView/MergingTypeTableBuilder.h" #include "llvm/DebugInfo/CodeView/TypeDeserializer.h" #include "llvm/DebugInfo/CodeView/TypeIndex.h" #include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h" #include "llvm/DebugInfo/CodeView/TypeRecord.h" #include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h" #include "llvm/Support/Error.h" using namespace llvm; using namespace llvm::codeview; static inline size_t slotForIndex(TypeIndex Idx) { assert(!Idx.isSimple() && "simple type indices have no slots"); return Idx.getIndex() - TypeIndex::FirstNonSimpleIndex; } namespace { /// Implementation of CodeView type stream merging. /// /// A CodeView type stream is a series of records that reference each other /// through type indices. A type index is either "simple", meaning it is less /// than 0x1000 and refers to a builtin type, or it is complex, meaning it /// refers to a prior type record in the current stream. The type index of a /// record is equal to the number of records before it in the stream plus /// 0x1000. /// /// Type records are only allowed to use type indices smaller than their own, so /// a type stream is effectively a topologically sorted DAG. Cycles occuring in /// the type graph of the source program are resolved with forward declarations /// of composite types. This class implements the following type stream merging /// algorithm, which relies on this DAG structure: /// /// - Begin with a new empty stream, and a new empty hash table that maps from /// type record contents to new type index. /// - For each new type stream, maintain a map from source type index to /// destination type index. /// - For each record, copy it and rewrite its type indices to be valid in the /// destination type stream. /// - If the new type record is not already present in the destination stream /// hash table, append it to the destination type stream, assign it the next /// type index, and update the two hash tables. /// - If the type record already exists in the destination stream, discard it /// and update the type index map to forward the source type index to the /// existing destination type index. /// /// As an additional complication, type stream merging actually produces two /// streams: an item (or IPI) stream and a type stream, as this is what is /// actually stored in the final PDB. We choose which records go where by /// looking at the record kind. class TypeStreamMerger { public: explicit TypeStreamMerger(SmallVectorImpl<TypeIndex> &SourceToDest) : IndexMap(SourceToDest) { // When dealing with precompiled headers objects, all data in SourceToDest // belongs to the precompiled headers object, and is assumed to be already // remapped to the target PDB. Any forthcoming type that will be merged in // might potentially back-reference this data. We also don't want to resolve // twice the types in the precompiled object. CurIndex += SourceToDest.size(); } static const TypeIndex Untranslated; // Local hashing entry points Error mergeTypesAndIds(MergingTypeTableBuilder &DestIds, MergingTypeTableBuilder &DestTypes, const CVTypeArray &IdsAndTypes, Optional<uint32_t> &S); Error mergeIdRecords(MergingTypeTableBuilder &Dest, ArrayRef<TypeIndex> TypeSourceToDest, const CVTypeArray &Ids); Error mergeTypeRecords(MergingTypeTableBuilder &Dest, const CVTypeArray &Types); // Global hashing entry points Error mergeTypesAndIds(GlobalTypeTableBuilder &DestIds, GlobalTypeTableBuilder &DestTypes, const CVTypeArray &IdsAndTypes, ArrayRef<GloballyHashedType> Hashes, Optional<uint32_t> &S); Error mergeIdRecords(GlobalTypeTableBuilder &Dest, ArrayRef<TypeIndex> TypeSourceToDest, const CVTypeArray &Ids, ArrayRef<GloballyHashedType> Hashes); Error mergeTypeRecords(GlobalTypeTableBuilder &Dest, const CVTypeArray &Types, ArrayRef<GloballyHashedType> Hashes, Optional<uint32_t> &S); private: Error doit(const CVTypeArray &Types); Error remapAllTypes(const CVTypeArray &Types); Error remapType(const CVType &Type); void addMapping(TypeIndex Idx); inline bool remapTypeIndex(TypeIndex &Idx) { // If we're mapping a pure index stream, then IndexMap only contains // mappings from OldIdStream -> NewIdStream, in which case we will need to // use the special mapping from OldTypeStream -> NewTypeStream which was // computed externally. Regardless, we use this special map if and only if // we are doing an id-only mapping. if (!hasTypeStream()) return remapIndex(Idx, TypeLookup); assert(TypeLookup.empty()); return remapIndex(Idx, IndexMap); } inline bool remapItemIndex(TypeIndex &Idx) { assert(hasIdStream()); return remapIndex(Idx, IndexMap); } bool hasTypeStream() const { return (UseGlobalHashes) ? (!!DestGlobalTypeStream) : (!!DestTypeStream); } bool hasIdStream() const { return (UseGlobalHashes) ? (!!DestGlobalIdStream) : (!!DestIdStream); } ArrayRef<uint8_t> remapIndices(const CVType &OriginalType, MutableArrayRef<uint8_t> Storage); inline bool remapIndex(TypeIndex &Idx, ArrayRef<TypeIndex> Map) { if (LLVM_LIKELY(remapIndexSimple(Idx, Map))) return true; return remapIndexFallback(Idx, Map); } inline bool remapIndexSimple(TypeIndex &Idx, ArrayRef<TypeIndex> Map) const { // Simple types are unchanged. if (Idx.isSimple()) return true; // Check if this type index refers to a record we've already translated // successfully. If it refers to a type later in the stream or a record we // had to defer, defer it until later pass. unsigned MapPos = slotForIndex(Idx); if (LLVM_UNLIKELY(MapPos >= Map.size() || Map[MapPos] == Untranslated)) return false; Idx = Map[MapPos]; return true; } bool remapIndexFallback(TypeIndex &Idx, ArrayRef<TypeIndex> Map); Error errorCorruptRecord() const { return llvm::make_error<CodeViewError>(cv_error_code::corrupt_record); } Expected<bool> shouldRemapType(const CVType &Type); Optional<Error> LastError; bool UseGlobalHashes = false; bool IsSecondPass = false; unsigned NumBadIndices = 0; TypeIndex CurIndex{TypeIndex::FirstNonSimpleIndex}; MergingTypeTableBuilder *DestIdStream = nullptr; MergingTypeTableBuilder *DestTypeStream = nullptr; GlobalTypeTableBuilder *DestGlobalIdStream = nullptr; GlobalTypeTableBuilder *DestGlobalTypeStream = nullptr; ArrayRef<GloballyHashedType> GlobalHashes; // If we're only mapping id records, this array contains the mapping for // type records. ArrayRef<TypeIndex> TypeLookup; /// Map from source type index to destination type index. Indexed by source /// type index minus 0x1000. SmallVectorImpl<TypeIndex> &IndexMap; /// Temporary storage that we use to copy a record's data while re-writing /// its type indices. SmallVector<uint8_t, 256> RemapStorage; Optional<uint32_t> PCHSignature; }; } // end anonymous namespace const TypeIndex TypeStreamMerger::Untranslated(SimpleTypeKind::NotTranslated); void TypeStreamMerger::addMapping(TypeIndex Idx) { if (!IsSecondPass) { assert(IndexMap.size() == slotForIndex(CurIndex) && "visitKnownRecord should add one index map entry"); IndexMap.push_back(Idx); } else { assert(slotForIndex(CurIndex) < IndexMap.size()); IndexMap[slotForIndex(CurIndex)] = Idx; } } bool TypeStreamMerger::remapIndexFallback(TypeIndex &Idx, ArrayRef<TypeIndex> Map) { size_t MapPos = slotForIndex(Idx); // If this is the second pass and this index isn't in the map, then it points // outside the current type stream, and this is a corrupt record. if (IsSecondPass && MapPos >= Map.size()) { // FIXME: Print a more useful error. We can give the current record and the // index that we think its pointing to. if (LastError) LastError = joinErrors(std::move(*LastError), errorCorruptRecord()); else LastError = errorCorruptRecord(); } ++NumBadIndices; // This type index is invalid. Remap this to "not translated by cvpack", // and return failure. Idx = Untranslated; return false; } // Local hashing entry points Error TypeStreamMerger::mergeTypeRecords(MergingTypeTableBuilder &Dest, const CVTypeArray &Types) { DestTypeStream = &Dest; UseGlobalHashes = false; return doit(Types); } Error TypeStreamMerger::mergeIdRecords(MergingTypeTableBuilder &Dest, ArrayRef<TypeIndex> TypeSourceToDest, const CVTypeArray &Ids) { DestIdStream = &Dest; TypeLookup = TypeSourceToDest; UseGlobalHashes = false; return doit(Ids); } Error TypeStreamMerger::mergeTypesAndIds(MergingTypeTableBuilder &DestIds, MergingTypeTableBuilder &DestTypes, const CVTypeArray &IdsAndTypes, Optional<uint32_t> &S) { DestIdStream = &DestIds; DestTypeStream = &DestTypes; UseGlobalHashes = false; auto Err = doit(IdsAndTypes); S = PCHSignature; return Err; } // Global hashing entry points Error TypeStreamMerger::mergeTypeRecords(GlobalTypeTableBuilder &Dest, const CVTypeArray &Types, ArrayRef<GloballyHashedType> Hashes, Optional<uint32_t> &S) { DestGlobalTypeStream = &Dest; UseGlobalHashes = true; GlobalHashes = Hashes; auto Err = doit(Types); S = PCHSignature; return Err; } Error TypeStreamMerger::mergeIdRecords(GlobalTypeTableBuilder &Dest, ArrayRef<TypeIndex> TypeSourceToDest, const CVTypeArray &Ids, ArrayRef<GloballyHashedType> Hashes) { DestGlobalIdStream = &Dest; TypeLookup = TypeSourceToDest; UseGlobalHashes = true; GlobalHashes = Hashes; return doit(Ids); } Error TypeStreamMerger::mergeTypesAndIds(GlobalTypeTableBuilder &DestIds, GlobalTypeTableBuilder &DestTypes, const CVTypeArray &IdsAndTypes, ArrayRef<GloballyHashedType> Hashes, Optional<uint32_t> &S) { DestGlobalIdStream = &DestIds; DestGlobalTypeStream = &DestTypes; UseGlobalHashes = true; GlobalHashes = Hashes; auto Err = doit(IdsAndTypes); S = PCHSignature; return Err; } Error TypeStreamMerger::doit(const CVTypeArray &Types) { if (auto EC = remapAllTypes(Types)) return EC; // If we found bad indices but no other errors, try doing another pass and see // if we can resolve the indices that weren't in the map on the first pass. // This may require multiple passes, but we should always make progress. MASM // is the only known CodeView producer that makes type streams that aren't // topologically sorted. The standard library contains MASM-produced objects, // so this is important to handle correctly, but we don't have to be too // efficient. MASM type streams are usually very small. while (!LastError && NumBadIndices > 0) { unsigned BadIndicesRemaining = NumBadIndices; IsSecondPass = true; NumBadIndices = 0; CurIndex = TypeIndex(TypeIndex::FirstNonSimpleIndex); if (auto EC = remapAllTypes(Types)) return EC; assert(NumBadIndices <= BadIndicesRemaining && "second pass found more bad indices"); if (!LastError && NumBadIndices == BadIndicesRemaining) { return llvm::make_error<CodeViewError>( cv_error_code::corrupt_record, "Input type graph contains cycles"); } } if (LastError) return std::move(*LastError); return Error::success(); } Error TypeStreamMerger::remapAllTypes(const CVTypeArray &Types) { BinaryStreamRef Stream = Types.getUnderlyingStream(); ArrayRef<uint8_t> Buffer; cantFail(Stream.readBytes(0, Stream.getLength(), Buffer)); return forEachCodeViewRecord<CVType>( Buffer, [this](const CVType &T) { return remapType(T); }); } Error TypeStreamMerger::remapType(const CVType &Type) { auto R = shouldRemapType(Type); if (!R) return R.takeError(); TypeIndex DestIdx = Untranslated; if (*R) { auto DoSerialize = [this, Type](MutableArrayRef<uint8_t> Storage) -> ArrayRef<uint8_t> { return remapIndices(Type, Storage); }; unsigned AlignedSize = alignTo(Type.RecordData.size(), 4); if (LLVM_LIKELY(UseGlobalHashes)) { GlobalTypeTableBuilder &Dest = isIdRecord(Type.kind()) ? *DestGlobalIdStream : *DestGlobalTypeStream; GloballyHashedType H = GlobalHashes[CurIndex.toArrayIndex()]; DestIdx = Dest.insertRecordAs(H, AlignedSize, DoSerialize); } else { MergingTypeTableBuilder &Dest = isIdRecord(Type.kind()) ? *DestIdStream : *DestTypeStream; RemapStorage.resize(AlignedSize); ArrayRef<uint8_t> Result = DoSerialize(RemapStorage); if (!Result.empty()) DestIdx = Dest.insertRecordBytes(Result); } } addMapping(DestIdx); ++CurIndex; assert((IsSecondPass || IndexMap.size() == slotForIndex(CurIndex)) && "visitKnownRecord should add one index map entry"); return Error::success(); } ArrayRef<uint8_t> TypeStreamMerger::remapIndices(const CVType &OriginalType, MutableArrayRef<uint8_t> Storage) { unsigned Align = OriginalType.RecordData.size() & 3; assert(Storage.size() == alignTo(OriginalType.RecordData.size(), 4) && "The storage buffer size is not a multiple of 4 bytes which will " "cause misalignment in the output TPI stream!"); SmallVector<TiReference, 4> Refs; discoverTypeIndices(OriginalType.RecordData, Refs); if (Refs.empty() && Align == 0) return OriginalType.RecordData; ::memcpy(Storage.data(), OriginalType.RecordData.data(), OriginalType.RecordData.size()); uint8_t *DestContent = Storage.data() + sizeof(RecordPrefix); for (auto &Ref : Refs) { TypeIndex *DestTIs = reinterpret_cast<TypeIndex *>(DestContent + Ref.Offset); for (size_t I = 0; I < Ref.Count; ++I) { TypeIndex &TI = DestTIs[I]; bool Success = (Ref.Kind == TiRefKind::IndexRef) ? remapItemIndex(TI) : remapTypeIndex(TI); if (LLVM_UNLIKELY(!Success)) return {}; } } if (Align > 0) { RecordPrefix *StorageHeader = reinterpret_cast<RecordPrefix *>(Storage.data()); StorageHeader->RecordLen += 4 - Align; DestContent = Storage.data() + OriginalType.RecordData.size(); for (; Align < 4; ++Align) *DestContent++ = LF_PAD4 - Align; } return Storage; } Error llvm::codeview::mergeTypeRecords(MergingTypeTableBuilder &Dest, SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &Types) { TypeStreamMerger M(SourceToDest); return M.mergeTypeRecords(Dest, Types); } Error llvm::codeview::mergeIdRecords(MergingTypeTableBuilder &Dest, ArrayRef<TypeIndex> TypeSourceToDest, SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &Ids) { TypeStreamMerger M(SourceToDest); return M.mergeIdRecords(Dest, TypeSourceToDest, Ids); } Error llvm::codeview::mergeTypeAndIdRecords( MergingTypeTableBuilder &DestIds, MergingTypeTableBuilder &DestTypes, SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &IdsAndTypes, Optional<uint32_t> &PCHSignature) { TypeStreamMerger M(SourceToDest); return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes, PCHSignature); } Error llvm::codeview::mergeTypeAndIdRecords( GlobalTypeTableBuilder &DestIds, GlobalTypeTableBuilder &DestTypes, SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &IdsAndTypes, ArrayRef<GloballyHashedType> Hashes, Optional<uint32_t> &PCHSignature) { TypeStreamMerger M(SourceToDest); return M.mergeTypesAndIds(DestIds, DestTypes, IdsAndTypes, Hashes, PCHSignature); } Error llvm::codeview::mergeTypeRecords(GlobalTypeTableBuilder &Dest, SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &Types, ArrayRef<GloballyHashedType> Hashes, Optional<uint32_t> &PCHSignature) { TypeStreamMerger M(SourceToDest); return M.mergeTypeRecords(Dest, Types, Hashes, PCHSignature); } Error llvm::codeview::mergeIdRecords(GlobalTypeTableBuilder &Dest, ArrayRef<TypeIndex> Types, SmallVectorImpl<TypeIndex> &SourceToDest, const CVTypeArray &Ids, ArrayRef<GloballyHashedType> Hashes) { TypeStreamMerger M(SourceToDest); return M.mergeIdRecords(Dest, Types, Ids, Hashes); } Expected<bool> TypeStreamMerger::shouldRemapType(const CVType &Type) { // For object files containing precompiled types, we need to extract the // signature, through EndPrecompRecord. This is done here for performance // reasons, to avoid re-parsing the Types stream. if (Type.kind() == LF_ENDPRECOMP) { EndPrecompRecord EP; if (auto EC = TypeDeserializer::deserializeAs(const_cast<CVType &>(Type), EP)) return joinErrors(std::move(EC), errorCorruptRecord()); if (PCHSignature.hasValue()) return errorCorruptRecord(); PCHSignature.emplace(EP.getSignature()); return false; } return true; }
Upload File
Create Folder