aboutsummaryrefslogtreecommitdiffstats
path: root/contrib/libs/llvm14/lib/DebugInfo
diff options
context:
space:
mode:
authorvitalyisaev <vitalyisaev@yandex-team.com>2023-06-29 10:00:50 +0300
committervitalyisaev <vitalyisaev@yandex-team.com>2023-06-29 10:00:50 +0300
commit6ffe9e53658409f212834330e13564e4952558f6 (patch)
tree85b1e00183517648b228aafa7c8fb07f5276f419 /contrib/libs/llvm14/lib/DebugInfo
parent726057070f9c5a91fc10fde0d5024913d10f1ab9 (diff)
downloadydb-6ffe9e53658409f212834330e13564e4952558f6.tar.gz
YQ Connector: support managed ClickHouse
Со стороны dqrun можно обратиться к инстансу коннектора, который работает на streaming стенде, и извлечь данные из облачного CH.
Diffstat (limited to 'contrib/libs/llvm14/lib/DebugInfo')
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp112
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp82
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/CVTypeVisitor.cpp274
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/CodeViewError.cpp50
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp377
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp251
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp115
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugCrossExSubsection.cpp52
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp96
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp60
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp125
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp160
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp107
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSubsection.cpp15
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp94
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp94
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSymbolRVASubsection.cpp35
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSymbolsSubsection.cpp33
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/EnumTables.cpp562
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/Formatters.cpp59
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp140
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp284
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/Line.cpp21
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp152
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/RecordName.cpp339
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/RecordSerialization.cpp154
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp67
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/StringsAndChecksums.cpp80
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/SymbolDumper.cpp679
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp93
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp558
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/SymbolSerializer.cpp59
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp570
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeHashing.cpp80
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeIndex.cpp106
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp523
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp52
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeRecordMapping.cpp735
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeStreamMerger.cpp496
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeTableCollection.cpp65
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/CodeView/ya.make65
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp231
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp905
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFAddressRange.cpp33
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp44
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFContext.cpp2046
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp135
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp167
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp184
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp178
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp127
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp1251
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp94
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugLine.cpp1496
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp411
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp243
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp118
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp119
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp263
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDie.cpp1285
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFExpression.cpp519
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFFormValue.cpp781
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp199
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFListTable.cpp109
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFLocationExpression.cpp19
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp53
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFUnit.cpp1029
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp300
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFVerifier.cpp1563
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/DWARF/ya.make56
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/GSYM/DwarfTransformer.cpp575
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/GSYM/FileWriter.cpp77
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/GSYM/FunctionInfo.cpp254
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/GSYM/GsymCreator.cpp362
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/GSYM/GsymReader.cpp406
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/GSYM/Header.cpp109
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/GSYM/InlineInfo.cpp265
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/GSYM/LineTable.cpp293
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/GSYM/LookupResult.cpp74
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp116
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/GSYM/Range.cpp123
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/GSYM/ya.make39
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/MSF/MSFBuilder.cpp401
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/MSF/MSFCommon.cpp82
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/MSF/MSFError.cpp56
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/MSF/MappedBlockStream.cpp421
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/MSF/ya.make29
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/GenericError.cpp48
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/IPDBSourceFile.cpp34
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp86
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp218
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiModuleList.cpp279
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiStream.cpp383
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp454
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/EnumTables.cpp37
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp494
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/GlobalsStream.cpp181
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/Hash.cpp84
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/HashTable.cpp71
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/InfoStream.cpp131
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp82
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp65
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp144
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp126
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp60
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumGlobals.cpp54
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumInjectedSources.cpp121
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumLineNumbers.cpp42
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp43
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumSymbols.cpp41
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp70
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp101
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeFunctionSymbol.cpp143
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeInlineSiteSymbol.cpp177
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeLineNumber.cpp51
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativePublicSymbol.cpp48
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp734
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeSession.cpp463
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeSourceFile.cpp47
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp124
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeArray.cpp66
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp46
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp381
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp199
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp193
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeTypedef.cpp29
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp220
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeVTShape.cpp35
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PDBFile.cpp508
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp355
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PDBStringTable.cpp140
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp229
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PublicsStream.cpp101
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/RawError.cpp53
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/SymbolCache.cpp633
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/SymbolStream.cpp45
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/TpiHashing.cpp129
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/TpiStream.cpp246
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp214
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDB.cpp51
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBContext.cpp159
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBExtras.cpp408
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp39
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymDumper.cpp146
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbol.cpp231
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp20
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolBlock.cpp19
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp110
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp21
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp29
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolCustom.cpp24
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolData.cpp68
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolExe.cpp29
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolFunc.cpp111
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp21
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp21
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolLabel.cpp18
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp21
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolThunk.cpp18
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp24
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp21
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp20
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp21
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp21
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp19
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp21
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp20
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp93
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp21
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp25
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp20
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp25
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp20
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp21
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolUnknown.cpp19
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp21
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/UDTLayout.cpp302
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/PDB/ya.make119
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/Symbolize/DIFetcher.cpp58
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/Symbolize/DIPrinter.cpp398
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp355
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h103
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/Symbolize/Symbolize.cpp659
-rw-r--r--contrib/libs/llvm14/lib/DebugInfo/Symbolize/ya.make33
184 files changed, 38792 insertions, 0 deletions
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp
new file mode 100644
index 0000000000..4d8b15530b
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/AppendingTypeTableBuilder.cpp
@@ -0,0 +1,112 @@
+//===- AppendingTypeTableBuilder.cpp --------------------------------------===//
+//
+// 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/AppendingTypeTableBuilder.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+TypeIndex AppendingTypeTableBuilder::nextTypeIndex() const {
+ return TypeIndex::fromArrayIndex(SeenRecords.size());
+}
+
+AppendingTypeTableBuilder::AppendingTypeTableBuilder(BumpPtrAllocator &Storage)
+ : RecordStorage(Storage) {}
+
+AppendingTypeTableBuilder::~AppendingTypeTableBuilder() = default;
+
+Optional<TypeIndex> AppendingTypeTableBuilder::getFirst() {
+ if (empty())
+ return None;
+
+ return TypeIndex(TypeIndex::FirstNonSimpleIndex);
+}
+
+Optional<TypeIndex> AppendingTypeTableBuilder::getNext(TypeIndex Prev) {
+ if (++Prev == nextTypeIndex())
+ return None;
+ return Prev;
+}
+
+CVType AppendingTypeTableBuilder::getType(TypeIndex Index){
+ return CVType(SeenRecords[Index.toArrayIndex()]);
+}
+
+StringRef AppendingTypeTableBuilder::getTypeName(TypeIndex Index) {
+ llvm_unreachable("Method not implemented");
+}
+
+bool AppendingTypeTableBuilder::contains(TypeIndex Index) {
+ if (Index.isSimple() || Index.isNoneType())
+ return false;
+
+ return Index.toArrayIndex() < SeenRecords.size();
+}
+
+uint32_t AppendingTypeTableBuilder::size() { return SeenRecords.size(); }
+
+uint32_t AppendingTypeTableBuilder::capacity() { return SeenRecords.size(); }
+
+ArrayRef<ArrayRef<uint8_t>> AppendingTypeTableBuilder::records() const {
+ return SeenRecords;
+}
+
+void AppendingTypeTableBuilder::reset() { SeenRecords.clear(); }
+
+static ArrayRef<uint8_t> stabilize(BumpPtrAllocator &RecordStorage,
+ ArrayRef<uint8_t> Record) {
+ uint8_t *Stable = RecordStorage.Allocate<uint8_t>(Record.size());
+ memcpy(Stable, Record.data(), Record.size());
+ return ArrayRef<uint8_t>(Stable, Record.size());
+}
+
+TypeIndex
+AppendingTypeTableBuilder::insertRecordBytes(ArrayRef<uint8_t> &Record) {
+ TypeIndex NewTI = nextTypeIndex();
+ Record = stabilize(RecordStorage, Record);
+ SeenRecords.push_back(Record);
+ return NewTI;
+}
+
+TypeIndex
+AppendingTypeTableBuilder::insertRecord(ContinuationRecordBuilder &Builder) {
+ TypeIndex TI;
+ auto Fragments = Builder.end(nextTypeIndex());
+ assert(!Fragments.empty());
+ for (auto C : Fragments)
+ TI = insertRecordBytes(C.RecordData);
+ return TI;
+}
+
+bool AppendingTypeTableBuilder::replaceType(TypeIndex &Index, CVType Data,
+ bool Stabilize) {
+ assert(Index.toArrayIndex() < SeenRecords.size() &&
+ "This function cannot be used to insert records!");
+
+ ArrayRef<uint8_t> Record = Data.data();
+ if (Stabilize)
+ Record = stabilize(RecordStorage, Record);
+ SeenRecords[Index.toArrayIndex()] = Record;
+ return true;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp
new file mode 100644
index 0000000000..48b9b0496f
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/CVSymbolVisitor.cpp
@@ -0,0 +1,82 @@
+//===- CVSymbolVisitor.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/CVSymbolVisitor.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+CVSymbolVisitor::CVSymbolVisitor(SymbolVisitorCallbacks &Callbacks)
+ : Callbacks(Callbacks) {}
+
+template <typename T>
+static Error visitKnownRecord(CVSymbol &Record,
+ SymbolVisitorCallbacks &Callbacks) {
+ SymbolRecordKind RK = static_cast<SymbolRecordKind>(Record.kind());
+ T KnownRecord(RK);
+ if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
+ return EC;
+ return Error::success();
+}
+
+static Error finishVisitation(CVSymbol &Record,
+ SymbolVisitorCallbacks &Callbacks) {
+ switch (Record.kind()) {
+ default:
+ if (auto EC = Callbacks.visitUnknownSymbol(Record))
+ return EC;
+ break;
+#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
+ case EnumName: { \
+ if (auto EC = visitKnownRecord<Name>(Record, Callbacks)) \
+ return EC; \
+ break; \
+ }
+#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
+ SYMBOL_RECORD(EnumVal, EnumVal, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
+ }
+
+ if (auto EC = Callbacks.visitSymbolEnd(Record))
+ return EC;
+
+ return Error::success();
+}
+
+Error CVSymbolVisitor::visitSymbolRecord(CVSymbol &Record) {
+ if (auto EC = Callbacks.visitSymbolBegin(Record))
+ return EC;
+ return finishVisitation(Record, Callbacks);
+}
+
+Error CVSymbolVisitor::visitSymbolRecord(CVSymbol &Record, uint32_t Offset) {
+ if (auto EC = Callbacks.visitSymbolBegin(Record, Offset))
+ return EC;
+ return finishVisitation(Record, Callbacks);
+}
+
+Error CVSymbolVisitor::visitSymbolStream(const CVSymbolArray &Symbols) {
+ for (auto I : Symbols) {
+ if (auto EC = visitSymbolRecord(I))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error CVSymbolVisitor::visitSymbolStream(const CVSymbolArray &Symbols,
+ uint32_t InitialOffset) {
+ for (auto I : Symbols) {
+ if (auto EC = visitSymbolRecord(I, InitialOffset + Symbols.skew()))
+ return EC;
+ InitialOffset += I.length();
+ }
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/CVTypeVisitor.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
new file mode 100644
index 0000000000..dd6f75f97a
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/CVTypeVisitor.cpp
@@ -0,0 +1,274 @@
+//===- CVTypeVisitor.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/CVTypeVisitor.h"
+
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/TypeCollection.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbackPipeline.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryStreamReader.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+
+template <typename T>
+static Error visitKnownRecord(CVType &Record, TypeVisitorCallbacks &Callbacks) {
+ TypeRecordKind RK = static_cast<TypeRecordKind>(Record.kind());
+ T KnownRecord(RK);
+ if (auto EC = Callbacks.visitKnownRecord(Record, KnownRecord))
+ return EC;
+ return Error::success();
+}
+
+template <typename T>
+static Error visitKnownMember(CVMemberRecord &Record,
+ TypeVisitorCallbacks &Callbacks) {
+ TypeRecordKind RK = static_cast<TypeRecordKind>(Record.Kind);
+ T KnownRecord(RK);
+ if (auto EC = Callbacks.visitKnownMember(Record, KnownRecord))
+ return EC;
+ return Error::success();
+}
+
+static Error visitMemberRecord(CVMemberRecord &Record,
+ TypeVisitorCallbacks &Callbacks) {
+ if (auto EC = Callbacks.visitMemberBegin(Record))
+ return EC;
+
+ switch (Record.Kind) {
+ default:
+ if (auto EC = Callbacks.visitUnknownMember(Record))
+ return EC;
+ break;
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
+ case EnumName: { \
+ if (auto EC = visitKnownMember<Name##Record>(Record, Callbacks)) \
+ return EC; \
+ break; \
+ }
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
+ MEMBER_RECORD(EnumVal, EnumVal, AliasName)
+#define TYPE_RECORD(EnumName, EnumVal, Name)
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+ }
+
+ if (auto EC = Callbacks.visitMemberEnd(Record))
+ return EC;
+
+ return Error::success();
+}
+
+namespace {
+
+class CVTypeVisitor {
+public:
+ explicit CVTypeVisitor(TypeVisitorCallbacks &Callbacks);
+
+ Error visitTypeRecord(CVType &Record, TypeIndex Index);
+ Error visitTypeRecord(CVType &Record);
+
+ /// Visits the type records in Data. Sets the error flag on parse failures.
+ Error visitTypeStream(const CVTypeArray &Types);
+ Error visitTypeStream(CVTypeRange Types);
+ Error visitTypeStream(TypeCollection &Types);
+
+ Error visitMemberRecord(CVMemberRecord Record);
+ Error visitFieldListMemberStream(BinaryStreamReader &Stream);
+
+private:
+ Error finishVisitation(CVType &Record);
+
+ /// The interface to the class that gets notified of each visitation.
+ TypeVisitorCallbacks &Callbacks;
+};
+
+CVTypeVisitor::CVTypeVisitor(TypeVisitorCallbacks &Callbacks)
+ : Callbacks(Callbacks) {}
+
+Error CVTypeVisitor::finishVisitation(CVType &Record) {
+ switch (Record.kind()) {
+ default:
+ if (auto EC = Callbacks.visitUnknownType(Record))
+ return EC;
+ break;
+#define TYPE_RECORD(EnumName, EnumVal, Name) \
+ case EnumName: { \
+ if (auto EC = visitKnownRecord<Name##Record>(Record, Callbacks)) \
+ return EC; \
+ break; \
+ }
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName) \
+ TYPE_RECORD(EnumVal, EnumVal, AliasName)
+#define MEMBER_RECORD(EnumName, EnumVal, Name)
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+ }
+
+ if (auto EC = Callbacks.visitTypeEnd(Record))
+ return EC;
+
+ return Error::success();
+}
+
+Error CVTypeVisitor::visitTypeRecord(CVType &Record, TypeIndex Index) {
+ if (auto EC = Callbacks.visitTypeBegin(Record, Index))
+ return EC;
+
+ return finishVisitation(Record);
+}
+
+Error CVTypeVisitor::visitTypeRecord(CVType &Record) {
+ if (auto EC = Callbacks.visitTypeBegin(Record))
+ return EC;
+
+ return finishVisitation(Record);
+}
+
+Error CVTypeVisitor::visitMemberRecord(CVMemberRecord Record) {
+ return ::visitMemberRecord(Record, Callbacks);
+}
+
+/// Visits the type records in Data. Sets the error flag on parse failures.
+Error CVTypeVisitor::visitTypeStream(const CVTypeArray &Types) {
+ for (auto I : Types) {
+ if (auto EC = visitTypeRecord(I))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error CVTypeVisitor::visitTypeStream(CVTypeRange Types) {
+ for (auto I : Types) {
+ if (auto EC = visitTypeRecord(I))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error CVTypeVisitor::visitTypeStream(TypeCollection &Types) {
+ Optional<TypeIndex> I = Types.getFirst();
+ while (I) {
+ CVType Type = Types.getType(*I);
+ if (auto EC = visitTypeRecord(Type, *I))
+ return EC;
+ I = Types.getNext(*I);
+ }
+ return Error::success();
+}
+
+Error CVTypeVisitor::visitFieldListMemberStream(BinaryStreamReader &Reader) {
+ TypeLeafKind Leaf;
+ while (!Reader.empty()) {
+ if (auto EC = Reader.readEnum(Leaf))
+ return EC;
+
+ CVMemberRecord Record;
+ Record.Kind = Leaf;
+ if (auto EC = ::visitMemberRecord(Record, Callbacks))
+ return EC;
+ }
+
+ return Error::success();
+}
+
+struct FieldListVisitHelper {
+ FieldListVisitHelper(TypeVisitorCallbacks &Callbacks, ArrayRef<uint8_t> Data,
+ VisitorDataSource Source)
+ : Stream(Data, llvm::support::little), Reader(Stream),
+ Deserializer(Reader),
+ Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
+ if (Source == VDS_BytesPresent) {
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Callbacks);
+ }
+ }
+
+ BinaryByteStream Stream;
+ BinaryStreamReader Reader;
+ FieldListDeserializer Deserializer;
+ TypeVisitorCallbackPipeline Pipeline;
+ CVTypeVisitor Visitor;
+};
+
+struct VisitHelper {
+ VisitHelper(TypeVisitorCallbacks &Callbacks, VisitorDataSource Source)
+ : Visitor((Source == VDS_BytesPresent) ? Pipeline : Callbacks) {
+ if (Source == VDS_BytesPresent) {
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Callbacks);
+ }
+ }
+
+ TypeDeserializer Deserializer;
+ TypeVisitorCallbackPipeline Pipeline;
+ CVTypeVisitor Visitor;
+};
+}
+
+Error llvm::codeview::visitTypeRecord(CVType &Record, TypeIndex Index,
+ TypeVisitorCallbacks &Callbacks,
+ VisitorDataSource Source) {
+ VisitHelper V(Callbacks, Source);
+ return V.Visitor.visitTypeRecord(Record, Index);
+}
+
+Error llvm::codeview::visitTypeRecord(CVType &Record,
+ TypeVisitorCallbacks &Callbacks,
+ VisitorDataSource Source) {
+ VisitHelper V(Callbacks, Source);
+ return V.Visitor.visitTypeRecord(Record);
+}
+
+Error llvm::codeview::visitTypeStream(const CVTypeArray &Types,
+ TypeVisitorCallbacks &Callbacks,
+ VisitorDataSource Source) {
+ VisitHelper V(Callbacks, Source);
+ return V.Visitor.visitTypeStream(Types);
+}
+
+Error llvm::codeview::visitTypeStream(CVTypeRange Types,
+ TypeVisitorCallbacks &Callbacks) {
+ VisitHelper V(Callbacks, VDS_BytesPresent);
+ return V.Visitor.visitTypeStream(Types);
+}
+
+Error llvm::codeview::visitTypeStream(TypeCollection &Types,
+ TypeVisitorCallbacks &Callbacks) {
+ // When the internal visitor calls Types.getType(Index) the interface is
+ // required to return a CVType with the bytes filled out. So we can assume
+ // that the bytes will be present when individual records are visited.
+ VisitHelper V(Callbacks, VDS_BytesPresent);
+ return V.Visitor.visitTypeStream(Types);
+}
+
+Error llvm::codeview::visitMemberRecord(CVMemberRecord Record,
+ TypeVisitorCallbacks &Callbacks,
+ VisitorDataSource Source) {
+ FieldListVisitHelper V(Callbacks, Record.Data, Source);
+ return V.Visitor.visitMemberRecord(Record);
+}
+
+Error llvm::codeview::visitMemberRecord(TypeLeafKind Kind,
+ ArrayRef<uint8_t> Record,
+ TypeVisitorCallbacks &Callbacks) {
+ CVMemberRecord R;
+ R.Data = Record;
+ R.Kind = Kind;
+ return visitMemberRecord(R, Callbacks, VDS_BytesPresent);
+}
+
+Error llvm::codeview::visitMemberRecordStream(ArrayRef<uint8_t> FieldList,
+ TypeVisitorCallbacks &Callbacks) {
+ FieldListVisitHelper V(Callbacks, FieldList, VDS_BytesPresent);
+ return V.Visitor.visitFieldListMemberStream(V.Reader);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/CodeViewError.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/CodeViewError.cpp
new file mode 100644
index 0000000000..d12f6c796e
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/CodeViewError.cpp
@@ -0,0 +1,50 @@
+//===- CodeViewError.cpp - Error extensions for CodeView --------*- 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/CodeViewError.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+#include <string>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+// FIXME: This class is only here to support the transition to llvm::Error. It
+// will be removed once this transition is complete. Clients should prefer to
+// deal with the Error value directly, rather than converting to error_code.
+class CodeViewErrorCategory : public std::error_category {
+public:
+ const char *name() const noexcept override { return "llvm.codeview"; }
+ std::string message(int Condition) const override {
+ switch (static_cast<cv_error_code>(Condition)) {
+ case cv_error_code::unspecified:
+ return "An unknown CodeView error has occurred.";
+ case cv_error_code::insufficient_buffer:
+ return "The buffer is not large enough to read the requested number of "
+ "bytes.";
+ case cv_error_code::corrupt_record:
+ return "The CodeView record is corrupted.";
+ case cv_error_code::no_records:
+ return "There are no records.";
+ case cv_error_code::operation_unsupported:
+ return "The requested operation is not supported.";
+ case cv_error_code::unknown_member_record:
+ return "The member record is of an unknown type.";
+ }
+ llvm_unreachable("Unrecognized cv_error_code");
+ }
+};
+} // namespace
+
+static llvm::ManagedStatic<CodeViewErrorCategory> CodeViewErrCategory;
+const std::error_category &llvm::codeview::CVErrorCategory() {
+ return *CodeViewErrCategory;
+}
+
+char CodeViewError::ID;
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp
new file mode 100644
index 0000000000..1af59ff679
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/CodeViewRecordIO.cpp
@@ -0,0 +1,377 @@
+//===- CodeViewRecordIO.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/CodeViewRecordIO.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error CodeViewRecordIO::beginRecord(Optional<uint32_t> MaxLength) {
+ RecordLimit Limit;
+ Limit.MaxLength = MaxLength;
+ Limit.BeginOffset = getCurrentOffset();
+ Limits.push_back(Limit);
+ return Error::success();
+}
+
+Error CodeViewRecordIO::endRecord() {
+ assert(!Limits.empty() && "Not in a record!");
+ Limits.pop_back();
+ // We would like to assert that we actually read / wrote all the bytes that we
+ // expected to for this record, but unfortunately we can't do this. Some
+ // producers such as MASM over-allocate for certain types of records and
+ // commit the extraneous data, so when reading we can't be sure every byte
+ // will have been read. And when writing we over-allocate temporarily since
+ // we don't know how big the record is until we're finished writing it, so
+ // even though we don't commit the extraneous data, we still can't guarantee
+ // we're at the end of the allocated data.
+
+ if (isStreaming()) {
+ // For streaming mode, add padding to align with 4 byte boundaries for each
+ // record
+ uint32_t Align = getStreamedLen() % 4;
+ if (Align == 0)
+ return Error::success();
+
+ int PaddingBytes = 4 - Align;
+ while (PaddingBytes > 0) {
+ char Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes);
+ StringRef BytesSR = StringRef(&Pad, sizeof(Pad));
+ Streamer->emitBytes(BytesSR);
+ --PaddingBytes;
+ }
+ resetStreamedLen();
+ }
+ return Error::success();
+}
+
+uint32_t CodeViewRecordIO::maxFieldLength() const {
+ if (isStreaming())
+ return 0;
+
+ assert(!Limits.empty() && "Not in a record!");
+
+ // The max length of the next field is the minimum of all lengths that would
+ // be allowed by any of the sub-records we're in. In practice, we can only
+ // ever be at most 1 sub-record deep (in a FieldList), but this works for
+ // the general case.
+ uint32_t Offset = getCurrentOffset();
+ Optional<uint32_t> Min = Limits.front().bytesRemaining(Offset);
+ for (auto X : makeArrayRef(Limits).drop_front()) {
+ Optional<uint32_t> ThisMin = X.bytesRemaining(Offset);
+ if (ThisMin.hasValue())
+ Min = (Min.hasValue()) ? std::min(*Min, *ThisMin) : *ThisMin;
+ }
+ assert(Min.hasValue() && "Every field must have a maximum length!");
+
+ return *Min;
+}
+
+Error CodeViewRecordIO::padToAlignment(uint32_t Align) {
+ if (isReading())
+ return Reader->padToAlignment(Align);
+ return Writer->padToAlignment(Align);
+}
+
+Error CodeViewRecordIO::skipPadding() {
+ assert(!isWriting() && "Cannot skip padding while writing!");
+
+ if (Reader->bytesRemaining() == 0)
+ return Error::success();
+
+ uint8_t Leaf = Reader->peek();
+ if (Leaf < LF_PAD0)
+ return Error::success();
+ // Leaf is greater than 0xf0. We should advance by the number of bytes in
+ // the low 4 bits.
+ unsigned BytesToAdvance = Leaf & 0x0F;
+ return Reader->skip(BytesToAdvance);
+}
+
+Error CodeViewRecordIO::mapByteVectorTail(ArrayRef<uint8_t> &Bytes,
+ const Twine &Comment) {
+ if (isStreaming()) {
+ emitComment(Comment);
+ Streamer->emitBinaryData(toStringRef(Bytes));
+ incrStreamedLen(Bytes.size());
+ } else if (isWriting()) {
+ if (auto EC = Writer->writeBytes(Bytes))
+ return EC;
+ } else {
+ if (auto EC = Reader->readBytes(Bytes, Reader->bytesRemaining()))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapByteVectorTail(std::vector<uint8_t> &Bytes,
+ const Twine &Comment) {
+ ArrayRef<uint8_t> BytesRef(Bytes);
+ if (auto EC = mapByteVectorTail(BytesRef, Comment))
+ return EC;
+ if (!isWriting())
+ Bytes.assign(BytesRef.begin(), BytesRef.end());
+
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapInteger(TypeIndex &TypeInd, const Twine &Comment) {
+ if (isStreaming()) {
+ std::string TypeNameStr = Streamer->getTypeName(TypeInd);
+ if (!TypeNameStr.empty())
+ emitComment(Comment + ": " + TypeNameStr);
+ else
+ emitComment(Comment);
+ Streamer->emitIntValue(TypeInd.getIndex(), sizeof(TypeInd.getIndex()));
+ incrStreamedLen(sizeof(TypeInd.getIndex()));
+ } else if (isWriting()) {
+ if (auto EC = Writer->writeInteger(TypeInd.getIndex()))
+ return EC;
+ } else {
+ uint32_t I;
+ if (auto EC = Reader->readInteger(I))
+ return EC;
+ TypeInd.setIndex(I);
+ }
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapEncodedInteger(int64_t &Value,
+ const Twine &Comment) {
+ if (isStreaming()) {
+ if (Value >= 0)
+ emitEncodedUnsignedInteger(static_cast<uint64_t>(Value), Comment);
+ else
+ emitEncodedSignedInteger(Value, Comment);
+ } else if (isWriting()) {
+ if (Value >= 0) {
+ if (auto EC = writeEncodedUnsignedInteger(static_cast<uint64_t>(Value)))
+ return EC;
+ } else {
+ if (auto EC = writeEncodedSignedInteger(Value))
+ return EC;
+ }
+ } else {
+ APSInt N;
+ if (auto EC = consume(*Reader, N))
+ return EC;
+ Value = N.getExtValue();
+ }
+
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapEncodedInteger(uint64_t &Value,
+ const Twine &Comment) {
+ if (isStreaming())
+ emitEncodedUnsignedInteger(Value, Comment);
+ else if (isWriting()) {
+ if (auto EC = writeEncodedUnsignedInteger(Value))
+ return EC;
+ } else {
+ APSInt N;
+ if (auto EC = consume(*Reader, N))
+ return EC;
+ Value = N.getZExtValue();
+ }
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapEncodedInteger(APSInt &Value, const Twine &Comment) {
+ if (isStreaming()) {
+ // FIXME: We also need to handle big values here, but it's
+ // not clear how we can excercise this code path yet.
+ if (Value.isSigned())
+ emitEncodedSignedInteger(Value.getSExtValue(), Comment);
+ else
+ emitEncodedUnsignedInteger(Value.getZExtValue(), Comment);
+ } else if (isWriting()) {
+ if (Value.isSigned())
+ return writeEncodedSignedInteger(
+ Value.isSingleWord() ? Value.getSExtValue() : INT64_MIN);
+ return writeEncodedUnsignedInteger(Value.getLimitedValue());
+ } else
+ return consume(*Reader, Value);
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapStringZ(StringRef &Value, const Twine &Comment) {
+ if (isStreaming()) {
+ auto NullTerminatedString = StringRef(Value.data(), Value.size() + 1);
+ emitComment(Comment);
+ Streamer->emitBytes(NullTerminatedString);
+ incrStreamedLen(NullTerminatedString.size());
+ } else if (isWriting()) {
+ // Truncate if we attempt to write too much.
+ StringRef S = Value.take_front(maxFieldLength() - 1);
+ if (auto EC = Writer->writeCString(S))
+ return EC;
+ } else {
+ if (auto EC = Reader->readCString(Value))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapGuid(GUID &Guid, const Twine &Comment) {
+ constexpr uint32_t GuidSize = 16;
+
+ if (isStreaming()) {
+ StringRef GuidSR =
+ StringRef((reinterpret_cast<const char *>(&Guid)), GuidSize);
+ emitComment(Comment);
+ Streamer->emitBytes(GuidSR);
+ incrStreamedLen(GuidSize);
+ return Error::success();
+ }
+
+ if (maxFieldLength() < GuidSize)
+ return make_error<CodeViewError>(cv_error_code::insufficient_buffer);
+
+ if (isWriting()) {
+ if (auto EC = Writer->writeBytes(Guid.Guid))
+ return EC;
+ } else {
+ ArrayRef<uint8_t> GuidBytes;
+ if (auto EC = Reader->readBytes(GuidBytes, GuidSize))
+ return EC;
+ memcpy(Guid.Guid, GuidBytes.data(), GuidSize);
+ }
+ return Error::success();
+}
+
+Error CodeViewRecordIO::mapStringZVectorZ(std::vector<StringRef> &Value,
+ const Twine &Comment) {
+
+ if (!isReading()) {
+ emitComment(Comment);
+ for (auto V : Value) {
+ if (auto EC = mapStringZ(V))
+ return EC;
+ }
+ uint8_t FinalZero = 0;
+ if (auto EC = mapInteger(FinalZero))
+ return EC;
+ } else {
+ StringRef S;
+ if (auto EC = mapStringZ(S))
+ return EC;
+ while (!S.empty()) {
+ Value.push_back(S);
+ if (auto EC = mapStringZ(S))
+ return EC;
+ };
+ }
+ return Error::success();
+}
+
+void CodeViewRecordIO::emitEncodedSignedInteger(const int64_t &Value,
+ const Twine &Comment) {
+ // FIXME: There are no test cases covering this function.
+ // This may be because we always consider enumerators to be unsigned.
+ // See FIXME at CodeViewDebug.cpp : CodeViewDebug::lowerTypeEnum.
+ if (Value >= std::numeric_limits<int8_t>::min()) {
+ Streamer->emitIntValue(LF_CHAR, 2);
+ emitComment(Comment);
+ Streamer->emitIntValue(Value, 1);
+ incrStreamedLen(3);
+ } else if (Value >= std::numeric_limits<int16_t>::min()) {
+ Streamer->emitIntValue(LF_SHORT, 2);
+ emitComment(Comment);
+ Streamer->emitIntValue(Value, 2);
+ incrStreamedLen(4);
+ } else if (Value >= std::numeric_limits<int32_t>::min()) {
+ Streamer->emitIntValue(LF_LONG, 2);
+ emitComment(Comment);
+ Streamer->emitIntValue(Value, 4);
+ incrStreamedLen(6);
+ } else {
+ Streamer->emitIntValue(LF_QUADWORD, 2);
+ emitComment(Comment);
+ Streamer->emitIntValue(Value, 4); // FIXME: Why not 8 (size of quadword)?
+ incrStreamedLen(6); // FIXME: Why not 10 (8 + 2)?
+ }
+}
+
+void CodeViewRecordIO::emitEncodedUnsignedInteger(const uint64_t &Value,
+ const Twine &Comment) {
+ if (Value < LF_NUMERIC) {
+ emitComment(Comment);
+ Streamer->emitIntValue(Value, 2);
+ incrStreamedLen(2);
+ } else if (Value <= std::numeric_limits<uint16_t>::max()) {
+ Streamer->emitIntValue(LF_USHORT, 2);
+ emitComment(Comment);
+ Streamer->emitIntValue(Value, 2);
+ incrStreamedLen(4);
+ } else if (Value <= std::numeric_limits<uint32_t>::max()) {
+ Streamer->emitIntValue(LF_ULONG, 2);
+ emitComment(Comment);
+ Streamer->emitIntValue(Value, 4);
+ incrStreamedLen(6);
+ } else {
+ // FIXME: There are no test cases covering this block.
+ Streamer->emitIntValue(LF_UQUADWORD, 2);
+ emitComment(Comment);
+ Streamer->emitIntValue(Value, 8);
+ incrStreamedLen(6); // FIXME: Why not 10 (8 + 2)?
+ }
+}
+
+Error CodeViewRecordIO::writeEncodedSignedInteger(const int64_t &Value) {
+ if (Value >= std::numeric_limits<int8_t>::min()) {
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_CHAR))
+ return EC;
+ if (auto EC = Writer->writeInteger<int8_t>(Value))
+ return EC;
+ } else if (Value >= std::numeric_limits<int16_t>::min()) {
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_SHORT))
+ return EC;
+ if (auto EC = Writer->writeInteger<int16_t>(Value))
+ return EC;
+ } else if (Value >= std::numeric_limits<int32_t>::min()) {
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_LONG))
+ return EC;
+ if (auto EC = Writer->writeInteger<int32_t>(Value))
+ return EC;
+ } else {
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_QUADWORD))
+ return EC;
+ if (auto EC = Writer->writeInteger(Value))
+ return EC;
+ }
+ return Error::success();
+}
+
+Error CodeViewRecordIO::writeEncodedUnsignedInteger(const uint64_t &Value) {
+ if (Value < LF_NUMERIC) {
+ if (auto EC = Writer->writeInteger<uint16_t>(Value))
+ return EC;
+ } else if (Value <= std::numeric_limits<uint16_t>::max()) {
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_USHORT))
+ return EC;
+ if (auto EC = Writer->writeInteger<uint16_t>(Value))
+ return EC;
+ } else if (Value <= std::numeric_limits<uint32_t>::max()) {
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_ULONG))
+ return EC;
+ if (auto EC = Writer->writeInteger<uint32_t>(Value))
+ return EC;
+ } else {
+ if (auto EC = Writer->writeInteger<uint16_t>(LF_UQUADWORD))
+ return EC;
+ if (auto EC = Writer->writeInteger(Value))
+ return EC;
+ }
+
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp
new file mode 100644
index 0000000000..c7b1c65f2f
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/ContinuationRecordBuilder.cpp
@@ -0,0 +1,251 @@
+#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+struct ContinuationRecord {
+ ulittle16_t Kind{uint16_t(TypeLeafKind::LF_INDEX)};
+ ulittle16_t Size{0};
+ ulittle32_t IndexRef{0xB0C0B0C0};
+};
+
+struct SegmentInjection {
+ SegmentInjection(TypeLeafKind Kind) { Prefix.RecordKind = Kind; }
+
+ ContinuationRecord Cont;
+ RecordPrefix Prefix;
+};
+} // namespace
+
+static void addPadding(BinaryStreamWriter &Writer) {
+ uint32_t Align = Writer.getOffset() % 4;
+ if (Align == 0)
+ return;
+
+ int PaddingBytes = 4 - Align;
+ while (PaddingBytes > 0) {
+ uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes);
+ cantFail(Writer.writeInteger(Pad));
+ --PaddingBytes;
+ }
+}
+
+static SegmentInjection InjectFieldList(TypeLeafKind::LF_FIELDLIST);
+static SegmentInjection InjectMethodOverloadList(TypeLeafKind::LF_METHODLIST);
+
+static constexpr uint32_t ContinuationLength = sizeof(ContinuationRecord);
+static constexpr uint32_t MaxSegmentLength =
+ MaxRecordLength - ContinuationLength;
+
+static inline TypeLeafKind getTypeLeafKind(ContinuationRecordKind CK) {
+ return (CK == ContinuationRecordKind::FieldList) ? LF_FIELDLIST
+ : LF_METHODLIST;
+}
+
+ContinuationRecordBuilder::ContinuationRecordBuilder()
+ : SegmentWriter(Buffer), Mapping(SegmentWriter) {}
+
+ContinuationRecordBuilder::~ContinuationRecordBuilder() {}
+
+void ContinuationRecordBuilder::begin(ContinuationRecordKind RecordKind) {
+ assert(!Kind.hasValue());
+ Kind = RecordKind;
+ Buffer.clear();
+ SegmentWriter.setOffset(0);
+ SegmentOffsets.clear();
+ SegmentOffsets.push_back(0);
+ assert(SegmentWriter.getOffset() == 0);
+ assert(SegmentWriter.getLength() == 0);
+
+ const SegmentInjection *FLI =
+ (RecordKind == ContinuationRecordKind::FieldList)
+ ? &InjectFieldList
+ : &InjectMethodOverloadList;
+ const uint8_t *FLIB = reinterpret_cast<const uint8_t *>(FLI);
+ InjectedSegmentBytes =
+ ArrayRef<uint8_t>(FLIB, FLIB + sizeof(SegmentInjection));
+
+ // Seed the first record with an appropriate record prefix.
+ RecordPrefix Prefix(getTypeLeafKind(RecordKind));
+ CVType Type(&Prefix, sizeof(Prefix));
+ cantFail(Mapping.visitTypeBegin(Type));
+
+ cantFail(SegmentWriter.writeObject(Prefix));
+}
+
+template <typename RecordType>
+void ContinuationRecordBuilder::writeMemberType(RecordType &Record) {
+ assert(Kind.hasValue());
+
+ uint32_t OriginalOffset = SegmentWriter.getOffset();
+ CVMemberRecord CVMR;
+ CVMR.Kind = static_cast<TypeLeafKind>(Record.getKind());
+
+ // Member Records aren't length-prefixed, they only have a 2-byte TypeLeafKind
+ // at the beginning.
+ cantFail(SegmentWriter.writeEnum(CVMR.Kind));
+
+ // Let the Mapping handle the rest.
+ cantFail(Mapping.visitMemberBegin(CVMR));
+ cantFail(Mapping.visitKnownMember(CVMR, Record));
+ cantFail(Mapping.visitMemberEnd(CVMR));
+
+ // Make sure it's padded to 4 bytes.
+ addPadding(SegmentWriter);
+ assert(getCurrentSegmentLength() % 4 == 0);
+
+ // The maximum length of a single segment is 64KB minus the size to insert a
+ // continuation. So if we are over that, inject a continuation between the
+ // previous member and the member that was just written, then end the previous
+ // segment after the continuation and begin a new one with the just-written
+ // member.
+ if (getCurrentSegmentLength() > MaxSegmentLength) {
+ // We need to inject some bytes before the member we just wrote but after
+ // the previous member. Save off the length of the member we just wrote so
+ // that we can do validate it.
+ uint32_t MemberLength = SegmentWriter.getOffset() - OriginalOffset;
+ (void) MemberLength;
+ insertSegmentEnd(OriginalOffset);
+ // Since this member now becomes a new top-level record, it should have
+ // gotten a RecordPrefix injected, and that RecordPrefix + the member we
+ // just wrote should now constitute the entirety of the current "new"
+ // segment.
+ assert(getCurrentSegmentLength() == MemberLength + sizeof(RecordPrefix));
+ }
+
+ assert(getCurrentSegmentLength() % 4 == 0);
+ assert(getCurrentSegmentLength() <= MaxSegmentLength);
+}
+
+uint32_t ContinuationRecordBuilder::getCurrentSegmentLength() const {
+ return SegmentWriter.getOffset() - SegmentOffsets.back();
+}
+
+void ContinuationRecordBuilder::insertSegmentEnd(uint32_t Offset) {
+ uint32_t SegmentBegin = SegmentOffsets.back();
+ (void)SegmentBegin;
+ assert(Offset > SegmentBegin);
+ assert(Offset - SegmentBegin <= MaxSegmentLength);
+
+ // We need to make space for the continuation record. For now we can't fill
+ // out the length or the TypeIndex of the back-reference, but we need the
+ // space to at least be there.
+ Buffer.insert(Offset, InjectedSegmentBytes);
+
+ uint32_t NewSegmentBegin = Offset + ContinuationLength;
+ uint32_t SegmentLength = NewSegmentBegin - SegmentOffsets.back();
+ (void) SegmentLength;
+
+ assert(SegmentLength % 4 == 0);
+ assert(SegmentLength <= MaxRecordLength);
+ SegmentOffsets.push_back(NewSegmentBegin);
+
+ // Seek to the end so that we can keep writing against the new segment.
+ SegmentWriter.setOffset(SegmentWriter.getLength());
+ assert(SegmentWriter.bytesRemaining() == 0);
+}
+
+CVType ContinuationRecordBuilder::createSegmentRecord(
+ uint32_t OffBegin, uint32_t OffEnd, Optional<TypeIndex> RefersTo) {
+ assert(OffEnd - OffBegin <= USHRT_MAX);
+
+ MutableArrayRef<uint8_t> Data = Buffer.data();
+ Data = Data.slice(OffBegin, OffEnd - OffBegin);
+
+ // Write the length to the RecordPrefix, making sure it does not include
+ // sizeof(RecordPrefix.Length)
+ RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(Data.data());
+ Prefix->RecordLen = Data.size() - sizeof(RecordPrefix::RecordLen);
+
+ if (RefersTo.hasValue()) {
+ auto Continuation = Data.take_back(ContinuationLength);
+ ContinuationRecord *CR =
+ reinterpret_cast<ContinuationRecord *>(Continuation.data());
+ assert(CR->Kind == TypeLeafKind::LF_INDEX);
+ assert(CR->IndexRef == 0xB0C0B0C0);
+ CR->IndexRef = RefersTo->getIndex();
+ }
+
+ return CVType(Data);
+}
+
+std::vector<CVType> ContinuationRecordBuilder::end(TypeIndex Index) {
+ RecordPrefix Prefix(getTypeLeafKind(*Kind));
+ CVType Type(&Prefix, sizeof(Prefix));
+ cantFail(Mapping.visitTypeEnd(Type));
+
+ // We're now done, and we have a series of segments each beginning at an
+ // offset specified in the SegmentOffsets array. We now need to iterate
+ // over each segment and post-process them in the following two ways:
+ // 1) Each top-level record has a RecordPrefix whose type is either
+ // LF_FIELDLIST or LF_METHODLIST, but the Length field is still 0.
+ // Those should all be set to the correct length now.
+ // 2) Each continuation record has an IndexRef field which we set to the
+ // magic value 0xB0C0B0C0. Now that the caller has told us the TypeIndex
+ // they want this sequence to start from, we can go through and update
+ // each one.
+ //
+ // Logically, the sequence of records we've built up looks like this:
+ //
+ // SegmentOffsets[0]: <Length> (Initially: uninitialized)
+ // SegmentOffsets[0]+2: LF_FIELDLIST
+ // SegmentOffsets[0]+4: Member[0]
+ // SegmentOffsets[0]+?: ...
+ // SegmentOffsets[0]+?: Member[4]
+ // SegmentOffsets[1]-8: LF_INDEX
+ // SegmentOffsets[1]-6: 0
+ // SegmentOffsets[1]-4: <Type Index of Next Record> (Initially: 0xB0C0B0C0)
+ //
+ // SegmentOffsets[1]: <Length> (Initially: uninitialized)
+ // SegmentOffsets[1]+2: LF_FIELDLIST
+ // SegmentOffsets[1]+4: Member[0]
+ // SegmentOffsets[1]+?: ...
+ // SegmentOffsets[1]+?: Member[s]
+ // SegmentOffsets[2]-8: LF_INDEX
+ // SegmentOffsets[2]-6: 0
+ // SegmentOffsets[2]-4: <Type Index of Next Record> (Initially: 0xB0C0B0C0)
+ //
+ // ...
+ //
+ // SegmentOffsets[N]: <Length> (Initially: uninitialized)
+ // SegmentOffsets[N]+2: LF_FIELDLIST
+ // SegmentOffsets[N]+4: Member[0]
+ // SegmentOffsets[N]+?: ...
+ // SegmentOffsets[N]+?: Member[t]
+ //
+ // And this is the way we have laid them out in the serialization buffer. But
+ // we cannot actually commit them to the underlying stream this way, due to
+ // the topological sorting requirement of a type stream (specifically,
+ // TypeIndex references can only point backwards, not forwards). So the
+ // sequence that we return to the caller contains the records in reverse
+ // order, which is the proper order for committing the serialized records.
+
+ std::vector<CVType> Types;
+ Types.reserve(SegmentOffsets.size());
+
+ auto SO = makeArrayRef(SegmentOffsets);
+
+ uint32_t End = SegmentWriter.getOffset();
+
+ Optional<TypeIndex> RefersTo;
+ for (uint32_t Offset : reverse(SO)) {
+ Types.push_back(createSegmentRecord(Offset, End, RefersTo));
+
+ End = Offset;
+ RefersTo = Index++;
+ }
+
+ Kind.reset();
+ return Types;
+}
+
+// Explicitly instantiate the member function for each known type so that we can
+// implement this in the cpp file.
+#define TYPE_RECORD(EnumName, EnumVal, Name)
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#define MEMBER_RECORD(EnumName, EnumVal, Name) \
+ template void llvm::codeview::ContinuationRecordBuilder::writeMemberType( \
+ Name##Record &Record);
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp
new file mode 100644
index 0000000000..3d28bac00c
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugChecksumsSubsection.cpp
@@ -0,0 +1,115 @@
+//===- DebugChecksumsSubsection.cpp ---------------------------------------===//
+//
+// 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/DebugChecksumsSubsection.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MathExtras.h"
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+struct FileChecksumEntryHeader {
+ using ulittle32_t = support::ulittle32_t;
+
+ ulittle32_t FileNameOffset; // Byte offset of filename in global string table.
+ uint8_t ChecksumSize; // Number of bytes of checksum.
+ uint8_t ChecksumKind; // FileChecksumKind
+ // Checksum bytes follow.
+};
+
+Error VarStreamArrayExtractor<FileChecksumEntry>::
+operator()(BinaryStreamRef Stream, uint32_t &Len, FileChecksumEntry &Item) {
+ BinaryStreamReader Reader(Stream);
+
+ const FileChecksumEntryHeader *Header;
+ if (auto EC = Reader.readObject(Header))
+ return EC;
+
+ Item.FileNameOffset = Header->FileNameOffset;
+ Item.Kind = static_cast<FileChecksumKind>(Header->ChecksumKind);
+ if (auto EC = Reader.readBytes(Item.Checksum, Header->ChecksumSize))
+ return EC;
+
+ Len = alignTo(Header->ChecksumSize + sizeof(FileChecksumEntryHeader), 4);
+ return Error::success();
+}
+
+Error DebugChecksumsSubsectionRef::initialize(BinaryStreamReader Reader) {
+ if (auto EC = Reader.readArray(Checksums, Reader.bytesRemaining()))
+ return EC;
+
+ return Error::success();
+}
+
+Error DebugChecksumsSubsectionRef::initialize(BinaryStreamRef Section) {
+ BinaryStreamReader Reader(Section);
+ return initialize(Reader);
+}
+
+DebugChecksumsSubsection::DebugChecksumsSubsection(
+ DebugStringTableSubsection &Strings)
+ : DebugSubsection(DebugSubsectionKind::FileChecksums), Strings(Strings) {}
+
+void DebugChecksumsSubsection::addChecksum(StringRef FileName,
+ FileChecksumKind Kind,
+ ArrayRef<uint8_t> Bytes) {
+ FileChecksumEntry Entry;
+ if (!Bytes.empty()) {
+ uint8_t *Copy = Storage.Allocate<uint8_t>(Bytes.size());
+ ::memcpy(Copy, Bytes.data(), Bytes.size());
+ Entry.Checksum = makeArrayRef(Copy, Bytes.size());
+ }
+
+ Entry.FileNameOffset = Strings.insert(FileName);
+ Entry.Kind = Kind;
+ Checksums.push_back(Entry);
+
+ // This maps the offset of this string in the string table to the offset
+ // of this checksum entry in the checksum buffer.
+ OffsetMap[Entry.FileNameOffset] = SerializedSize;
+ assert(SerializedSize % 4 == 0);
+
+ uint32_t Len = alignTo(sizeof(FileChecksumEntryHeader) + Bytes.size(), 4);
+ SerializedSize += Len;
+}
+
+uint32_t DebugChecksumsSubsection::calculateSerializedSize() const {
+ return SerializedSize;
+}
+
+Error DebugChecksumsSubsection::commit(BinaryStreamWriter &Writer) const {
+ for (const auto &FC : Checksums) {
+ FileChecksumEntryHeader Header;
+ Header.ChecksumKind = uint8_t(FC.Kind);
+ Header.ChecksumSize = FC.Checksum.size();
+ Header.FileNameOffset = FC.FileNameOffset;
+ if (auto EC = Writer.writeObject(Header))
+ return EC;
+ if (auto EC = Writer.writeArray(makeArrayRef(FC.Checksum)))
+ return EC;
+ if (auto EC = Writer.padToAlignment(4))
+ return EC;
+ }
+ return Error::success();
+}
+
+uint32_t DebugChecksumsSubsection::mapChecksumOffset(StringRef FileName) const {
+ uint32_t Offset = Strings.getIdForString(FileName);
+ auto Iter = OffsetMap.find(Offset);
+ assert(Iter != OffsetMap.end());
+ return Iter->second;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugCrossExSubsection.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugCrossExSubsection.cpp
new file mode 100644
index 0000000000..b23410409f
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugCrossExSubsection.cpp
@@ -0,0 +1,52 @@
+//===- DebugCrossExSubsection.cpp -----------------------------------------===//
+//
+// 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/DebugCrossExSubsection.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error DebugCrossModuleExportsSubsectionRef::initialize(
+ BinaryStreamReader Reader) {
+ if (Reader.bytesRemaining() % sizeof(CrossModuleExport) != 0)
+ return make_error<CodeViewError>(
+ cv_error_code::corrupt_record,
+ "Cross Scope Exports section is an invalid size!");
+
+ uint32_t Size = Reader.bytesRemaining() / sizeof(CrossModuleExport);
+ return Reader.readArray(References, Size);
+}
+
+Error DebugCrossModuleExportsSubsectionRef::initialize(BinaryStreamRef Stream) {
+ BinaryStreamReader Reader(Stream);
+ return initialize(Reader);
+}
+
+void DebugCrossModuleExportsSubsection::addMapping(uint32_t Local,
+ uint32_t Global) {
+ Mappings[Local] = Global;
+}
+
+uint32_t DebugCrossModuleExportsSubsection::calculateSerializedSize() const {
+ return Mappings.size() * sizeof(CrossModuleExport);
+}
+
+Error DebugCrossModuleExportsSubsection::commit(
+ BinaryStreamWriter &Writer) const {
+ for (const auto &M : Mappings) {
+ if (auto EC = Writer.writeInteger(M.first))
+ return EC;
+ if (auto EC = Writer.writeInteger(M.second))
+ return EC;
+ }
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp
new file mode 100644
index 0000000000..dbadafd3aa
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugCrossImpSubsection.cpp
@@ -0,0 +1,96 @@
+//===- DebugCrossImpSubsection.cpp ----------------------------------------===//
+//
+// 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/DebugCrossImpSubsection.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cstdint>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error VarStreamArrayExtractor<CrossModuleImportItem>::
+operator()(BinaryStreamRef Stream, uint32_t &Len,
+ codeview::CrossModuleImportItem &Item) {
+ BinaryStreamReader Reader(Stream);
+ if (Reader.bytesRemaining() < sizeof(CrossModuleImport))
+ return make_error<CodeViewError>(
+ cv_error_code::insufficient_buffer,
+ "Not enough bytes for a Cross Module Import Header!");
+ if (auto EC = Reader.readObject(Item.Header))
+ return EC;
+ if (Reader.bytesRemaining() < Item.Header->Count * sizeof(uint32_t))
+ return make_error<CodeViewError>(
+ cv_error_code::insufficient_buffer,
+ "Not enough to read specified number of Cross Module References!");
+ if (auto EC = Reader.readArray(Item.Imports, Item.Header->Count))
+ return EC;
+ return Error::success();
+}
+
+Error DebugCrossModuleImportsSubsectionRef::initialize(
+ BinaryStreamReader Reader) {
+ return Reader.readArray(References, Reader.bytesRemaining());
+}
+
+Error DebugCrossModuleImportsSubsectionRef::initialize(BinaryStreamRef Stream) {
+ BinaryStreamReader Reader(Stream);
+ return initialize(Reader);
+}
+
+void DebugCrossModuleImportsSubsection::addImport(StringRef Module,
+ uint32_t ImportId) {
+ Strings.insert(Module);
+ std::vector<support::ulittle32_t> Targets = {support::ulittle32_t(ImportId)};
+ auto Result = Mappings.insert(std::make_pair(Module, Targets));
+ if (!Result.second)
+ Result.first->getValue().push_back(Targets[0]);
+}
+
+uint32_t DebugCrossModuleImportsSubsection::calculateSerializedSize() const {
+ uint32_t Size = 0;
+ for (const auto &Item : Mappings) {
+ Size += sizeof(CrossModuleImport);
+ Size += sizeof(support::ulittle32_t) * Item.second.size();
+ }
+ return Size;
+}
+
+Error DebugCrossModuleImportsSubsection::commit(
+ BinaryStreamWriter &Writer) const {
+ using T = decltype(&*Mappings.begin());
+ std::vector<T> Ids;
+ Ids.reserve(Mappings.size());
+
+ for (const auto &M : Mappings)
+ Ids.push_back(&M);
+
+ llvm::sort(Ids, [this](const T &L1, const T &L2) {
+ return Strings.getIdForString(L1->getKey()) <
+ Strings.getIdForString(L2->getKey());
+ });
+
+ for (const auto &Item : Ids) {
+ CrossModuleImport Imp;
+ Imp.ModuleNameOffset = Strings.getIdForString(Item->getKey());
+ Imp.Count = Item->getValue().size();
+ if (auto EC = Writer.writeObject(Imp))
+ return EC;
+ if (auto EC = Writer.writeArray(makeArrayRef(Item->getValue())))
+ return EC;
+ }
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp
new file mode 100644
index 0000000000..9bc69abea1
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugFrameDataSubsection.cpp
@@ -0,0 +1,60 @@
+//===- DebugFrameDataSubsection.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/DebugFrameDataSubsection.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error DebugFrameDataSubsectionRef::initialize(BinaryStreamReader Reader) {
+ if (Reader.bytesRemaining() % sizeof(FrameData) != 0) {
+ if (auto EC = Reader.readObject(RelocPtr))
+ return EC;
+ }
+
+ if (Reader.bytesRemaining() % sizeof(FrameData) != 0)
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Invalid frame data record format!");
+
+ uint32_t Count = Reader.bytesRemaining() / sizeof(FrameData);
+ if (auto EC = Reader.readArray(Frames, Count))
+ return EC;
+ return Error::success();
+}
+
+Error DebugFrameDataSubsectionRef::initialize(BinaryStreamRef Section) {
+ BinaryStreamReader Reader(Section);
+ return initialize(Reader);
+}
+
+uint32_t DebugFrameDataSubsection::calculateSerializedSize() const {
+ uint32_t Size = sizeof(FrameData) * Frames.size();
+ if (IncludeRelocPtr)
+ Size += sizeof(uint32_t);
+ return Size;
+}
+
+Error DebugFrameDataSubsection::commit(BinaryStreamWriter &Writer) const {
+ if (IncludeRelocPtr) {
+ if (auto EC = Writer.writeInteger<uint32_t>(0))
+ return EC;
+ }
+
+ std::vector<FrameData> SortedFrames(Frames.begin(), Frames.end());
+ llvm::sort(SortedFrames, [](const FrameData &LHS, const FrameData &RHS) {
+ return LHS.RvaStart < RHS.RvaStart;
+ });
+ if (auto EC = Writer.writeArray(makeArrayRef(SortedFrames)))
+ return EC;
+ return Error::success();
+}
+
+void DebugFrameDataSubsection::addFrameData(const FrameData &Frame) {
+ Frames.push_back(Frame);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp
new file mode 100644
index 0000000000..48ec7e4ecd
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugInlineeLinesSubsection.cpp
@@ -0,0 +1,125 @@
+//===- DebugInlineeLinesSubsection.cpp ------------------------------------===//
+//
+// 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/DebugInlineeLinesSubsection.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <cassert>
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error VarStreamArrayExtractor<InlineeSourceLine>::
+operator()(BinaryStreamRef Stream, uint32_t &Len, InlineeSourceLine &Item) {
+ BinaryStreamReader Reader(Stream);
+
+ if (auto EC = Reader.readObject(Item.Header))
+ return EC;
+
+ if (HasExtraFiles) {
+ uint32_t ExtraFileCount;
+ if (auto EC = Reader.readInteger(ExtraFileCount))
+ return EC;
+ if (auto EC = Reader.readArray(Item.ExtraFiles, ExtraFileCount))
+ return EC;
+ }
+
+ Len = Reader.getOffset();
+ return Error::success();
+}
+
+DebugInlineeLinesSubsectionRef::DebugInlineeLinesSubsectionRef()
+ : DebugSubsectionRef(DebugSubsectionKind::InlineeLines) {}
+
+Error DebugInlineeLinesSubsectionRef::initialize(BinaryStreamReader Reader) {
+ if (auto EC = Reader.readEnum(Signature))
+ return EC;
+
+ Lines.getExtractor().HasExtraFiles = hasExtraFiles();
+ if (auto EC = Reader.readArray(Lines, Reader.bytesRemaining()))
+ return EC;
+
+ assert(Reader.bytesRemaining() == 0);
+ return Error::success();
+}
+
+bool DebugInlineeLinesSubsectionRef::hasExtraFiles() const {
+ return Signature == InlineeLinesSignature::ExtraFiles;
+}
+
+DebugInlineeLinesSubsection::DebugInlineeLinesSubsection(
+ DebugChecksumsSubsection &Checksums, bool HasExtraFiles)
+ : DebugSubsection(DebugSubsectionKind::InlineeLines), Checksums(Checksums),
+ HasExtraFiles(HasExtraFiles) {}
+
+uint32_t DebugInlineeLinesSubsection::calculateSerializedSize() const {
+ // 4 bytes for the signature
+ uint32_t Size = sizeof(InlineeLinesSignature);
+
+ // one header for each entry.
+ Size += Entries.size() * sizeof(InlineeSourceLineHeader);
+ if (HasExtraFiles) {
+ // If extra files are enabled, one count for each entry.
+ Size += Entries.size() * sizeof(uint32_t);
+
+ // And one file id for each file.
+ Size += ExtraFileCount * sizeof(uint32_t);
+ }
+ assert(Size % 4 == 0);
+ return Size;
+}
+
+Error DebugInlineeLinesSubsection::commit(BinaryStreamWriter &Writer) const {
+ InlineeLinesSignature Sig = InlineeLinesSignature::Normal;
+ if (HasExtraFiles)
+ Sig = InlineeLinesSignature::ExtraFiles;
+
+ if (auto EC = Writer.writeEnum(Sig))
+ return EC;
+
+ for (const auto &E : Entries) {
+ if (auto EC = Writer.writeObject(E.Header))
+ return EC;
+
+ if (!HasExtraFiles)
+ continue;
+
+ if (auto EC = Writer.writeInteger<uint32_t>(E.ExtraFiles.size()))
+ return EC;
+ if (auto EC = Writer.writeArray(makeArrayRef(E.ExtraFiles)))
+ return EC;
+ }
+
+ return Error::success();
+}
+
+void DebugInlineeLinesSubsection::addExtraFile(StringRef FileName) {
+ uint32_t Offset = Checksums.mapChecksumOffset(FileName);
+
+ auto &Entry = Entries.back();
+ Entry.ExtraFiles.push_back(ulittle32_t(Offset));
+ ++ExtraFileCount;
+}
+
+void DebugInlineeLinesSubsection::addInlineSite(TypeIndex FuncId,
+ StringRef FileName,
+ uint32_t SourceLine) {
+ uint32_t Offset = Checksums.mapChecksumOffset(FileName);
+
+ Entries.emplace_back();
+ auto &Entry = Entries.back();
+ Entry.Header.FileID = Offset;
+ Entry.Header.SourceLineNum = SourceLine;
+ Entry.Header.Inlinee = FuncId;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp
new file mode 100644
index 0000000000..ea16c0a6c6
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugLinesSubsection.cpp
@@ -0,0 +1,160 @@
+//===- DebugLinesSubsection.cpp -------------------------------------------===//
+//
+// 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/DebugLinesSubsection.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Error.h"
+#include <cassert>
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error LineColumnExtractor::operator()(BinaryStreamRef Stream, uint32_t &Len,
+ LineColumnEntry &Item) {
+ const LineBlockFragmentHeader *BlockHeader;
+ BinaryStreamReader Reader(Stream);
+ if (auto EC = Reader.readObject(BlockHeader))
+ return EC;
+ bool HasColumn = Header->Flags & uint16_t(LF_HaveColumns);
+ uint32_t LineInfoSize =
+ BlockHeader->NumLines *
+ (sizeof(LineNumberEntry) + (HasColumn ? sizeof(ColumnNumberEntry) : 0));
+ if (BlockHeader->BlockSize < sizeof(LineBlockFragmentHeader))
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Invalid line block record size");
+ uint32_t Size = BlockHeader->BlockSize - sizeof(LineBlockFragmentHeader);
+ if (LineInfoSize > Size)
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Invalid line block record size");
+ // The value recorded in BlockHeader->BlockSize includes the size of
+ // LineBlockFragmentHeader.
+ Len = BlockHeader->BlockSize;
+ Item.NameIndex = BlockHeader->NameIndex;
+ if (auto EC = Reader.readArray(Item.LineNumbers, BlockHeader->NumLines))
+ return EC;
+ if (HasColumn) {
+ if (auto EC = Reader.readArray(Item.Columns, BlockHeader->NumLines))
+ return EC;
+ }
+ return Error::success();
+}
+
+DebugLinesSubsectionRef::DebugLinesSubsectionRef()
+ : DebugSubsectionRef(DebugSubsectionKind::Lines) {}
+
+Error DebugLinesSubsectionRef::initialize(BinaryStreamReader Reader) {
+ if (auto EC = Reader.readObject(Header))
+ return EC;
+
+ LinesAndColumns.getExtractor().Header = Header;
+ if (auto EC = Reader.readArray(LinesAndColumns, Reader.bytesRemaining()))
+ return EC;
+
+ return Error::success();
+}
+
+bool DebugLinesSubsectionRef::hasColumnInfo() const {
+ return !!(Header->Flags & LF_HaveColumns);
+}
+
+DebugLinesSubsection::DebugLinesSubsection(DebugChecksumsSubsection &Checksums,
+ DebugStringTableSubsection &Strings)
+ : DebugSubsection(DebugSubsectionKind::Lines), Checksums(Checksums) {}
+
+void DebugLinesSubsection::createBlock(StringRef FileName) {
+ uint32_t Offset = Checksums.mapChecksumOffset(FileName);
+
+ Blocks.emplace_back(Offset);
+}
+
+void DebugLinesSubsection::addLineInfo(uint32_t Offset, const LineInfo &Line) {
+ Block &B = Blocks.back();
+ LineNumberEntry LNE;
+ LNE.Flags = Line.getRawData();
+ LNE.Offset = Offset;
+ B.Lines.push_back(LNE);
+}
+
+void DebugLinesSubsection::addLineAndColumnInfo(uint32_t Offset,
+ const LineInfo &Line,
+ uint32_t ColStart,
+ uint32_t ColEnd) {
+ Block &B = Blocks.back();
+ assert(B.Lines.size() == B.Columns.size());
+
+ addLineInfo(Offset, Line);
+ ColumnNumberEntry CNE;
+ CNE.StartColumn = ColStart;
+ CNE.EndColumn = ColEnd;
+ B.Columns.push_back(CNE);
+}
+
+Error DebugLinesSubsection::commit(BinaryStreamWriter &Writer) const {
+ LineFragmentHeader Header;
+ Header.CodeSize = CodeSize;
+ Header.Flags = hasColumnInfo() ? LF_HaveColumns : 0;
+ Header.RelocOffset = RelocOffset;
+ Header.RelocSegment = RelocSegment;
+
+ if (auto EC = Writer.writeObject(Header))
+ return EC;
+
+ for (const auto &B : Blocks) {
+ LineBlockFragmentHeader BlockHeader;
+ assert(B.Lines.size() == B.Columns.size() || B.Columns.empty());
+
+ BlockHeader.NumLines = B.Lines.size();
+ BlockHeader.BlockSize = sizeof(LineBlockFragmentHeader);
+ BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(LineNumberEntry);
+ if (hasColumnInfo())
+ BlockHeader.BlockSize += BlockHeader.NumLines * sizeof(ColumnNumberEntry);
+ BlockHeader.NameIndex = B.ChecksumBufferOffset;
+ if (auto EC = Writer.writeObject(BlockHeader))
+ return EC;
+
+ if (auto EC = Writer.writeArray(makeArrayRef(B.Lines)))
+ return EC;
+
+ if (hasColumnInfo()) {
+ if (auto EC = Writer.writeArray(makeArrayRef(B.Columns)))
+ return EC;
+ }
+ }
+ return Error::success();
+}
+
+uint32_t DebugLinesSubsection::calculateSerializedSize() const {
+ uint32_t Size = sizeof(LineFragmentHeader);
+ for (const auto &B : Blocks) {
+ Size += sizeof(LineBlockFragmentHeader);
+ Size += B.Lines.size() * sizeof(LineNumberEntry);
+ if (hasColumnInfo())
+ Size += B.Columns.size() * sizeof(ColumnNumberEntry);
+ }
+ return Size;
+}
+
+void DebugLinesSubsection::setRelocationAddress(uint16_t Segment,
+ uint32_t Offset) {
+ RelocOffset = Offset;
+ RelocSegment = Segment;
+}
+
+void DebugLinesSubsection::setCodeSize(uint32_t Size) { CodeSize = Size; }
+
+void DebugLinesSubsection::setFlags(LineFlags Flags) { this->Flags = Flags; }
+
+bool DebugLinesSubsection::hasColumnInfo() const {
+ return Flags & LF_HaveColumns;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp
new file mode 100644
index 0000000000..6334274991
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugStringTableSubsection.cpp
@@ -0,0 +1,107 @@
+//===- DebugStringTableSubsection.cpp - CodeView String Table -------------===//
+//
+// 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/DebugStringTableSubsection.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+DebugStringTableSubsectionRef::DebugStringTableSubsectionRef()
+ : DebugSubsectionRef(DebugSubsectionKind::StringTable) {}
+
+Error DebugStringTableSubsectionRef::initialize(BinaryStreamRef Contents) {
+ Stream = Contents;
+ return Error::success();
+}
+
+Error DebugStringTableSubsectionRef::initialize(BinaryStreamReader &Reader) {
+ return Reader.readStreamRef(Stream);
+}
+
+Expected<StringRef>
+DebugStringTableSubsectionRef::getString(uint32_t Offset) const {
+ BinaryStreamReader Reader(Stream);
+ Reader.setOffset(Offset);
+ StringRef Result;
+ if (auto EC = Reader.readCString(Result))
+ return std::move(EC);
+ return Result;
+}
+
+DebugStringTableSubsection::DebugStringTableSubsection()
+ : DebugSubsection(DebugSubsectionKind::StringTable) {}
+
+uint32_t DebugStringTableSubsection::insert(StringRef S) {
+ auto P = StringToId.insert({S, StringSize});
+
+ // If a given string didn't exist in the string table, we want to increment
+ // the string table size and insert it into the reverse lookup.
+ if (P.second) {
+ IdToString.insert({P.first->getValue(), P.first->getKey()});
+ StringSize += S.size() + 1; // +1 for '\0'
+ }
+
+ return P.first->second;
+}
+
+uint32_t DebugStringTableSubsection::calculateSerializedSize() const {
+ return StringSize;
+}
+
+Error DebugStringTableSubsection::commit(BinaryStreamWriter &Writer) const {
+ uint32_t Begin = Writer.getOffset();
+ uint32_t End = Begin + StringSize;
+
+ // Write a null string at the beginning.
+ if (auto EC = Writer.writeCString(StringRef()))
+ return EC;
+
+ for (auto &Pair : StringToId) {
+ StringRef S = Pair.getKey();
+ uint32_t Offset = Begin + Pair.getValue();
+ Writer.setOffset(Offset);
+ if (auto EC = Writer.writeCString(S))
+ return EC;
+ assert(Writer.getOffset() <= End);
+ }
+
+ Writer.setOffset(End);
+ assert((End - Begin) == StringSize);
+ return Error::success();
+}
+
+uint32_t DebugStringTableSubsection::size() const { return StringToId.size(); }
+
+std::vector<uint32_t> DebugStringTableSubsection::sortedIds() const {
+ std::vector<uint32_t> Result;
+ Result.reserve(IdToString.size());
+ for (const auto &Entry : IdToString)
+ Result.push_back(Entry.first);
+ llvm::sort(Result);
+ return Result;
+}
+
+uint32_t DebugStringTableSubsection::getIdForString(StringRef S) const {
+ auto Iter = StringToId.find(S);
+ assert(Iter != StringToId.end());
+ return Iter->second;
+}
+
+StringRef DebugStringTableSubsection::getStringForId(uint32_t Id) const {
+ auto Iter = IdToString.find(Id);
+ assert(Iter != IdToString.end());
+ return Iter->second;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSubsection.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSubsection.cpp
new file mode 100644
index 0000000000..3f93463fe6
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSubsection.cpp
@@ -0,0 +1,15 @@
+//===- DebugSubsection.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/DebugSubsection.h"
+
+using namespace llvm::codeview;
+
+DebugSubsectionRef::~DebugSubsectionRef() {}
+
+DebugSubsection::~DebugSubsection() {}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp
new file mode 100644
index 0000000000..3c8a301014
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSubsectionRecord.cpp
@@ -0,0 +1,94 @@
+//===- DebugSubsectionRecord.cpp ------------------------------------------===//
+//
+// 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/DebugSubsectionRecord.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsection.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MathExtras.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+DebugSubsectionRecord::DebugSubsectionRecord() = default;
+
+DebugSubsectionRecord::DebugSubsectionRecord(DebugSubsectionKind Kind,
+ BinaryStreamRef Data)
+ : Kind(Kind), Data(Data) {}
+
+Error DebugSubsectionRecord::initialize(BinaryStreamRef Stream,
+ DebugSubsectionRecord &Info) {
+ const DebugSubsectionHeader *Header;
+ BinaryStreamReader Reader(Stream);
+ if (auto EC = Reader.readObject(Header))
+ return EC;
+
+ DebugSubsectionKind Kind =
+ static_cast<DebugSubsectionKind>(uint32_t(Header->Kind));
+ if (auto EC = Reader.readStreamRef(Info.Data, Header->Length))
+ return EC;
+ Info.Kind = Kind;
+ return Error::success();
+}
+
+uint32_t DebugSubsectionRecord::getRecordLength() const {
+ return sizeof(DebugSubsectionHeader) + Data.getLength();
+}
+
+DebugSubsectionKind DebugSubsectionRecord::kind() const { return Kind; }
+
+BinaryStreamRef DebugSubsectionRecord::getRecordData() const { return Data; }
+
+DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder(
+ std::shared_ptr<DebugSubsection> Subsection)
+ : Subsection(std::move(Subsection)) {}
+
+DebugSubsectionRecordBuilder::DebugSubsectionRecordBuilder(
+ const DebugSubsectionRecord &Contents)
+ : Contents(Contents) {}
+
+uint32_t DebugSubsectionRecordBuilder::calculateSerializedLength() const {
+ uint32_t DataSize = Subsection ? Subsection->calculateSerializedSize()
+ : Contents.getRecordData().getLength();
+ // The length of the entire subsection is always padded to 4 bytes,
+ // regardless of the container kind.
+ return sizeof(DebugSubsectionHeader) + alignTo(DataSize, 4);
+}
+
+Error DebugSubsectionRecordBuilder::commit(BinaryStreamWriter &Writer,
+ CodeViewContainer Container) const {
+ assert(Writer.getOffset() % alignOf(Container) == 0 &&
+ "Debug Subsection not properly aligned");
+
+ DebugSubsectionHeader Header;
+ Header.Kind = uint32_t(Subsection ? Subsection->kind() : Contents.kind());
+ // The value written into the Header's Length field is only padded to the
+ // container's alignment
+ uint32_t DataSize = Subsection ? Subsection->calculateSerializedSize()
+ : Contents.getRecordData().getLength();
+ Header.Length = alignTo(DataSize, alignOf(Container));
+
+ if (auto EC = Writer.writeObject(Header))
+ return EC;
+ if (Subsection) {
+ if (auto EC = Subsection->commit(Writer))
+ return EC;
+ } else {
+ if (auto EC = Writer.writeStreamRef(Contents.getRecordData()))
+ return EC;
+ }
+ if (auto EC = Writer.padToAlignment(4))
+ return EC;
+
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp
new file mode 100644
index 0000000000..7968b6a2d7
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSubsectionVisitor.cpp
@@ -0,0 +1,94 @@
+//===- DebugSubsectionVisitor.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/DebugSubsectionVisitor.h"
+
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugCrossExSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugCrossImpSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+#include "llvm/DebugInfo/CodeView/DebugSymbolRVASubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugSymbolsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugUnknownSubsection.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamRef.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error llvm::codeview::visitDebugSubsection(
+ const DebugSubsectionRecord &R, DebugSubsectionVisitor &V,
+ const StringsAndChecksumsRef &State) {
+ BinaryStreamReader Reader(R.getRecordData());
+ switch (R.kind()) {
+ case DebugSubsectionKind::Lines: {
+ DebugLinesSubsectionRef Fragment;
+ if (auto EC = Fragment.initialize(Reader))
+ return EC;
+
+ return V.visitLines(Fragment, State);
+ }
+ case DebugSubsectionKind::FileChecksums: {
+ DebugChecksumsSubsectionRef Fragment;
+ if (auto EC = Fragment.initialize(Reader))
+ return EC;
+
+ return V.visitFileChecksums(Fragment, State);
+ }
+ case DebugSubsectionKind::InlineeLines: {
+ DebugInlineeLinesSubsectionRef Fragment;
+ if (auto EC = Fragment.initialize(Reader))
+ return EC;
+ return V.visitInlineeLines(Fragment, State);
+ }
+ case DebugSubsectionKind::CrossScopeExports: {
+ DebugCrossModuleExportsSubsectionRef Section;
+ if (auto EC = Section.initialize(Reader))
+ return EC;
+ return V.visitCrossModuleExports(Section, State);
+ }
+ case DebugSubsectionKind::CrossScopeImports: {
+ DebugCrossModuleImportsSubsectionRef Section;
+ if (auto EC = Section.initialize(Reader))
+ return EC;
+ return V.visitCrossModuleImports(Section, State);
+ }
+ case DebugSubsectionKind::Symbols: {
+ DebugSymbolsSubsectionRef Section;
+ if (auto EC = Section.initialize(Reader))
+ return EC;
+ return V.visitSymbols(Section, State);
+ }
+ case DebugSubsectionKind::StringTable: {
+ DebugStringTableSubsectionRef Section;
+ if (auto EC = Section.initialize(Reader))
+ return EC;
+ return V.visitStringTable(Section, State);
+ }
+ case DebugSubsectionKind::FrameData: {
+ DebugFrameDataSubsectionRef Section;
+ if (auto EC = Section.initialize(Reader))
+ return EC;
+ return V.visitFrameData(Section, State);
+ }
+ case DebugSubsectionKind::CoffSymbolRVA: {
+ DebugSymbolRVASubsectionRef Section;
+ if (auto EC = Section.initialize(Reader))
+ return EC;
+ return V.visitCOFFSymbolRVAs(Section, State);
+ }
+ default: {
+ DebugUnknownSubsectionRef Fragment(R.kind(), R.getRecordData());
+ return V.visitUnknown(Fragment);
+ }
+ }
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSymbolRVASubsection.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSymbolRVASubsection.cpp
new file mode 100644
index 0000000000..5232896735
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSymbolRVASubsection.cpp
@@ -0,0 +1,35 @@
+//===- DebugSymbolRVASubsection.cpp ---------------------------------------===//
+//
+// 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/DebugSymbolRVASubsection.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+DebugSymbolRVASubsectionRef::DebugSymbolRVASubsectionRef()
+ : DebugSubsectionRef(DebugSubsectionKind::CoffSymbolRVA) {}
+
+Error DebugSymbolRVASubsectionRef::initialize(BinaryStreamReader &Reader) {
+ return Reader.readArray(RVAs, Reader.bytesRemaining() / sizeof(uint32_t));
+}
+
+DebugSymbolRVASubsection::DebugSymbolRVASubsection()
+ : DebugSubsection(DebugSubsectionKind::CoffSymbolRVA) {}
+
+Error DebugSymbolRVASubsection::commit(BinaryStreamWriter &Writer) const {
+ return Writer.writeArray(makeArrayRef(RVAs));
+}
+
+uint32_t DebugSymbolRVASubsection::calculateSerializedSize() const {
+ return RVAs.size() * sizeof(uint32_t);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSymbolsSubsection.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSymbolsSubsection.cpp
new file mode 100644
index 0000000000..c833103663
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/DebugSymbolsSubsection.cpp
@@ -0,0 +1,33 @@
+//===- DebugSymbolsSubsection.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/DebugSymbolsSubsection.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+Error DebugSymbolsSubsectionRef::initialize(BinaryStreamReader Reader) {
+ return Reader.readArray(Records, Reader.getLength());
+}
+
+uint32_t DebugSymbolsSubsection::calculateSerializedSize() const {
+ return Length;
+}
+
+Error DebugSymbolsSubsection::commit(BinaryStreamWriter &Writer) const {
+ for (const auto &Record : Records) {
+ if (auto EC = Writer.writeBytes(Record.RecordData))
+ return EC;
+ }
+ return Error::success();
+}
+
+void DebugSymbolsSubsection::addSymbol(CVSymbol Symbol) {
+ Records.push_back(Symbol);
+ Length += Symbol.length();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/EnumTables.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/EnumTables.cpp
new file mode 100644
index 0000000000..adf4ae519d
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/EnumTables.cpp
@@ -0,0 +1,562 @@
+//===- EnumTables.cpp - Enum to string conversion tables ------------------===//
+//
+// 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/EnumTables.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include <type_traits>
+
+using namespace llvm;
+using namespace codeview;
+
+#define CV_ENUM_CLASS_ENT(enum_class, enum) \
+ { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
+
+#define CV_ENUM_ENT(ns, enum) \
+ { #enum, ns::enum }
+
+static const EnumEntry<SymbolKind> SymbolTypeNames[] = {
+#define CV_SYMBOL(enum, val) {#enum, enum},
+#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
+#undef CV_SYMBOL
+};
+
+static const EnumEntry<TypeLeafKind> TypeLeafNames[] = {
+#define CV_TYPE(name, val) {#name, name},
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+#undef CV_TYPE
+};
+
+static const EnumEntry<uint16_t> RegisterNames_X86[] = {
+#define CV_REGISTERS_X86
+#define CV_REGISTER(name, val) CV_ENUM_CLASS_ENT(RegisterId, name),
+#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"
+#undef CV_REGISTER
+#undef CV_REGISTERS_X86
+};
+
+static const EnumEntry<uint16_t> RegisterNames_ARM[] = {
+#define CV_REGISTERS_ARM
+#define CV_REGISTER(name, val) CV_ENUM_CLASS_ENT(RegisterId, name),
+#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"
+#undef CV_REGISTER
+#undef CV_REGISTERS_ARM
+};
+
+static const EnumEntry<uint16_t> RegisterNames_ARM64[] = {
+#define CV_REGISTERS_ARM64
+#define CV_REGISTER(name, val) CV_ENUM_CLASS_ENT(RegisterId, name),
+#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"
+#undef CV_REGISTER
+#undef CV_REGISTERS_ARM64
+};
+
+static const EnumEntry<uint32_t> PublicSymFlagNames[] = {
+ CV_ENUM_CLASS_ENT(PublicSymFlags, Code),
+ CV_ENUM_CLASS_ENT(PublicSymFlags, Function),
+ CV_ENUM_CLASS_ENT(PublicSymFlags, Managed),
+ CV_ENUM_CLASS_ENT(PublicSymFlags, MSIL),
+};
+
+static const EnumEntry<uint8_t> ProcSymFlagNames[] = {
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasFP),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasIRET),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasFRET),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, IsNoReturn),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, IsUnreachable),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasCustomCallingConv),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, IsNoInline),
+ CV_ENUM_CLASS_ENT(ProcSymFlags, HasOptimizedDebugInfo),
+};
+
+static const EnumEntry<uint16_t> LocalFlags[] = {
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsParameter),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAddressTaken),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsCompilerGenerated),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAggregate),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAggregated),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAliased),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsAlias),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsReturnValue),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsOptimizedOut),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsEnregisteredGlobal),
+ CV_ENUM_CLASS_ENT(LocalSymFlags, IsEnregisteredStatic),
+};
+
+static const EnumEntry<uint8_t> FrameCookieKinds[] = {
+ CV_ENUM_CLASS_ENT(FrameCookieKind, Copy),
+ CV_ENUM_CLASS_ENT(FrameCookieKind, XorStackPointer),
+ CV_ENUM_CLASS_ENT(FrameCookieKind, XorFramePointer),
+ CV_ENUM_CLASS_ENT(FrameCookieKind, XorR13),
+};
+
+static const EnumEntry<codeview::SourceLanguage> SourceLanguages[] = {
+ CV_ENUM_ENT(SourceLanguage, C), CV_ENUM_ENT(SourceLanguage, Cpp),
+ CV_ENUM_ENT(SourceLanguage, Fortran), CV_ENUM_ENT(SourceLanguage, Masm),
+ CV_ENUM_ENT(SourceLanguage, Pascal), CV_ENUM_ENT(SourceLanguage, Basic),
+ CV_ENUM_ENT(SourceLanguage, Cobol), CV_ENUM_ENT(SourceLanguage, Link),
+ CV_ENUM_ENT(SourceLanguage, Cvtres), CV_ENUM_ENT(SourceLanguage, Cvtpgd),
+ CV_ENUM_ENT(SourceLanguage, CSharp), CV_ENUM_ENT(SourceLanguage, VB),
+ CV_ENUM_ENT(SourceLanguage, ILAsm), CV_ENUM_ENT(SourceLanguage, Java),
+ CV_ENUM_ENT(SourceLanguage, JScript), CV_ENUM_ENT(SourceLanguage, MSIL),
+ CV_ENUM_ENT(SourceLanguage, HLSL), CV_ENUM_ENT(SourceLanguage, D),
+ CV_ENUM_ENT(SourceLanguage, Swift), CV_ENUM_ENT(SourceLanguage, Rust),
+};
+
+static const EnumEntry<uint32_t> CompileSym2FlagNames[] = {
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, EC),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, NoDbgInfo),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, LTCG),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, NoDataAlign),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, ManagedPresent),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, SecurityChecks),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, HotPatch),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, CVTCIL),
+ CV_ENUM_CLASS_ENT(CompileSym2Flags, MSILModule),
+};
+
+static const EnumEntry<uint32_t> CompileSym3FlagNames[] = {
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, EC),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, NoDbgInfo),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, LTCG),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, NoDataAlign),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, ManagedPresent),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, SecurityChecks),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, HotPatch),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, CVTCIL),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, MSILModule),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, Sdl),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, PGO),
+ CV_ENUM_CLASS_ENT(CompileSym3Flags, Exp),
+};
+
+static const EnumEntry<uint32_t> FileChecksumNames[] = {
+ CV_ENUM_CLASS_ENT(FileChecksumKind, None),
+ CV_ENUM_CLASS_ENT(FileChecksumKind, MD5),
+ CV_ENUM_CLASS_ENT(FileChecksumKind, SHA1),
+ CV_ENUM_CLASS_ENT(FileChecksumKind, SHA256),
+};
+
+static const EnumEntry<unsigned> CPUTypeNames[] = {
+ CV_ENUM_CLASS_ENT(CPUType, Intel8080),
+ CV_ENUM_CLASS_ENT(CPUType, Intel8086),
+ CV_ENUM_CLASS_ENT(CPUType, Intel80286),
+ CV_ENUM_CLASS_ENT(CPUType, Intel80386),
+ CV_ENUM_CLASS_ENT(CPUType, Intel80486),
+ CV_ENUM_CLASS_ENT(CPUType, Pentium),
+ CV_ENUM_CLASS_ENT(CPUType, PentiumPro),
+ CV_ENUM_CLASS_ENT(CPUType, Pentium3),
+ CV_ENUM_CLASS_ENT(CPUType, MIPS),
+ CV_ENUM_CLASS_ENT(CPUType, MIPS16),
+ CV_ENUM_CLASS_ENT(CPUType, MIPS32),
+ CV_ENUM_CLASS_ENT(CPUType, MIPS64),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSI),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSII),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSIII),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSIV),
+ CV_ENUM_CLASS_ENT(CPUType, MIPSV),
+ CV_ENUM_CLASS_ENT(CPUType, M68000),
+ CV_ENUM_CLASS_ENT(CPUType, M68010),
+ CV_ENUM_CLASS_ENT(CPUType, M68020),
+ CV_ENUM_CLASS_ENT(CPUType, M68030),
+ CV_ENUM_CLASS_ENT(CPUType, M68040),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha21164),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha21164A),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha21264),
+ CV_ENUM_CLASS_ENT(CPUType, Alpha21364),
+ CV_ENUM_CLASS_ENT(CPUType, PPC601),
+ CV_ENUM_CLASS_ENT(CPUType, PPC603),
+ CV_ENUM_CLASS_ENT(CPUType, PPC604),
+ CV_ENUM_CLASS_ENT(CPUType, PPC620),
+ CV_ENUM_CLASS_ENT(CPUType, PPCFP),
+ CV_ENUM_CLASS_ENT(CPUType, PPCBE),
+ CV_ENUM_CLASS_ENT(CPUType, SH3),
+ CV_ENUM_CLASS_ENT(CPUType, SH3E),
+ CV_ENUM_CLASS_ENT(CPUType, SH3DSP),
+ CV_ENUM_CLASS_ENT(CPUType, SH4),
+ CV_ENUM_CLASS_ENT(CPUType, SHMedia),
+ CV_ENUM_CLASS_ENT(CPUType, ARM3),
+ CV_ENUM_CLASS_ENT(CPUType, ARM4),
+ CV_ENUM_CLASS_ENT(CPUType, ARM4T),
+ CV_ENUM_CLASS_ENT(CPUType, ARM5),
+ CV_ENUM_CLASS_ENT(CPUType, ARM5T),
+ CV_ENUM_CLASS_ENT(CPUType, ARM6),
+ CV_ENUM_CLASS_ENT(CPUType, ARM_XMAC),
+ CV_ENUM_CLASS_ENT(CPUType, ARM_WMMX),
+ CV_ENUM_CLASS_ENT(CPUType, ARM7),
+ CV_ENUM_CLASS_ENT(CPUType, Omni),
+ CV_ENUM_CLASS_ENT(CPUType, Ia64),
+ CV_ENUM_CLASS_ENT(CPUType, Ia64_2),
+ CV_ENUM_CLASS_ENT(CPUType, CEE),
+ CV_ENUM_CLASS_ENT(CPUType, AM33),
+ CV_ENUM_CLASS_ENT(CPUType, M32R),
+ CV_ENUM_CLASS_ENT(CPUType, TriCore),
+ CV_ENUM_CLASS_ENT(CPUType, X64),
+ CV_ENUM_CLASS_ENT(CPUType, EBC),
+ CV_ENUM_CLASS_ENT(CPUType, Thumb),
+ CV_ENUM_CLASS_ENT(CPUType, ARMNT),
+ CV_ENUM_CLASS_ENT(CPUType, ARM64),
+ CV_ENUM_CLASS_ENT(CPUType, HybridX86ARM64),
+ CV_ENUM_CLASS_ENT(CPUType, ARM64EC),
+ CV_ENUM_CLASS_ENT(CPUType, ARM64X),
+ CV_ENUM_CLASS_ENT(CPUType, D3D11_Shader),
+};
+
+static const EnumEntry<uint32_t> FrameProcSymFlagNames[] = {
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasAlloca),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasSetJmp),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasLongJmp),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasInlineAssembly),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasExceptionHandling),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, MarkedInline),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, HasStructuredExceptionHandling),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, Naked),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, SecurityChecks),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, AsynchronousExceptionHandling),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, NoStackOrderingForSecurityChecks),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, Inlined),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, StrictSecurityChecks),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, SafeBuffers),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, EncodedLocalBasePointerMask),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, EncodedParamBasePointerMask),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, ProfileGuidedOptimization),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, ValidProfileCounts),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, OptimizedForSpeed),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfg),
+ CV_ENUM_CLASS_ENT(FrameProcedureOptions, GuardCfw),
+};
+
+static const EnumEntry<uint32_t> ModuleSubstreamKindNames[] = {
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, None),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, Symbols),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, Lines),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, StringTable),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, FileChecksums),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, FrameData),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, InlineeLines),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, CrossScopeImports),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, CrossScopeExports),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, ILLines),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, FuncMDTokenMap),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, TypeMDTokenMap),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, MergedAssemblyInput),
+ CV_ENUM_CLASS_ENT(DebugSubsectionKind, CoffSymbolRVA),
+};
+
+static const EnumEntry<uint16_t> ExportSymFlagNames[] = {
+ CV_ENUM_CLASS_ENT(ExportFlags, IsConstant),
+ CV_ENUM_CLASS_ENT(ExportFlags, IsData),
+ CV_ENUM_CLASS_ENT(ExportFlags, IsPrivate),
+ CV_ENUM_CLASS_ENT(ExportFlags, HasNoName),
+ CV_ENUM_CLASS_ENT(ExportFlags, HasExplicitOrdinal),
+ CV_ENUM_CLASS_ENT(ExportFlags, IsForwarder),
+};
+
+static const EnumEntry<uint8_t> ThunkOrdinalNames[] = {
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, Standard),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, ThisAdjustor),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, Vcall),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, Pcode),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, UnknownLoad),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, TrampIncremental),
+ CV_ENUM_CLASS_ENT(ThunkOrdinal, BranchIsland),
+};
+
+static const EnumEntry<uint16_t> TrampolineNames[] = {
+ CV_ENUM_CLASS_ENT(TrampolineType, TrampIncremental),
+ CV_ENUM_CLASS_ENT(TrampolineType, BranchIsland),
+};
+
+static const EnumEntry<COFF::SectionCharacteristics>
+ ImageSectionCharacteristicNames[] = {
+ CV_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NOLOAD),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_TYPE_NO_PAD),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_CODE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_INITIALIZED_DATA),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_CNT_UNINITIALIZED_DATA),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_OTHER),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_INFO),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_REMOVE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_COMDAT),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_GPREL),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_PURGEABLE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_16BIT),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_LOCKED),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_PRELOAD),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_16BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_32BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_64BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_128BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_256BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_512BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_1024BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_2048BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_4096BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_ALIGN_8192BYTES),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_LNK_NRELOC_OVFL),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_DISCARDABLE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_CACHED),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_NOT_PAGED),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_SHARED),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_EXECUTE),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_READ),
+ CV_ENUM_ENT(COFF, IMAGE_SCN_MEM_WRITE)};
+
+static const EnumEntry<uint16_t> ClassOptionNames[] = {
+ CV_ENUM_CLASS_ENT(ClassOptions, Packed),
+ CV_ENUM_CLASS_ENT(ClassOptions, HasConstructorOrDestructor),
+ CV_ENUM_CLASS_ENT(ClassOptions, HasOverloadedOperator),
+ CV_ENUM_CLASS_ENT(ClassOptions, Nested),
+ CV_ENUM_CLASS_ENT(ClassOptions, ContainsNestedClass),
+ CV_ENUM_CLASS_ENT(ClassOptions, HasOverloadedAssignmentOperator),
+ CV_ENUM_CLASS_ENT(ClassOptions, HasConversionOperator),
+ CV_ENUM_CLASS_ENT(ClassOptions, ForwardReference),
+ CV_ENUM_CLASS_ENT(ClassOptions, Scoped),
+ CV_ENUM_CLASS_ENT(ClassOptions, HasUniqueName),
+ CV_ENUM_CLASS_ENT(ClassOptions, Sealed),
+ CV_ENUM_CLASS_ENT(ClassOptions, Intrinsic),
+};
+
+static const EnumEntry<uint8_t> MemberAccessNames[] = {
+ CV_ENUM_CLASS_ENT(MemberAccess, None),
+ CV_ENUM_CLASS_ENT(MemberAccess, Private),
+ CV_ENUM_CLASS_ENT(MemberAccess, Protected),
+ CV_ENUM_CLASS_ENT(MemberAccess, Public),
+};
+
+static const EnumEntry<uint16_t> MethodOptionNames[] = {
+ CV_ENUM_CLASS_ENT(MethodOptions, Pseudo),
+ CV_ENUM_CLASS_ENT(MethodOptions, NoInherit),
+ CV_ENUM_CLASS_ENT(MethodOptions, NoConstruct),
+ CV_ENUM_CLASS_ENT(MethodOptions, CompilerGenerated),
+ CV_ENUM_CLASS_ENT(MethodOptions, Sealed),
+};
+
+static const EnumEntry<uint16_t> MemberKindNames[] = {
+ CV_ENUM_CLASS_ENT(MethodKind, Vanilla),
+ CV_ENUM_CLASS_ENT(MethodKind, Virtual),
+ CV_ENUM_CLASS_ENT(MethodKind, Static),
+ CV_ENUM_CLASS_ENT(MethodKind, Friend),
+ CV_ENUM_CLASS_ENT(MethodKind, IntroducingVirtual),
+ CV_ENUM_CLASS_ENT(MethodKind, PureVirtual),
+ CV_ENUM_CLASS_ENT(MethodKind, PureIntroducingVirtual),
+};
+
+static const EnumEntry<uint8_t> PtrKindNames[] = {
+ CV_ENUM_CLASS_ENT(PointerKind, Near16),
+ CV_ENUM_CLASS_ENT(PointerKind, Far16),
+ CV_ENUM_CLASS_ENT(PointerKind, Huge16),
+ CV_ENUM_CLASS_ENT(PointerKind, BasedOnSegment),
+ CV_ENUM_CLASS_ENT(PointerKind, BasedOnValue),
+ CV_ENUM_CLASS_ENT(PointerKind, BasedOnSegmentValue),
+ CV_ENUM_CLASS_ENT(PointerKind, BasedOnAddress),
+ CV_ENUM_CLASS_ENT(PointerKind, BasedOnSegmentAddress),
+ CV_ENUM_CLASS_ENT(PointerKind, BasedOnType),
+ CV_ENUM_CLASS_ENT(PointerKind, BasedOnSelf),
+ CV_ENUM_CLASS_ENT(PointerKind, Near32),
+ CV_ENUM_CLASS_ENT(PointerKind, Far32),
+ CV_ENUM_CLASS_ENT(PointerKind, Near64),
+};
+
+static const EnumEntry<uint8_t> PtrModeNames[] = {
+ CV_ENUM_CLASS_ENT(PointerMode, Pointer),
+ CV_ENUM_CLASS_ENT(PointerMode, LValueReference),
+ CV_ENUM_CLASS_ENT(PointerMode, PointerToDataMember),
+ CV_ENUM_CLASS_ENT(PointerMode, PointerToMemberFunction),
+ CV_ENUM_CLASS_ENT(PointerMode, RValueReference),
+};
+
+static const EnumEntry<uint16_t> PtrMemberRepNames[] = {
+ CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, Unknown),
+ CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, SingleInheritanceData),
+ CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, MultipleInheritanceData),
+ CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, VirtualInheritanceData),
+ CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, GeneralData),
+ CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, SingleInheritanceFunction),
+ CV_ENUM_CLASS_ENT(PointerToMemberRepresentation,
+ MultipleInheritanceFunction),
+ CV_ENUM_CLASS_ENT(PointerToMemberRepresentation,
+ VirtualInheritanceFunction),
+ CV_ENUM_CLASS_ENT(PointerToMemberRepresentation, GeneralFunction),
+};
+
+static const EnumEntry<uint16_t> TypeModifierNames[] = {
+ CV_ENUM_CLASS_ENT(ModifierOptions, Const),
+ CV_ENUM_CLASS_ENT(ModifierOptions, Volatile),
+ CV_ENUM_CLASS_ENT(ModifierOptions, Unaligned),
+};
+
+static const EnumEntry<uint8_t> CallingConventions[] = {
+ CV_ENUM_CLASS_ENT(CallingConvention, NearC),
+ CV_ENUM_CLASS_ENT(CallingConvention, FarC),
+ CV_ENUM_CLASS_ENT(CallingConvention, NearPascal),
+ CV_ENUM_CLASS_ENT(CallingConvention, FarPascal),
+ CV_ENUM_CLASS_ENT(CallingConvention, NearFast),
+ CV_ENUM_CLASS_ENT(CallingConvention, FarFast),
+ CV_ENUM_CLASS_ENT(CallingConvention, NearStdCall),
+ CV_ENUM_CLASS_ENT(CallingConvention, FarStdCall),
+ CV_ENUM_CLASS_ENT(CallingConvention, NearSysCall),
+ CV_ENUM_CLASS_ENT(CallingConvention, FarSysCall),
+ CV_ENUM_CLASS_ENT(CallingConvention, ThisCall),
+ CV_ENUM_CLASS_ENT(CallingConvention, MipsCall),
+ CV_ENUM_CLASS_ENT(CallingConvention, Generic),
+ CV_ENUM_CLASS_ENT(CallingConvention, AlphaCall),
+ CV_ENUM_CLASS_ENT(CallingConvention, PpcCall),
+ CV_ENUM_CLASS_ENT(CallingConvention, SHCall),
+ CV_ENUM_CLASS_ENT(CallingConvention, ArmCall),
+ CV_ENUM_CLASS_ENT(CallingConvention, AM33Call),
+ CV_ENUM_CLASS_ENT(CallingConvention, TriCall),
+ CV_ENUM_CLASS_ENT(CallingConvention, SH5Call),
+ CV_ENUM_CLASS_ENT(CallingConvention, M32RCall),
+ CV_ENUM_CLASS_ENT(CallingConvention, ClrCall),
+ CV_ENUM_CLASS_ENT(CallingConvention, Inline),
+ CV_ENUM_CLASS_ENT(CallingConvention, NearVector),
+};
+
+static const EnumEntry<uint8_t> FunctionOptionEnum[] = {
+ CV_ENUM_CLASS_ENT(FunctionOptions, CxxReturnUdt),
+ CV_ENUM_CLASS_ENT(FunctionOptions, Constructor),
+ CV_ENUM_CLASS_ENT(FunctionOptions, ConstructorWithVirtualBases),
+};
+
+static const EnumEntry<uint16_t> LabelTypeEnum[] = {
+ CV_ENUM_CLASS_ENT(LabelType, Near),
+ CV_ENUM_CLASS_ENT(LabelType, Far),
+};
+
+namespace llvm {
+namespace codeview {
+
+ArrayRef<EnumEntry<SymbolKind>> getSymbolTypeNames() {
+ return makeArrayRef(SymbolTypeNames);
+}
+
+ArrayRef<EnumEntry<TypeLeafKind>> getTypeLeafNames() {
+ return makeArrayRef(TypeLeafNames);
+}
+
+ArrayRef<EnumEntry<uint16_t>> getRegisterNames(CPUType Cpu) {
+ if (Cpu == CPUType::ARMNT) {
+ return makeArrayRef(RegisterNames_ARM);
+ } else if (Cpu == CPUType::ARM64) {
+ return makeArrayRef(RegisterNames_ARM64);
+ }
+ return makeArrayRef(RegisterNames_X86);
+}
+
+ArrayRef<EnumEntry<uint32_t>> getPublicSymFlagNames() {
+ return makeArrayRef(PublicSymFlagNames);
+}
+
+ArrayRef<EnumEntry<uint8_t>> getProcSymFlagNames() {
+ return makeArrayRef(ProcSymFlagNames);
+}
+
+ArrayRef<EnumEntry<uint16_t>> getLocalFlagNames() {
+ return makeArrayRef(LocalFlags);
+}
+
+ArrayRef<EnumEntry<uint8_t>> getFrameCookieKindNames() {
+ return makeArrayRef(FrameCookieKinds);
+}
+
+ArrayRef<EnumEntry<SourceLanguage>> getSourceLanguageNames() {
+ return makeArrayRef(SourceLanguages);
+}
+
+ArrayRef<EnumEntry<uint32_t>> getCompileSym2FlagNames() {
+ return makeArrayRef(CompileSym2FlagNames);
+}
+
+ArrayRef<EnumEntry<uint32_t>> getCompileSym3FlagNames() {
+ return makeArrayRef(CompileSym3FlagNames);
+}
+
+ArrayRef<EnumEntry<uint32_t>> getFileChecksumNames() {
+ return makeArrayRef(FileChecksumNames);
+}
+
+ArrayRef<EnumEntry<unsigned>> getCPUTypeNames() {
+ return makeArrayRef(CPUTypeNames);
+}
+
+ArrayRef<EnumEntry<uint32_t>> getFrameProcSymFlagNames() {
+ return makeArrayRef(FrameProcSymFlagNames);
+}
+
+ArrayRef<EnumEntry<uint16_t>> getExportSymFlagNames() {
+ return makeArrayRef(ExportSymFlagNames);
+}
+
+ArrayRef<EnumEntry<uint32_t>> getModuleSubstreamKindNames() {
+ return makeArrayRef(ModuleSubstreamKindNames);
+}
+
+ArrayRef<EnumEntry<uint8_t>> getThunkOrdinalNames() {
+ return makeArrayRef(ThunkOrdinalNames);
+}
+
+ArrayRef<EnumEntry<uint16_t>> getTrampolineNames() {
+ return makeArrayRef(TrampolineNames);
+}
+
+ArrayRef<EnumEntry<COFF::SectionCharacteristics>>
+getImageSectionCharacteristicNames() {
+ return makeArrayRef(ImageSectionCharacteristicNames);
+}
+
+ArrayRef<EnumEntry<uint16_t>> getClassOptionNames() {
+ return makeArrayRef(ClassOptionNames);
+}
+
+ArrayRef<EnumEntry<uint8_t>> getMemberAccessNames() {
+ return makeArrayRef(MemberAccessNames);
+}
+
+ArrayRef<EnumEntry<uint16_t>> getMethodOptionNames() {
+ return makeArrayRef(MethodOptionNames);
+}
+
+ArrayRef<EnumEntry<uint16_t>> getMemberKindNames() {
+ return makeArrayRef(MemberKindNames);
+}
+
+ArrayRef<EnumEntry<uint8_t>> getPtrKindNames() {
+ return makeArrayRef(PtrKindNames);
+}
+
+ArrayRef<EnumEntry<uint8_t>> getPtrModeNames() {
+ return makeArrayRef(PtrModeNames);
+}
+
+ArrayRef<EnumEntry<uint16_t>> getPtrMemberRepNames() {
+ return makeArrayRef(PtrMemberRepNames);
+}
+
+ArrayRef<EnumEntry<uint16_t>> getTypeModifierNames() {
+ return makeArrayRef(TypeModifierNames);
+}
+
+ArrayRef<EnumEntry<uint8_t>> getCallingConventions() {
+ return makeArrayRef(CallingConventions);
+}
+
+ArrayRef<EnumEntry<uint8_t>> getFunctionOptionEnum() {
+ return makeArrayRef(FunctionOptionEnum);
+}
+
+ArrayRef<EnumEntry<uint16_t>> getLabelTypeEnum() {
+ return makeArrayRef(LabelTypeEnum);
+}
+
+} // end namespace codeview
+} // end namespace llvm
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/Formatters.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/Formatters.cpp
new file mode 100644
index 0000000000..f1f51bcb39
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/Formatters.cpp
@@ -0,0 +1,59 @@
+//===- Formatters.cpp -----------------------------------------------------===//
+//
+// 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/Formatters.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/GUID.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::codeview::detail;
+
+GuidAdapter::GuidAdapter(StringRef Guid)
+ : FormatAdapter(makeArrayRef(Guid.bytes_begin(), Guid.bytes_end())) {}
+
+GuidAdapter::GuidAdapter(ArrayRef<uint8_t> Guid)
+ : FormatAdapter(std::move(Guid)) {}
+
+// From https://docs.microsoft.com/en-us/windows/win32/msi/guid documentation:
+// The GUID data type is a text string representing a Class identifier (ID).
+// All GUIDs must be authored in uppercase.
+// The valid format for a GUID is {XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX} where
+// X is a hex digit (0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F).
+//
+// The individual string components must be padded to comply with the specific
+// lengths of {8-4-4-4-12} characters.
+// The llvm-yaml2obj tool checks that a GUID follow that format:
+// - the total length to be 38 (including the curly braces.
+// - there is a dash at the positions: 8, 13, 18 and 23.
+void GuidAdapter::format(raw_ostream &Stream, StringRef Style) {
+ assert(Item.size() == 16 && "Expected 16-byte GUID");
+ struct MSGuid {
+ support::ulittle32_t Data1;
+ support::ulittle16_t Data2;
+ support::ulittle16_t Data3;
+ support::ubig64_t Data4;
+ };
+ const MSGuid *G = reinterpret_cast<const MSGuid *>(Item.data());
+ Stream
+ << '{' << format_hex_no_prefix(G->Data1, 8, /*Upper=*/true)
+ << '-' << format_hex_no_prefix(G->Data2, 4, /*Upper=*/true)
+ << '-' << format_hex_no_prefix(G->Data3, 4, /*Upper=*/true)
+ << '-' << format_hex_no_prefix(G->Data4 >> 48, 4, /*Upper=*/true) << '-'
+ << format_hex_no_prefix(G->Data4 & ((1ULL << 48) - 1), 12, /*Upper=*/true)
+ << '}';
+}
+
+raw_ostream &llvm::codeview::operator<<(raw_ostream &OS, const GUID &Guid) {
+ codeview::detail::GuidAdapter A(Guid.Guid);
+ A.format(OS, "");
+ return OS;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp
new file mode 100644
index 0000000000..7cd9ca7498
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/GlobalTypeTableBuilder.cpp
@@ -0,0 +1,140 @@
+//===- GlobalTypeTableBuilder.cpp -----------------------------------------===//
+//
+// 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/GlobalTypeTableBuilder.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+TypeIndex GlobalTypeTableBuilder::nextTypeIndex() const {
+ return TypeIndex::fromArrayIndex(SeenRecords.size());
+}
+
+GlobalTypeTableBuilder::GlobalTypeTableBuilder(BumpPtrAllocator &Storage)
+ : RecordStorage(Storage) {
+ SeenRecords.reserve(4096);
+}
+
+GlobalTypeTableBuilder::~GlobalTypeTableBuilder() = default;
+
+Optional<TypeIndex> GlobalTypeTableBuilder::getFirst() {
+ if (empty())
+ return None;
+
+ return TypeIndex(TypeIndex::FirstNonSimpleIndex);
+}
+
+Optional<TypeIndex> GlobalTypeTableBuilder::getNext(TypeIndex Prev) {
+ if (++Prev == nextTypeIndex())
+ return None;
+ return Prev;
+}
+
+CVType GlobalTypeTableBuilder::getType(TypeIndex Index) {
+ CVType Type(SeenRecords[Index.toArrayIndex()]);
+ return Type;
+}
+
+StringRef GlobalTypeTableBuilder::getTypeName(TypeIndex Index) {
+ llvm_unreachable("Method not implemented");
+}
+
+bool GlobalTypeTableBuilder::contains(TypeIndex Index) {
+ if (Index.isSimple() || Index.isNoneType())
+ return false;
+
+ return Index.toArrayIndex() < SeenRecords.size();
+}
+
+uint32_t GlobalTypeTableBuilder::size() { return SeenRecords.size(); }
+
+uint32_t GlobalTypeTableBuilder::capacity() { return SeenRecords.size(); }
+
+ArrayRef<ArrayRef<uint8_t>> GlobalTypeTableBuilder::records() const {
+ return SeenRecords;
+}
+
+ArrayRef<GloballyHashedType> GlobalTypeTableBuilder::hashes() const {
+ return SeenHashes;
+}
+
+void GlobalTypeTableBuilder::reset() {
+ HashedRecords.clear();
+ SeenRecords.clear();
+}
+
+static inline ArrayRef<uint8_t> stabilize(BumpPtrAllocator &Alloc,
+ ArrayRef<uint8_t> Data) {
+ uint8_t *Stable = Alloc.Allocate<uint8_t>(Data.size());
+ memcpy(Stable, Data.data(), Data.size());
+ return makeArrayRef(Stable, Data.size());
+}
+
+TypeIndex GlobalTypeTableBuilder::insertRecordBytes(ArrayRef<uint8_t> Record) {
+ GloballyHashedType GHT =
+ GloballyHashedType::hashType(Record, SeenHashes, SeenHashes);
+ return insertRecordAs(GHT, Record.size(),
+ [Record](MutableArrayRef<uint8_t> Data) {
+ assert(Data.size() == Record.size());
+ ::memcpy(Data.data(), Record.data(), Record.size());
+ return Data;
+ });
+}
+
+TypeIndex
+GlobalTypeTableBuilder::insertRecord(ContinuationRecordBuilder &Builder) {
+ TypeIndex TI;
+ auto Fragments = Builder.end(nextTypeIndex());
+ assert(!Fragments.empty());
+ for (auto C : Fragments)
+ TI = insertRecordBytes(C.RecordData);
+ return TI;
+}
+
+bool GlobalTypeTableBuilder::replaceType(TypeIndex &Index, CVType Data,
+ bool Stabilize) {
+ assert(Index.toArrayIndex() < SeenRecords.size() &&
+ "This function cannot be used to insert records!");
+
+ ArrayRef<uint8_t> Record = Data.data();
+ assert(Record.size() < UINT32_MAX && "Record too big");
+ assert(Record.size() % 4 == 0 &&
+ "The type record size is not a multiple of 4 bytes which will cause "
+ "misalignment in the output TPI stream!");
+
+ GloballyHashedType Hash =
+ GloballyHashedType::hashType(Record, SeenHashes, SeenHashes);
+ auto Result = HashedRecords.try_emplace(Hash, Index.toArrayIndex());
+ if (!Result.second) {
+ Index = Result.first->second;
+ return false; // The record is already there, at a different location
+ }
+
+ if (Stabilize)
+ Record = stabilize(RecordStorage, Record);
+
+ SeenRecords[Index.toArrayIndex()] = Record;
+ SeenHashes[Index.toArrayIndex()] = Hash;
+ return true;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
new file mode 100644
index 0000000000..c0fc3e0ef6
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/LazyRandomTypeCollection.cpp
@@ -0,0 +1,284 @@
+//===- LazyRandomTypeCollection.cpp ---------------------------------------===//
+//
+// 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/LazyRandomTypeCollection.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/RecordName.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <iterator>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+static void error(Error &&EC) {
+ assert(!static_cast<bool>(EC));
+ if (EC)
+ consumeError(std::move(EC));
+}
+
+LazyRandomTypeCollection::LazyRandomTypeCollection(uint32_t RecordCountHint)
+ : LazyRandomTypeCollection(CVTypeArray(), RecordCountHint,
+ PartialOffsetArray()) {}
+
+LazyRandomTypeCollection::LazyRandomTypeCollection(
+ const CVTypeArray &Types, uint32_t RecordCountHint,
+ PartialOffsetArray PartialOffsets)
+ : NameStorage(Allocator), Types(Types), PartialOffsets(PartialOffsets) {
+ Records.resize(RecordCountHint);
+}
+
+LazyRandomTypeCollection::LazyRandomTypeCollection(ArrayRef<uint8_t> Data,
+ uint32_t RecordCountHint)
+ : LazyRandomTypeCollection(RecordCountHint) {
+}
+
+LazyRandomTypeCollection::LazyRandomTypeCollection(StringRef Data,
+ uint32_t RecordCountHint)
+ : LazyRandomTypeCollection(
+ makeArrayRef(Data.bytes_begin(), Data.bytes_end()), RecordCountHint) {
+}
+
+LazyRandomTypeCollection::LazyRandomTypeCollection(const CVTypeArray &Types,
+ uint32_t NumRecords)
+ : LazyRandomTypeCollection(Types, NumRecords, PartialOffsetArray()) {}
+
+void LazyRandomTypeCollection::reset(BinaryStreamReader &Reader,
+ uint32_t RecordCountHint) {
+ Count = 0;
+ PartialOffsets = PartialOffsetArray();
+
+ error(Reader.readArray(Types, Reader.bytesRemaining()));
+
+ // Clear and then resize, to make sure existing data gets destroyed.
+ Records.clear();
+ Records.resize(RecordCountHint);
+}
+
+void LazyRandomTypeCollection::reset(StringRef Data, uint32_t RecordCountHint) {
+ BinaryStreamReader Reader(Data, support::little);
+ reset(Reader, RecordCountHint);
+}
+
+void LazyRandomTypeCollection::reset(ArrayRef<uint8_t> Data,
+ uint32_t RecordCountHint) {
+ BinaryStreamReader Reader(Data, support::little);
+ reset(Reader, RecordCountHint);
+}
+
+uint32_t LazyRandomTypeCollection::getOffsetOfType(TypeIndex Index) {
+ error(ensureTypeExists(Index));
+ assert(contains(Index));
+
+ return Records[Index.toArrayIndex()].Offset;
+}
+
+CVType LazyRandomTypeCollection::getType(TypeIndex Index) {
+ assert(!Index.isSimple());
+
+ auto EC = ensureTypeExists(Index);
+ error(std::move(EC));
+ assert(contains(Index));
+
+ return Records[Index.toArrayIndex()].Type;
+}
+
+Optional<CVType> LazyRandomTypeCollection::tryGetType(TypeIndex Index) {
+ if (Index.isSimple())
+ return None;
+
+ if (auto EC = ensureTypeExists(Index)) {
+ consumeError(std::move(EC));
+ return None;
+ }
+
+ assert(contains(Index));
+ return Records[Index.toArrayIndex()].Type;
+}
+
+StringRef LazyRandomTypeCollection::getTypeName(TypeIndex Index) {
+ if (Index.isNoneType() || Index.isSimple())
+ return TypeIndex::simpleTypeName(Index);
+
+ // Try to make sure the type exists. Even if it doesn't though, it may be
+ // because we're dumping a symbol stream with no corresponding type stream
+ // present, in which case we still want to be able to print <unknown UDT>
+ // for the type names.
+ if (auto EC = ensureTypeExists(Index)) {
+ consumeError(std::move(EC));
+ return "<unknown UDT>";
+ }
+
+ uint32_t I = Index.toArrayIndex();
+ ensureCapacityFor(Index);
+ if (Records[I].Name.data() == nullptr) {
+ StringRef Result = NameStorage.save(computeTypeName(*this, Index));
+ Records[I].Name = Result;
+ }
+ return Records[I].Name;
+}
+
+bool LazyRandomTypeCollection::contains(TypeIndex Index) {
+ if (Index.isSimple() || Index.isNoneType())
+ return false;
+
+ if (Records.size() <= Index.toArrayIndex())
+ return false;
+ if (!Records[Index.toArrayIndex()].Type.valid())
+ return false;
+ return true;
+}
+
+uint32_t LazyRandomTypeCollection::size() { return Count; }
+
+uint32_t LazyRandomTypeCollection::capacity() { return Records.size(); }
+
+Error LazyRandomTypeCollection::ensureTypeExists(TypeIndex TI) {
+ if (contains(TI))
+ return Error::success();
+
+ return visitRangeForType(TI);
+}
+
+void LazyRandomTypeCollection::ensureCapacityFor(TypeIndex Index) {
+ assert(!Index.isSimple());
+ uint32_t MinSize = Index.toArrayIndex() + 1;
+
+ if (MinSize <= capacity())
+ return;
+
+ uint32_t NewCapacity = MinSize * 3 / 2;
+
+ assert(NewCapacity > capacity());
+ Records.resize(NewCapacity);
+}
+
+Error LazyRandomTypeCollection::visitRangeForType(TypeIndex TI) {
+ assert(!TI.isSimple());
+ if (PartialOffsets.empty())
+ return fullScanForType(TI);
+
+ auto Next = llvm::upper_bound(PartialOffsets, TI,
+ [](TypeIndex Value, const TypeIndexOffset &IO) {
+ return Value < IO.Type;
+ });
+
+ assert(Next != PartialOffsets.begin());
+ auto Prev = std::prev(Next);
+
+ TypeIndex TIB = Prev->Type;
+ if (contains(TIB)) {
+ // They've asked us to fetch a type index, but the entry we found in the
+ // partial offsets array has already been visited. Since we visit an entire
+ // block every time, that means this record should have been previously
+ // discovered. Ultimately, this means this is a request for a non-existent
+ // type index.
+ return make_error<CodeViewError>("Invalid type index");
+ }
+
+ TypeIndex TIE;
+ if (Next == PartialOffsets.end()) {
+ TIE = TypeIndex::fromArrayIndex(capacity());
+ } else {
+ TIE = Next->Type;
+ }
+
+ visitRange(TIB, Prev->Offset, TIE);
+ return Error::success();
+}
+
+Optional<TypeIndex> LazyRandomTypeCollection::getFirst() {
+ TypeIndex TI = TypeIndex::fromArrayIndex(0);
+ if (auto EC = ensureTypeExists(TI)) {
+ consumeError(std::move(EC));
+ return None;
+ }
+ return TI;
+}
+
+Optional<TypeIndex> LazyRandomTypeCollection::getNext(TypeIndex Prev) {
+ // We can't be sure how long this type stream is, given that the initial count
+ // given to the constructor is just a hint. So just try to make sure the next
+ // record exists, and if anything goes wrong, we must be at the end.
+ if (auto EC = ensureTypeExists(Prev + 1)) {
+ consumeError(std::move(EC));
+ return None;
+ }
+
+ return Prev + 1;
+}
+
+Error LazyRandomTypeCollection::fullScanForType(TypeIndex TI) {
+ assert(!TI.isSimple());
+ assert(PartialOffsets.empty());
+
+ TypeIndex CurrentTI = TypeIndex::fromArrayIndex(0);
+ auto Begin = Types.begin();
+
+ if (Count > 0) {
+ // In the case of type streams which we don't know the number of records of,
+ // it's possible to search for a type index triggering a full scan, but then
+ // later additional records are added since we didn't know how many there
+ // would be until we did a full visitation, then you try to access the new
+ // type triggering another full scan. To avoid this, we assume that if the
+ // database has some records, this must be what's going on. We can also
+ // assume that this index must be larger than the largest type index we've
+ // visited, so we start from there and scan forward.
+ uint32_t Offset = Records[LargestTypeIndex.toArrayIndex()].Offset;
+ CurrentTI = LargestTypeIndex + 1;
+ Begin = Types.at(Offset);
+ ++Begin;
+ }
+
+ auto End = Types.end();
+ while (Begin != End) {
+ ensureCapacityFor(CurrentTI);
+ LargestTypeIndex = std::max(LargestTypeIndex, CurrentTI);
+ auto Idx = CurrentTI.toArrayIndex();
+ Records[Idx].Type = *Begin;
+ Records[Idx].Offset = Begin.offset();
+ ++Count;
+ ++Begin;
+ ++CurrentTI;
+ }
+ if (CurrentTI <= TI) {
+ return make_error<CodeViewError>("Type Index does not exist!");
+ }
+ return Error::success();
+}
+
+void LazyRandomTypeCollection::visitRange(TypeIndex Begin, uint32_t BeginOffset,
+ TypeIndex End) {
+ auto RI = Types.at(BeginOffset);
+ assert(RI != Types.end());
+
+ ensureCapacityFor(End);
+ while (Begin != End) {
+ LargestTypeIndex = std::max(LargestTypeIndex, Begin);
+ auto Idx = Begin.toArrayIndex();
+ Records[Idx].Type = *RI;
+ Records[Idx].Offset = RI.offset();
+ ++Count;
+ ++Begin;
+ ++RI;
+ }
+}
+
+bool LazyRandomTypeCollection::replaceType(TypeIndex &Index, CVType Data,
+ bool Stabilize) {
+ llvm_unreachable("Method cannot be called");
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/Line.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/Line.cpp
new file mode 100644
index 0000000000..53adc8cac5
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/Line.cpp
@@ -0,0 +1,21 @@
+//===-- Line.cpp ----------------------------------------------------------===//
+//
+// 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/Line.h"
+
+using namespace llvm;
+using namespace codeview;
+
+LineInfo::LineInfo(uint32_t StartLine, uint32_t EndLine, bool IsStatement) {
+ LineData = StartLine & StartLineMask;
+ uint32_t LineDelta = EndLine - StartLine;
+ LineData |= (LineDelta << EndLineDeltaShift) & EndLineDeltaMask;
+ if (IsStatement) {
+ LineData |= StatementFlag;
+ }
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp
new file mode 100644
index 0000000000..13ce3ae82c
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/MergingTypeTableBuilder.cpp
@@ -0,0 +1,152 @@
+//===- MergingTypeTableBuilder.cpp ----------------------------------------===//
+//
+// 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/MergingTypeTableBuilder.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/DenseSet.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/ContinuationRecordBuilder.h"
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+TypeIndex MergingTypeTableBuilder::nextTypeIndex() const {
+ return TypeIndex::fromArrayIndex(SeenRecords.size());
+}
+
+MergingTypeTableBuilder::MergingTypeTableBuilder(BumpPtrAllocator &Storage)
+ : RecordStorage(Storage) {
+ SeenRecords.reserve(4096);
+}
+
+MergingTypeTableBuilder::~MergingTypeTableBuilder() = default;
+
+Optional<TypeIndex> MergingTypeTableBuilder::getFirst() {
+ if (empty())
+ return None;
+
+ return TypeIndex(TypeIndex::FirstNonSimpleIndex);
+}
+
+Optional<TypeIndex> MergingTypeTableBuilder::getNext(TypeIndex Prev) {
+ if (++Prev == nextTypeIndex())
+ return None;
+ return Prev;
+}
+
+CVType MergingTypeTableBuilder::getType(TypeIndex Index) {
+ CVType Type(SeenRecords[Index.toArrayIndex()]);
+ return Type;
+}
+
+StringRef MergingTypeTableBuilder::getTypeName(TypeIndex Index) {
+ llvm_unreachable("Method not implemented");
+}
+
+bool MergingTypeTableBuilder::contains(TypeIndex Index) {
+ if (Index.isSimple() || Index.isNoneType())
+ return false;
+
+ return Index.toArrayIndex() < SeenRecords.size();
+}
+
+uint32_t MergingTypeTableBuilder::size() { return SeenRecords.size(); }
+
+uint32_t MergingTypeTableBuilder::capacity() { return SeenRecords.size(); }
+
+ArrayRef<ArrayRef<uint8_t>> MergingTypeTableBuilder::records() const {
+ return SeenRecords;
+}
+
+void MergingTypeTableBuilder::reset() {
+ HashedRecords.clear();
+ SeenRecords.clear();
+}
+
+static inline ArrayRef<uint8_t> stabilize(BumpPtrAllocator &Alloc,
+ ArrayRef<uint8_t> Data) {
+ uint8_t *Stable = Alloc.Allocate<uint8_t>(Data.size());
+ memcpy(Stable, Data.data(), Data.size());
+ return makeArrayRef(Stable, Data.size());
+}
+
+TypeIndex MergingTypeTableBuilder::insertRecordAs(hash_code Hash,
+ ArrayRef<uint8_t> &Record) {
+ assert(Record.size() < UINT32_MAX && "Record too big");
+ assert(Record.size() % 4 == 0 &&
+ "The type record size is not a multiple of 4 bytes which will cause "
+ "misalignment in the output TPI stream!");
+
+ LocallyHashedType WeakHash{Hash, Record};
+ auto Result = HashedRecords.try_emplace(WeakHash, nextTypeIndex());
+
+ if (Result.second) {
+ ArrayRef<uint8_t> RecordData = stabilize(RecordStorage, Record);
+ Result.first->first.RecordData = RecordData;
+ SeenRecords.push_back(RecordData);
+ }
+
+ // Update the caller's copy of Record to point a stable copy.
+ TypeIndex ActualTI = Result.first->second;
+ Record = SeenRecords[ActualTI.toArrayIndex()];
+ return ActualTI;
+}
+
+TypeIndex
+MergingTypeTableBuilder::insertRecordBytes(ArrayRef<uint8_t> &Record) {
+ return insertRecordAs(hash_value(Record), Record);
+}
+
+TypeIndex
+MergingTypeTableBuilder::insertRecord(ContinuationRecordBuilder &Builder) {
+ TypeIndex TI;
+ auto Fragments = Builder.end(nextTypeIndex());
+ assert(!Fragments.empty());
+ for (auto C : Fragments)
+ TI = insertRecordBytes(C.RecordData);
+ return TI;
+}
+
+bool MergingTypeTableBuilder::replaceType(TypeIndex &Index, CVType Data,
+ bool Stabilize) {
+ assert(Index.toArrayIndex() < SeenRecords.size() &&
+ "This function cannot be used to insert records!");
+
+ ArrayRef<uint8_t> Record = Data.data();
+ assert(Record.size() < UINT32_MAX && "Record too big");
+ assert(Record.size() % 4 == 0 &&
+ "The type record size is not a multiple of 4 bytes which will cause "
+ "misalignment in the output TPI stream!");
+
+ LocallyHashedType WeakHash{hash_value(Record), Record};
+ auto Result = HashedRecords.try_emplace(WeakHash, Index.toArrayIndex());
+ if (!Result.second) {
+ Index = Result.first->second;
+ return false; // The record is already there, at a different location
+ }
+
+ if (Stabilize) {
+ Record = stabilize(RecordStorage, Record);
+ Result.first->first.RecordData = Record;
+ }
+
+ SeenRecords[Index.toArrayIndex()] = Record;
+ return true;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/RecordName.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/RecordName.cpp
new file mode 100644
index 0000000000..1ca899789b
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/RecordName.cpp
@@ -0,0 +1,339 @@
+//===- RecordName.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/RecordName.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecordMapping.h"
+#include "llvm/DebugInfo/CodeView/TypeVisitorCallbacks.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+class TypeNameComputer : public TypeVisitorCallbacks {
+ /// The type collection. Used to calculate names of nested types.
+ TypeCollection &Types;
+ TypeIndex CurrentTypeIndex = TypeIndex::None();
+
+ /// Name of the current type. Only valid before visitTypeEnd.
+ SmallString<256> Name;
+
+public:
+ explicit TypeNameComputer(TypeCollection &Types) : Types(Types) {}
+
+ StringRef name() const { return Name; }
+
+ /// Paired begin/end actions for all types. Receives all record data,
+ /// including the fixed-length record prefix.
+ Error visitTypeBegin(CVType &Record) override;
+ Error visitTypeBegin(CVType &Record, TypeIndex Index) override;
+ Error visitTypeEnd(CVType &Record) override;
+
+#define TYPE_RECORD(EnumName, EnumVal, Name) \
+ Error visitKnownRecord(CVType &CVR, Name##Record &Record) override;
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#define MEMBER_RECORD(EnumName, EnumVal, Name)
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+};
+} // namespace
+
+Error TypeNameComputer::visitTypeBegin(CVType &Record) {
+ llvm_unreachable("Must call visitTypeBegin with a TypeIndex!");
+ return Error::success();
+}
+
+Error TypeNameComputer::visitTypeBegin(CVType &Record, TypeIndex Index) {
+ // Reset Name to the empty string. If the visitor sets it, we know it.
+ Name = "";
+ CurrentTypeIndex = Index;
+ return Error::success();
+}
+
+Error TypeNameComputer::visitTypeEnd(CVType &CVR) { return Error::success(); }
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR,
+ FieldListRecord &FieldList) {
+ Name = "<field list>";
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVRecord<TypeLeafKind> &CVR,
+ StringIdRecord &String) {
+ Name = String.getString();
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArgListRecord &Args) {
+ auto Indices = Args.getIndices();
+ uint32_t Size = Indices.size();
+ Name = "(";
+ for (uint32_t I = 0; I < Size; ++I) {
+ if (Indices[I] < CurrentTypeIndex)
+ Name.append(Types.getTypeName(Indices[I]));
+ else
+ Name.append("<unknown 0x" + utohexstr(Indices[I].getIndex()) + ">");
+ if (I + 1 != Size)
+ Name.append(", ");
+ }
+ Name.push_back(')');
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR,
+ StringListRecord &Strings) {
+ auto Indices = Strings.getIndices();
+ uint32_t Size = Indices.size();
+ Name = "\"";
+ for (uint32_t I = 0; I < Size; ++I) {
+ Name.append(Types.getTypeName(Indices[I]));
+ if (I + 1 != Size)
+ Name.append("\" \"");
+ }
+ Name.push_back('\"');
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, ClassRecord &Class) {
+ Name = Class.getName();
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, UnionRecord &Union) {
+ Name = Union.getName();
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
+ Name = Enum.getName();
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
+ Name = AT.getName();
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) {
+ Name = VFT.getName();
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) {
+ Name = Id.getName();
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) {
+ StringRef Ret = Types.getTypeName(Proc.getReturnType());
+ StringRef Params = Types.getTypeName(Proc.getArgumentList());
+ Name = formatv("{0} {1}", Ret, Params).sstr<256>();
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR,
+ MemberFunctionRecord &MF) {
+ StringRef Ret = Types.getTypeName(MF.getReturnType());
+ StringRef Class = Types.getTypeName(MF.getClassType());
+ StringRef Params = Types.getTypeName(MF.getArgumentList());
+ Name = formatv("{0} {1}::{2}", Ret, Class, Params).sstr<256>();
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) {
+ Name = Func.getName();
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) {
+ Name = TS.getName();
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) {
+
+ if (Ptr.isPointerToMember()) {
+ const MemberPointerInfo &MI = Ptr.getMemberInfo();
+
+ StringRef Pointee = Types.getTypeName(Ptr.getReferentType());
+ StringRef Class = Types.getTypeName(MI.getContainingType());
+ Name = formatv("{0} {1}::*", Pointee, Class);
+ } else {
+ Name.append(Types.getTypeName(Ptr.getReferentType()));
+
+ if (Ptr.getMode() == PointerMode::LValueReference)
+ Name.append("&");
+ else if (Ptr.getMode() == PointerMode::RValueReference)
+ Name.append("&&");
+ else if (Ptr.getMode() == PointerMode::Pointer)
+ Name.append("*");
+
+ // Qualifiers in pointer records apply to the pointer, not the pointee, so
+ // they go on the right.
+ if (Ptr.isConst())
+ Name.append(" const");
+ if (Ptr.isVolatile())
+ Name.append(" volatile");
+ if (Ptr.isUnaligned())
+ Name.append(" __unaligned");
+ if (Ptr.isRestrict())
+ Name.append(" __restrict");
+ }
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
+ uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
+
+ if (Mods & uint16_t(ModifierOptions::Const))
+ Name.append("const ");
+ if (Mods & uint16_t(ModifierOptions::Volatile))
+ Name.append("volatile ");
+ if (Mods & uint16_t(ModifierOptions::Unaligned))
+ Name.append("__unaligned ");
+ Name.append(Types.getTypeName(Mod.getModifiedType()));
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR,
+ VFTableShapeRecord &Shape) {
+ Name = formatv("<vftable {0} methods>", Shape.getEntryCount());
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(
+ CVType &CVR, UdtModSourceLineRecord &ModSourceLine) {
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR,
+ UdtSourceLineRecord &SourceLine) {
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, BitFieldRecord &BF) {
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR,
+ MethodOverloadListRecord &Overloads) {
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, BuildInfoRecord &BI) {
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR, LabelRecord &R) {
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR,
+ PrecompRecord &Precomp) {
+ return Error::success();
+}
+
+Error TypeNameComputer::visitKnownRecord(CVType &CVR,
+ EndPrecompRecord &EndPrecomp) {
+ return Error::success();
+}
+
+std::string llvm::codeview::computeTypeName(TypeCollection &Types,
+ TypeIndex Index) {
+ TypeNameComputer Computer(Types);
+ CVType Record = Types.getType(Index);
+ if (auto EC = visitTypeRecord(Record, Index, Computer)) {
+ consumeError(std::move(EC));
+ return "<unknown UDT>";
+ }
+ return std::string(Computer.name());
+}
+
+static int getSymbolNameOffset(CVSymbol Sym) {
+ switch (Sym.kind()) {
+ // See ProcSym
+ case SymbolKind::S_GPROC32:
+ case SymbolKind::S_LPROC32:
+ case SymbolKind::S_GPROC32_ID:
+ case SymbolKind::S_LPROC32_ID:
+ case SymbolKind::S_LPROC32_DPC:
+ case SymbolKind::S_LPROC32_DPC_ID:
+ return 35;
+ // See Thunk32Sym
+ case SymbolKind::S_THUNK32:
+ return 21;
+ // See SectionSym
+ case SymbolKind::S_SECTION:
+ return 16;
+ // See CoffGroupSym
+ case SymbolKind::S_COFFGROUP:
+ return 14;
+ // See PublicSym32, FileStaticSym, RegRelativeSym, DataSym, ThreadLocalDataSym
+ case SymbolKind::S_PUB32:
+ case SymbolKind::S_FILESTATIC:
+ case SymbolKind::S_REGREL32:
+ case SymbolKind::S_GDATA32:
+ case SymbolKind::S_LDATA32:
+ case SymbolKind::S_LMANDATA:
+ case SymbolKind::S_GMANDATA:
+ case SymbolKind::S_LTHREAD32:
+ case SymbolKind::S_GTHREAD32:
+ case SymbolKind::S_PROCREF:
+ case SymbolKind::S_LPROCREF:
+ return 10;
+ // See RegisterSym and LocalSym
+ case SymbolKind::S_REGISTER:
+ case SymbolKind::S_LOCAL:
+ return 6;
+ // See BlockSym
+ case SymbolKind::S_BLOCK32:
+ return 18;
+ // See LabelSym
+ case SymbolKind::S_LABEL32:
+ return 7;
+ // See ObjNameSym, ExportSym, and UDTSym
+ case SymbolKind::S_OBJNAME:
+ case SymbolKind::S_EXPORT:
+ case SymbolKind::S_UDT:
+ return 4;
+ // See BPRelativeSym
+ case SymbolKind::S_BPREL32:
+ return 8;
+ // See UsingNamespaceSym
+ case SymbolKind::S_UNAMESPACE:
+ return 0;
+ default:
+ return -1;
+ }
+}
+
+StringRef llvm::codeview::getSymbolName(CVSymbol Sym) {
+ if (Sym.kind() == SymbolKind::S_CONSTANT) {
+ // S_CONSTANT is preceded by an APSInt, which has a variable length. So we
+ // have to do a full deserialization.
+ BinaryStreamReader Reader(Sym.content(), llvm::support::little);
+ // The container doesn't matter for single records.
+ SymbolRecordMapping Mapping(Reader, CodeViewContainer::ObjectFile);
+ ConstantSym Const(SymbolKind::S_CONSTANT);
+ cantFail(Mapping.visitSymbolBegin(Sym));
+ cantFail(Mapping.visitKnownRecord(Sym, Const));
+ cantFail(Mapping.visitSymbolEnd(Sym));
+ return Const.Name;
+ }
+
+ int Offset = getSymbolNameOffset(Sym);
+ if (Offset == -1)
+ return StringRef();
+
+ StringRef StringData = toStringRef(Sym.content()).drop_front(Offset);
+ return StringData.split('\0').first;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/RecordSerialization.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/RecordSerialization.cpp
new file mode 100644
index 0000000000..63ce302a4e
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/RecordSerialization.cpp
@@ -0,0 +1,154 @@
+//===-- RecordSerialization.cpp -------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Utilities for serializing and deserializing CodeView records.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/DebugInfo/CodeView/CodeViewError.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/Support/BinaryByteStream.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::support;
+
+/// Reinterpret a byte array as an array of characters. Does not interpret as
+/// a C string, as StringRef has several helpers (split) that make that easy.
+StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {
+ return StringRef(reinterpret_cast<const char *>(LeafData.data()),
+ LeafData.size());
+}
+
+StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) {
+ return getBytesAsCharacters(LeafData).split('\0').first;
+}
+
+Error llvm::codeview::consume(BinaryStreamReader &Reader, APSInt &Num) {
+ // Used to avoid overload ambiguity on APInt constructor.
+ bool FalseVal = false;
+ uint16_t Short;
+ if (auto EC = Reader.readInteger(Short))
+ return EC;
+
+ if (Short < LF_NUMERIC) {
+ Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false),
+ /*isUnsigned=*/true);
+ return Error::success();
+ }
+
+ switch (Short) {
+ case LF_CHAR: {
+ int8_t N;
+ if (auto EC = Reader.readInteger(N))
+ return EC;
+ Num = APSInt(APInt(8, N, true), false);
+ return Error::success();
+ }
+ case LF_SHORT: {
+ int16_t N;
+ if (auto EC = Reader.readInteger(N))
+ return EC;
+ Num = APSInt(APInt(16, N, true), false);
+ return Error::success();
+ }
+ case LF_USHORT: {
+ uint16_t N;
+ if (auto EC = Reader.readInteger(N))
+ return EC;
+ Num = APSInt(APInt(16, N, false), true);
+ return Error::success();
+ }
+ case LF_LONG: {
+ int32_t N;
+ if (auto EC = Reader.readInteger(N))
+ return EC;
+ Num = APSInt(APInt(32, N, true), false);
+ return Error::success();
+ }
+ case LF_ULONG: {
+ uint32_t N;
+ if (auto EC = Reader.readInteger(N))
+ return EC;
+ Num = APSInt(APInt(32, N, FalseVal), true);
+ return Error::success();
+ }
+ case LF_QUADWORD: {
+ int64_t N;
+ if (auto EC = Reader.readInteger(N))
+ return EC;
+ Num = APSInt(APInt(64, N, true), false);
+ return Error::success();
+ }
+ case LF_UQUADWORD: {
+ uint64_t N;
+ if (auto EC = Reader.readInteger(N))
+ return EC;
+ Num = APSInt(APInt(64, N, false), true);
+ return Error::success();
+ }
+ }
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Buffer contains invalid APSInt type");
+}
+
+Error llvm::codeview::consume(StringRef &Data, APSInt &Num) {
+ ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
+ BinaryByteStream S(Bytes, llvm::support::little);
+ BinaryStreamReader SR(S);
+ auto EC = consume(SR, Num);
+ Data = Data.take_back(SR.bytesRemaining());
+ return EC;
+}
+
+/// Decode a numeric leaf value that is known to be a uint64_t.
+Error llvm::codeview::consume_numeric(BinaryStreamReader &Reader,
+ uint64_t &Num) {
+ APSInt N;
+ if (auto EC = consume(Reader, N))
+ return EC;
+ if (N.isSigned() || !N.isIntN(64))
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Data is not a numeric value!");
+ Num = N.getLimitedValue();
+ return Error::success();
+}
+
+Error llvm::codeview::consume(BinaryStreamReader &Reader, uint32_t &Item) {
+ return Reader.readInteger(Item);
+}
+
+Error llvm::codeview::consume(StringRef &Data, uint32_t &Item) {
+ ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
+ BinaryByteStream S(Bytes, llvm::support::little);
+ BinaryStreamReader SR(S);
+ auto EC = consume(SR, Item);
+ Data = Data.take_back(SR.bytesRemaining());
+ return EC;
+}
+
+Error llvm::codeview::consume(BinaryStreamReader &Reader, int32_t &Item) {
+ return Reader.readInteger(Item);
+}
+
+Error llvm::codeview::consume(BinaryStreamReader &Reader, StringRef &Item) {
+ if (Reader.empty())
+ return make_error<CodeViewError>(cv_error_code::corrupt_record,
+ "Null terminated string buffer is empty!");
+
+ return Reader.readCString(Item);
+}
+
+Expected<CVSymbol> llvm::codeview::readSymbolFromStream(BinaryStreamRef Stream,
+ uint32_t Offset) {
+ return readCVRecordFromStream<SymbolKind>(Stream, Offset);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp
new file mode 100644
index 0000000000..d963e34628
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/SimpleTypeSerializer.cpp
@@ -0,0 +1,67 @@
+//===- SimpleTypeSerializer.cpp -----------------------------------------===//
+//
+// 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/SimpleTypeSerializer.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecordMapping.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+static void addPadding(BinaryStreamWriter &Writer) {
+ uint32_t Align = Writer.getOffset() % 4;
+ if (Align == 0)
+ return;
+
+ int PaddingBytes = 4 - Align;
+ while (PaddingBytes > 0) {
+ uint8_t Pad = static_cast<uint8_t>(LF_PAD0 + PaddingBytes);
+ cantFail(Writer.writeInteger(Pad));
+ --PaddingBytes;
+ }
+}
+
+SimpleTypeSerializer::SimpleTypeSerializer() : ScratchBuffer(MaxRecordLength) {}
+
+SimpleTypeSerializer::~SimpleTypeSerializer() {}
+
+template <typename T>
+ArrayRef<uint8_t> SimpleTypeSerializer::serialize(T &Record) {
+ BinaryStreamWriter Writer(ScratchBuffer, support::little);
+ TypeRecordMapping Mapping(Writer);
+
+ // Write the record prefix first with a dummy length but real kind.
+ RecordPrefix DummyPrefix(uint16_t(Record.getKind()));
+ cantFail(Writer.writeObject(DummyPrefix));
+
+ RecordPrefix *Prefix = reinterpret_cast<RecordPrefix *>(ScratchBuffer.data());
+ CVType CVT(Prefix, sizeof(RecordPrefix));
+
+ cantFail(Mapping.visitTypeBegin(CVT));
+ cantFail(Mapping.visitKnownRecord(CVT, Record));
+ cantFail(Mapping.visitTypeEnd(CVT));
+
+ addPadding(Writer);
+
+ // Update the size and kind after serialization.
+ Prefix->RecordKind = CVT.kind();
+ Prefix->RecordLen = Writer.getOffset() - sizeof(uint16_t);
+
+ return {ScratchBuffer.data(), static_cast<size_t>(Writer.getOffset())};
+}
+
+// Explicitly instantiate the member function for each known type so that we can
+// implement this in the cpp file.
+#define TYPE_RECORD(EnumName, EnumVal, Name) \
+ template ArrayRef<uint8_t> llvm::codeview::SimpleTypeSerializer::serialize( \
+ Name##Record &Record);
+#define TYPE_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#define MEMBER_RECORD(EnumName, EnumVal, Name)
+#define MEMBER_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/StringsAndChecksums.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/StringsAndChecksums.cpp
new file mode 100644
index 0000000000..9e204eec86
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/StringsAndChecksums.cpp
@@ -0,0 +1,80 @@
+//===- StringsAndChecksums.cpp --------------------------------------------===//
+//
+// 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/StringsAndChecksums.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+#include "llvm/Support/Error.h"
+#include <cassert>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+StringsAndChecksumsRef::StringsAndChecksumsRef() = default;
+
+StringsAndChecksumsRef::StringsAndChecksumsRef(
+ const DebugStringTableSubsectionRef &Strings)
+ : Strings(&Strings) {}
+
+StringsAndChecksumsRef::StringsAndChecksumsRef(
+ const DebugStringTableSubsectionRef &Strings,
+ const DebugChecksumsSubsectionRef &Checksums)
+ : Strings(&Strings), Checksums(&Checksums) {}
+
+void StringsAndChecksumsRef::initializeStrings(
+ const DebugSubsectionRecord &SR) {
+ assert(SR.kind() == DebugSubsectionKind::StringTable);
+ assert(!Strings && "Found a string table even though we already have one!");
+
+ OwnedStrings = std::make_shared<DebugStringTableSubsectionRef>();
+ consumeError(OwnedStrings->initialize(SR.getRecordData()));
+ Strings = OwnedStrings.get();
+}
+
+void StringsAndChecksumsRef::reset() {
+ resetStrings();
+ resetChecksums();
+}
+
+void StringsAndChecksumsRef::resetStrings() {
+ OwnedStrings.reset();
+ Strings = nullptr;
+}
+
+void StringsAndChecksumsRef::resetChecksums() {
+ OwnedChecksums.reset();
+ Checksums = nullptr;
+}
+
+void StringsAndChecksumsRef::setStrings(
+ const DebugStringTableSubsectionRef &StringsRef) {
+ OwnedStrings = std::make_shared<DebugStringTableSubsectionRef>();
+ *OwnedStrings = StringsRef;
+ Strings = OwnedStrings.get();
+}
+
+void StringsAndChecksumsRef::setChecksums(
+ const DebugChecksumsSubsectionRef &CS) {
+ OwnedChecksums = std::make_shared<DebugChecksumsSubsectionRef>();
+ *OwnedChecksums = CS;
+ Checksums = OwnedChecksums.get();
+}
+
+void StringsAndChecksumsRef::initializeChecksums(
+ const DebugSubsectionRecord &FCR) {
+ assert(FCR.kind() == DebugSubsectionKind::FileChecksums);
+ if (Checksums)
+ return;
+
+ OwnedChecksums = std::make_shared<DebugChecksumsSubsectionRef>();
+ consumeError(OwnedChecksums->initialize(FCR.getRecordData()));
+ Checksums = OwnedChecksums.get();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/SymbolDumper.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/SymbolDumper.cpp
new file mode 100644
index 0000000000..45b63983be
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/SymbolDumper.cpp
@@ -0,0 +1,679 @@
+//===-- SymbolDumper.cpp - CodeView symbol info dumper ----------*- 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/SymbolDumper.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/DebugInfo/CodeView/CVSymbolVisitor.h"
+#include "llvm/DebugInfo/CodeView/DebugStringTableSubsection.h"
+#include "llvm/DebugInfo/CodeView/EnumTables.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolDumpDelegate.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbackPipeline.h"
+#include "llvm/DebugInfo/CodeView/SymbolVisitorCallbacks.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+#include <system_error>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+/// Use this private dumper implementation to keep implementation details about
+/// the visitor out of SymbolDumper.h.
+class CVSymbolDumperImpl : public SymbolVisitorCallbacks {
+public:
+ CVSymbolDumperImpl(TypeCollection &Types, SymbolDumpDelegate *ObjDelegate,
+ ScopedPrinter &W, CPUType CPU, bool PrintRecordBytes)
+ : Types(Types), ObjDelegate(ObjDelegate), W(W), CompilationCPUType(CPU),
+ PrintRecordBytes(PrintRecordBytes), InFunctionScope(false) {}
+
+/// CVSymbolVisitor overrides.
+#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
+ Error visitKnownRecord(CVSymbol &CVR, Name &Record) override;
+#define SYMBOL_RECORD_ALIAS(EnumName, EnumVal, Name, AliasName)
+#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
+
+ Error visitSymbolBegin(CVSymbol &Record) override;
+ Error visitSymbolEnd(CVSymbol &Record) override;
+ Error visitUnknownSymbol(CVSymbol &Record) override;
+
+ CPUType getCompilationCPUType() const { return CompilationCPUType; }
+
+private:
+ void printLocalVariableAddrRange(const LocalVariableAddrRange &Range,
+ uint32_t RelocationOffset);
+ void printLocalVariableAddrGap(ArrayRef<LocalVariableAddrGap> Gaps);
+ void printTypeIndex(StringRef FieldName, TypeIndex TI);
+
+ TypeCollection &Types;
+ SymbolDumpDelegate *ObjDelegate;
+ ScopedPrinter &W;
+
+ /// Save the machine or CPU type when dumping a compile symbols.
+ CPUType CompilationCPUType = CPUType::X64;
+
+ bool PrintRecordBytes;
+ bool InFunctionScope;
+};
+}
+
+static StringRef getSymbolKindName(SymbolKind Kind) {
+ switch (Kind) {
+#define SYMBOL_RECORD(EnumName, EnumVal, Name) \
+ case EnumName: \
+ return #Name;
+#include "llvm/DebugInfo/CodeView/CodeViewSymbols.def"
+ default:
+ break;
+ }
+ return "UnknownSym";
+}
+
+void CVSymbolDumperImpl::printLocalVariableAddrRange(
+ const LocalVariableAddrRange &Range, uint32_t RelocationOffset) {
+ DictScope S(W, "LocalVariableAddrRange");
+ if (ObjDelegate)
+ ObjDelegate->printRelocatedField("OffsetStart", RelocationOffset,
+ Range.OffsetStart);
+ W.printHex("ISectStart", Range.ISectStart);
+ W.printHex("Range", Range.Range);
+}
+
+void CVSymbolDumperImpl::printLocalVariableAddrGap(
+ ArrayRef<LocalVariableAddrGap> Gaps) {
+ for (auto &Gap : Gaps) {
+ ListScope S(W, "LocalVariableAddrGap");
+ W.printHex("GapStartOffset", Gap.GapStartOffset);
+ W.printHex("Range", Gap.Range);
+ }
+}
+
+void CVSymbolDumperImpl::printTypeIndex(StringRef FieldName, TypeIndex TI) {
+ codeview::printTypeIndex(W, FieldName, TI, Types);
+}
+
+Error CVSymbolDumperImpl::visitSymbolBegin(CVSymbol &CVR) {
+ W.startLine() << getSymbolKindName(CVR.kind());
+ W.getOStream() << " {\n";
+ W.indent();
+ W.printEnum("Kind", unsigned(CVR.kind()), getSymbolTypeNames());
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitSymbolEnd(CVSymbol &CVR) {
+ if (PrintRecordBytes && ObjDelegate)
+ ObjDelegate->printBinaryBlockWithRelocs("SymData", CVR.content());
+
+ W.unindent();
+ W.startLine() << "}\n";
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, BlockSym &Block) {
+ StringRef LinkageName;
+ W.printHex("PtrParent", Block.Parent);
+ W.printHex("PtrEnd", Block.End);
+ W.printHex("CodeSize", Block.CodeSize);
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset", Block.getRelocationOffset(),
+ Block.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", Block.Segment);
+ W.printString("BlockName", Block.Name);
+ W.printString("LinkageName", LinkageName);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, Thunk32Sym &Thunk) {
+ W.printString("Name", Thunk.Name);
+ W.printNumber("Parent", Thunk.Parent);
+ W.printNumber("End", Thunk.End);
+ W.printNumber("Next", Thunk.Next);
+ W.printNumber("Off", Thunk.Offset);
+ W.printNumber("Seg", Thunk.Segment);
+ W.printNumber("Len", Thunk.Length);
+ W.printEnum("Ordinal", uint8_t(Thunk.Thunk), getThunkOrdinalNames());
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ TrampolineSym &Tramp) {
+ W.printEnum("Type", uint16_t(Tramp.Type), getTrampolineNames());
+ W.printNumber("Size", Tramp.Size);
+ W.printNumber("ThunkOff", Tramp.ThunkOffset);
+ W.printNumber("TargetOff", Tramp.TargetOffset);
+ W.printNumber("ThunkSection", Tramp.ThunkSection);
+ W.printNumber("TargetSection", Tramp.TargetSection);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, SectionSym &Section) {
+ W.printNumber("SectionNumber", Section.SectionNumber);
+ W.printNumber("Alignment", Section.Alignment);
+ W.printNumber("Rva", Section.Rva);
+ W.printNumber("Length", Section.Length);
+ W.printFlags("Characteristics", Section.Characteristics,
+ getImageSectionCharacteristicNames(),
+ COFF::SectionCharacteristics(0x00F00000));
+
+ W.printString("Name", Section.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ CoffGroupSym &CoffGroup) {
+ W.printNumber("Size", CoffGroup.Size);
+ W.printFlags("Characteristics", CoffGroup.Characteristics,
+ getImageSectionCharacteristicNames(),
+ COFF::SectionCharacteristics(0x00F00000));
+ W.printNumber("Offset", CoffGroup.Offset);
+ W.printNumber("Segment", CoffGroup.Segment);
+ W.printString("Name", CoffGroup.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ BPRelativeSym &BPRel) {
+ W.printNumber("Offset", BPRel.Offset);
+ printTypeIndex("Type", BPRel.Type);
+ W.printString("VarName", BPRel.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ BuildInfoSym &BuildInfo) {
+ printTypeIndex("BuildId", BuildInfo.BuildId);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ CallSiteInfoSym &CallSiteInfo) {
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset",
+ CallSiteInfo.getRelocationOffset(),
+ CallSiteInfo.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", CallSiteInfo.Segment);
+ printTypeIndex("Type", CallSiteInfo.Type);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ EnvBlockSym &EnvBlock) {
+ ListScope L(W, "Entries");
+ for (auto Entry : EnvBlock.Fields) {
+ W.printString(Entry);
+ }
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ FileStaticSym &FileStatic) {
+ printTypeIndex("Index", FileStatic.Index);
+ W.printNumber("ModFilenameOffset", FileStatic.ModFilenameOffset);
+ W.printFlags("Flags", uint16_t(FileStatic.Flags), getLocalFlagNames());
+ W.printString("Name", FileStatic.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ExportSym &Export) {
+ W.printNumber("Ordinal", Export.Ordinal);
+ W.printFlags("Flags", uint16_t(Export.Flags), getExportSymFlagNames());
+ W.printString("Name", Export.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ Compile2Sym &Compile2) {
+ W.printEnum("Language", Compile2.getLanguage(), getSourceLanguageNames());
+ W.printFlags("Flags", Compile2.getFlags(), getCompileSym2FlagNames());
+ W.printEnum("Machine", unsigned(Compile2.Machine), getCPUTypeNames());
+ CompilationCPUType = Compile2.Machine;
+ std::string FrontendVersion;
+ {
+ raw_string_ostream Out(FrontendVersion);
+ Out << Compile2.VersionFrontendMajor << '.' << Compile2.VersionFrontendMinor
+ << '.' << Compile2.VersionFrontendBuild;
+ }
+ std::string BackendVersion;
+ {
+ raw_string_ostream Out(BackendVersion);
+ Out << Compile2.VersionBackendMajor << '.' << Compile2.VersionBackendMinor
+ << '.' << Compile2.VersionBackendBuild;
+ }
+ W.printString("FrontendVersion", FrontendVersion);
+ W.printString("BackendVersion", BackendVersion);
+ W.printString("VersionName", Compile2.Version);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ Compile3Sym &Compile3) {
+ W.printEnum("Language", uint8_t(Compile3.getLanguage()), getSourceLanguageNames());
+ W.printFlags("Flags", uint32_t(Compile3.getFlags()),
+ getCompileSym3FlagNames());
+ W.printEnum("Machine", unsigned(Compile3.Machine), getCPUTypeNames());
+ CompilationCPUType = Compile3.Machine;
+ std::string FrontendVersion;
+ {
+ raw_string_ostream Out(FrontendVersion);
+ Out << Compile3.VersionFrontendMajor << '.' << Compile3.VersionFrontendMinor
+ << '.' << Compile3.VersionFrontendBuild << '.'
+ << Compile3.VersionFrontendQFE;
+ }
+ std::string BackendVersion;
+ {
+ raw_string_ostream Out(BackendVersion);
+ Out << Compile3.VersionBackendMajor << '.' << Compile3.VersionBackendMinor
+ << '.' << Compile3.VersionBackendBuild << '.'
+ << Compile3.VersionBackendQFE;
+ }
+ W.printString("FrontendVersion", FrontendVersion);
+ W.printString("BackendVersion", BackendVersion);
+ W.printString("VersionName", Compile3.Version);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ ConstantSym &Constant) {
+ printTypeIndex("Type", Constant.Type);
+ W.printNumber("Value", Constant.Value);
+ W.printString("Name", Constant.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, DataSym &Data) {
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(),
+ Data.DataOffset, &LinkageName);
+ }
+ printTypeIndex("Type", Data.Type);
+ W.printString("DisplayName", Data.Name);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR,
+ DefRangeFramePointerRelFullScopeSym &DefRangeFramePointerRelFullScope) {
+ W.printNumber("Offset", DefRangeFramePointerRelFullScope.Offset);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR, DefRangeFramePointerRelSym &DefRangeFramePointerRel) {
+ W.printNumber("Offset", DefRangeFramePointerRel.Hdr.Offset);
+ printLocalVariableAddrRange(DefRangeFramePointerRel.Range,
+ DefRangeFramePointerRel.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeFramePointerRel.Gaps);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR, DefRangeRegisterRelSym &DefRangeRegisterRel) {
+ W.printEnum("BaseRegister", uint16_t(DefRangeRegisterRel.Hdr.Register),
+ getRegisterNames(CompilationCPUType));
+ W.printBoolean("HasSpilledUDTMember",
+ DefRangeRegisterRel.hasSpilledUDTMember());
+ W.printNumber("OffsetInParent", DefRangeRegisterRel.offsetInParent());
+ W.printNumber("BasePointerOffset", DefRangeRegisterRel.Hdr.BasePointerOffset);
+ printLocalVariableAddrRange(DefRangeRegisterRel.Range,
+ DefRangeRegisterRel.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeRegisterRel.Gaps);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR, DefRangeRegisterSym &DefRangeRegister) {
+ W.printEnum("Register", uint16_t(DefRangeRegister.Hdr.Register),
+ getRegisterNames(CompilationCPUType));
+ W.printNumber("MayHaveNoName", DefRangeRegister.Hdr.MayHaveNoName);
+ printLocalVariableAddrRange(DefRangeRegister.Range,
+ DefRangeRegister.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeRegister.Gaps);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) {
+ W.printEnum("Register", uint16_t(DefRangeSubfieldRegister.Hdr.Register),
+ getRegisterNames(CompilationCPUType));
+ W.printNumber("MayHaveNoName", DefRangeSubfieldRegister.Hdr.MayHaveNoName);
+ W.printNumber("OffsetInParent", DefRangeSubfieldRegister.Hdr.OffsetInParent);
+ printLocalVariableAddrRange(DefRangeSubfieldRegister.Range,
+ DefRangeSubfieldRegister.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeSubfieldRegister.Gaps);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR, DefRangeSubfieldSym &DefRangeSubfield) {
+ if (ObjDelegate) {
+ DebugStringTableSubsectionRef Strings = ObjDelegate->getStringTable();
+ auto ExpectedProgram = Strings.getString(DefRangeSubfield.Program);
+ if (!ExpectedProgram) {
+ consumeError(ExpectedProgram.takeError());
+ return llvm::make_error<CodeViewError>(
+ "String table offset outside of bounds of String Table!");
+ }
+ W.printString("Program", *ExpectedProgram);
+ }
+ W.printNumber("OffsetInParent", DefRangeSubfield.OffsetInParent);
+ printLocalVariableAddrRange(DefRangeSubfield.Range,
+ DefRangeSubfield.getRelocationOffset());
+ printLocalVariableAddrGap(DefRangeSubfield.Gaps);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ DefRangeSym &DefRange) {
+ if (ObjDelegate) {
+ DebugStringTableSubsectionRef Strings = ObjDelegate->getStringTable();
+ auto ExpectedProgram = Strings.getString(DefRange.Program);
+ if (!ExpectedProgram) {
+ consumeError(ExpectedProgram.takeError());
+ return llvm::make_error<CodeViewError>(
+ "String table offset outside of bounds of String Table!");
+ }
+ W.printString("Program", *ExpectedProgram);
+ }
+ printLocalVariableAddrRange(DefRange.Range, DefRange.getRelocationOffset());
+ printLocalVariableAddrGap(DefRange.Gaps);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ FrameCookieSym &FrameCookie) {
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset",
+ FrameCookie.getRelocationOffset(),
+ FrameCookie.CodeOffset, &LinkageName);
+ }
+ W.printEnum("Register", uint16_t(FrameCookie.Register),
+ getRegisterNames(CompilationCPUType));
+ W.printEnum("CookieKind", uint16_t(FrameCookie.CookieKind),
+ getFrameCookieKindNames());
+ W.printHex("Flags", FrameCookie.Flags);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ FrameProcSym &FrameProc) {
+ W.printHex("TotalFrameBytes", FrameProc.TotalFrameBytes);
+ W.printHex("PaddingFrameBytes", FrameProc.PaddingFrameBytes);
+ W.printHex("OffsetToPadding", FrameProc.OffsetToPadding);
+ W.printHex("BytesOfCalleeSavedRegisters",
+ FrameProc.BytesOfCalleeSavedRegisters);
+ W.printHex("OffsetOfExceptionHandler", FrameProc.OffsetOfExceptionHandler);
+ W.printHex("SectionIdOfExceptionHandler",
+ FrameProc.SectionIdOfExceptionHandler);
+ W.printFlags("Flags", static_cast<uint32_t>(FrameProc.Flags),
+ getFrameProcSymFlagNames());
+ W.printEnum("LocalFramePtrReg",
+ uint16_t(FrameProc.getLocalFramePtrReg(CompilationCPUType)),
+ getRegisterNames(CompilationCPUType));
+ W.printEnum("ParamFramePtrReg",
+ uint16_t(FrameProc.getParamFramePtrReg(CompilationCPUType)),
+ getRegisterNames(CompilationCPUType));
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(
+ CVSymbol &CVR, HeapAllocationSiteSym &HeapAllocSite) {
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset",
+ HeapAllocSite.getRelocationOffset(),
+ HeapAllocSite.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", HeapAllocSite.Segment);
+ W.printHex("CallInstructionSize", HeapAllocSite.CallInstructionSize);
+ printTypeIndex("Type", HeapAllocSite.Type);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ InlineSiteSym &InlineSite) {
+ W.printHex("PtrParent", InlineSite.Parent);
+ W.printHex("PtrEnd", InlineSite.End);
+ printTypeIndex("Inlinee", InlineSite.Inlinee);
+
+ ListScope BinaryAnnotations(W, "BinaryAnnotations");
+ for (auto &Annotation : InlineSite.annotations()) {
+ switch (Annotation.OpCode) {
+ case BinaryAnnotationsOpCode::Invalid:
+ W.printString("(Annotation Padding)");
+ break;
+ case BinaryAnnotationsOpCode::CodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeLength:
+ W.printHex(Annotation.Name, Annotation.U1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetBase:
+ case BinaryAnnotationsOpCode::ChangeLineEndDelta:
+ case BinaryAnnotationsOpCode::ChangeRangeKind:
+ case BinaryAnnotationsOpCode::ChangeColumnStart:
+ case BinaryAnnotationsOpCode::ChangeColumnEnd:
+ W.printNumber(Annotation.Name, Annotation.U1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeLineOffset:
+ case BinaryAnnotationsOpCode::ChangeColumnEndDelta:
+ W.printNumber(Annotation.Name, Annotation.S1);
+ break;
+ case BinaryAnnotationsOpCode::ChangeFile:
+ if (ObjDelegate) {
+ W.printHex("ChangeFile",
+ ObjDelegate->getFileNameForFileOffset(Annotation.U1),
+ Annotation.U1);
+ } else {
+ W.printHex("ChangeFile", Annotation.U1);
+ }
+
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset: {
+ W.startLine() << "ChangeCodeOffsetAndLineOffset: {CodeOffset: "
+ << W.hex(Annotation.U1) << ", LineOffset: " << Annotation.S1
+ << "}\n";
+ break;
+ }
+ case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset: {
+ W.startLine() << "ChangeCodeLengthAndCodeOffset: {CodeOffset: "
+ << W.hex(Annotation.U2)
+ << ", Length: " << W.hex(Annotation.U1) << "}\n";
+ break;
+ }
+ }
+ }
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ RegisterSym &Register) {
+ printTypeIndex("Type", Register.Index);
+ W.printEnum("Seg", uint16_t(Register.Register),
+ getRegisterNames(CompilationCPUType));
+ W.printString("Name", Register.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, PublicSym32 &Public) {
+ W.printFlags("Flags", uint32_t(Public.Flags), getPublicSymFlagNames());
+ W.printNumber("Seg", Public.Segment);
+ W.printNumber("Off", Public.Offset);
+ W.printString("Name", Public.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ProcRefSym &ProcRef) {
+ W.printNumber("SumName", ProcRef.SumName);
+ W.printNumber("SymOffset", ProcRef.SymOffset);
+ W.printNumber("Mod", ProcRef.Module);
+ W.printString("Name", ProcRef.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LabelSym &Label) {
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset", Label.getRelocationOffset(),
+ Label.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", Label.Segment);
+ W.printHex("Flags", uint8_t(Label.Flags));
+ W.printFlags("Flags", uint8_t(Label.Flags), getProcSymFlagNames());
+ W.printString("DisplayName", Label.Name);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) {
+ printTypeIndex("Type", Local.Type);
+ W.printFlags("Flags", uint16_t(Local.Flags), getLocalFlagNames());
+ W.printString("VarName", Local.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ObjNameSym &ObjName) {
+ W.printHex("Signature", ObjName.Signature);
+ W.printString("ObjectName", ObjName.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) {
+ if (InFunctionScope)
+ return llvm::make_error<CodeViewError>(
+ "Visiting a ProcSym while inside function scope!");
+
+ InFunctionScope = true;
+
+ StringRef LinkageName;
+ W.printHex("PtrParent", Proc.Parent);
+ W.printHex("PtrEnd", Proc.End);
+ W.printHex("PtrNext", Proc.Next);
+ W.printHex("CodeSize", Proc.CodeSize);
+ W.printHex("DbgStart", Proc.DbgStart);
+ W.printHex("DbgEnd", Proc.DbgEnd);
+ printTypeIndex("FunctionType", Proc.FunctionType);
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("CodeOffset", Proc.getRelocationOffset(),
+ Proc.CodeOffset, &LinkageName);
+ }
+ W.printHex("Segment", Proc.Segment);
+ W.printFlags("Flags", static_cast<uint8_t>(Proc.Flags),
+ getProcSymFlagNames());
+ W.printString("DisplayName", Proc.Name);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ ScopeEndSym &ScopeEnd) {
+ InFunctionScope = false;
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) {
+ ListScope S(W, CVR.kind() == S_CALLEES ? "Callees" : "Callers");
+ for (auto FuncID : Caller.Indices)
+ printTypeIndex("FuncID", FuncID);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ RegRelativeSym &RegRel) {
+ W.printHex("Offset", RegRel.Offset);
+ printTypeIndex("Type", RegRel.Type);
+ W.printEnum("Register", uint16_t(RegRel.Register),
+ getRegisterNames(CompilationCPUType));
+ W.printString("VarName", RegRel.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ ThreadLocalDataSym &Data) {
+ StringRef LinkageName;
+ if (ObjDelegate) {
+ ObjDelegate->printRelocatedField("DataOffset", Data.getRelocationOffset(),
+ Data.DataOffset, &LinkageName);
+ }
+ printTypeIndex("Type", Data.Type);
+ W.printString("DisplayName", Data.Name);
+ if (!LinkageName.empty())
+ W.printString("LinkageName", LinkageName);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) {
+ printTypeIndex("Type", UDT.Type);
+ W.printString("UDTName", UDT.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ UsingNamespaceSym &UN) {
+ W.printString("Namespace", UN.Name);
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitKnownRecord(CVSymbol &CVR,
+ AnnotationSym &Annot) {
+ W.printHex("Offset", Annot.CodeOffset);
+ W.printHex("Segment", Annot.Segment);
+
+ ListScope S(W, "Strings");
+ for (StringRef Str : Annot.Strings)
+ W.printString(Str);
+
+ return Error::success();
+}
+
+Error CVSymbolDumperImpl::visitUnknownSymbol(CVSymbol &CVR) {
+ W.printNumber("Length", CVR.length());
+ return Error::success();
+}
+
+Error CVSymbolDumper::dump(CVRecord<SymbolKind> &Record) {
+ SymbolVisitorCallbackPipeline Pipeline;
+ SymbolDeserializer Deserializer(ObjDelegate.get(), Container);
+ CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, CompilationCPUType,
+ PrintRecordBytes);
+
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Dumper);
+ CVSymbolVisitor Visitor(Pipeline);
+ auto Err = Visitor.visitSymbolRecord(Record);
+ CompilationCPUType = Dumper.getCompilationCPUType();
+ return Err;
+}
+
+Error CVSymbolDumper::dump(const CVSymbolArray &Symbols) {
+ SymbolVisitorCallbackPipeline Pipeline;
+ SymbolDeserializer Deserializer(ObjDelegate.get(), Container);
+ CVSymbolDumperImpl Dumper(Types, ObjDelegate.get(), W, CompilationCPUType,
+ PrintRecordBytes);
+
+ Pipeline.addCallbackToPipeline(Deserializer);
+ Pipeline.addCallbackToPipeline(Dumper);
+ CVSymbolVisitor Visitor(Pipeline);
+ auto Err = Visitor.visitSymbolStream(Symbols);
+ CompilationCPUType = Dumper.getCompilationCPUType();
+ return Err;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp
new file mode 100644
index 0000000000..2562c633bb
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/SymbolRecordHelpers.cpp
@@ -0,0 +1,93 @@
+//===- SymbolRecordHelpers.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/SymbolRecordHelpers.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+template <typename RecordT> static RecordT createRecord(const CVSymbol &sym) {
+ RecordT record(static_cast<SymbolRecordKind>(sym.kind()));
+ cantFail(SymbolDeserializer::deserializeAs<RecordT>(sym, record));
+ return record;
+}
+
+uint32_t llvm::codeview::getScopeEndOffset(const CVSymbol &Sym) {
+ assert(symbolOpensScope(Sym.kind()));
+ switch (Sym.kind()) {
+ case SymbolKind::S_GPROC32:
+ case SymbolKind::S_LPROC32:
+ case SymbolKind::S_GPROC32_ID:
+ case SymbolKind::S_LPROC32_ID:
+ case SymbolKind::S_LPROC32_DPC:
+ case SymbolKind::S_LPROC32_DPC_ID: {
+ ProcSym Proc = createRecord<ProcSym>(Sym);
+ return Proc.End;
+ }
+ case SymbolKind::S_BLOCK32: {
+ BlockSym Block = createRecord<BlockSym>(Sym);
+ return Block.End;
+ }
+ case SymbolKind::S_THUNK32: {
+ Thunk32Sym Thunk = createRecord<Thunk32Sym>(Sym);
+ return Thunk.End;
+ }
+ case SymbolKind::S_INLINESITE: {
+ InlineSiteSym Site = createRecord<InlineSiteSym>(Sym);
+ return Site.End;
+ }
+ default:
+ assert(false && "Unknown record type");
+ return 0;
+ }
+}
+
+uint32_t
+llvm::codeview::getScopeParentOffset(const llvm::codeview::CVSymbol &Sym) {
+ assert(symbolOpensScope(Sym.kind()));
+ switch (Sym.kind()) {
+ case SymbolKind::S_GPROC32:
+ case SymbolKind::S_LPROC32:
+ case SymbolKind::S_GPROC32_ID:
+ case SymbolKind::S_LPROC32_ID:
+ case SymbolKind::S_LPROC32_DPC:
+ case SymbolKind::S_LPROC32_DPC_ID: {
+ ProcSym Proc = createRecord<ProcSym>(Sym);
+ return Proc.Parent;
+ }
+ case SymbolKind::S_BLOCK32: {
+ BlockSym Block = createRecord<BlockSym>(Sym);
+ return Block.Parent;
+ }
+ case SymbolKind::S_THUNK32: {
+ Thunk32Sym Thunk = createRecord<Thunk32Sym>(Sym);
+ return Thunk.Parent;
+ }
+ case SymbolKind::S_INLINESITE: {
+ InlineSiteSym Site = createRecord<InlineSiteSym>(Sym);
+ return Site.Parent;
+ }
+ default:
+ assert(false && "Unknown record type");
+ return 0;
+ }
+}
+
+CVSymbolArray
+llvm::codeview::limitSymbolArrayToScope(const CVSymbolArray &Symbols,
+ uint32_t ScopeBegin) {
+ CVSymbol Opener = *Symbols.at(ScopeBegin);
+ assert(symbolOpensScope(Opener.kind()));
+ uint32_t EndOffset = getScopeEndOffset(Opener);
+ CVSymbol Closer = *Symbols.at(EndOffset);
+ EndOffset += Closer.RecordData.size();
+ return Symbols.substream(ScopeBegin, EndOffset);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp
new file mode 100644
index 0000000000..3b627930e2
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/SymbolRecordMapping.cpp
@@ -0,0 +1,558 @@
+//===- SymbolRecordMapping.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/SymbolRecordMapping.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+#define error(X) \
+ if (auto EC = X) \
+ return EC;
+
+namespace {
+struct MapGap {
+ Error operator()(CodeViewRecordIO &IO, LocalVariableAddrGap &Gap) const {
+ error(IO.mapInteger(Gap.GapStartOffset));
+ error(IO.mapInteger(Gap.Range));
+ return Error::success();
+ }
+};
+}
+
+static Error mapLocalVariableAddrRange(CodeViewRecordIO &IO,
+ LocalVariableAddrRange &Range) {
+ error(IO.mapInteger(Range.OffsetStart));
+ error(IO.mapInteger(Range.ISectStart));
+ error(IO.mapInteger(Range.Range));
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitSymbolBegin(CVSymbol &Record) {
+ error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix)));
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitSymbolEnd(CVSymbol &Record) {
+ error(IO.padToAlignment(alignOf(Container)));
+ error(IO.endRecord());
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, BlockSym &Block) {
+
+ error(IO.mapInteger(Block.Parent));
+ error(IO.mapInteger(Block.End));
+ error(IO.mapInteger(Block.CodeSize));
+ error(IO.mapInteger(Block.CodeOffset));
+ error(IO.mapInteger(Block.Segment));
+ error(IO.mapStringZ(Block.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, Thunk32Sym &Thunk) {
+
+ error(IO.mapInteger(Thunk.Parent));
+ error(IO.mapInteger(Thunk.End));
+ error(IO.mapInteger(Thunk.Next));
+ error(IO.mapInteger(Thunk.Offset));
+ error(IO.mapInteger(Thunk.Segment));
+ error(IO.mapInteger(Thunk.Length));
+ error(IO.mapEnum(Thunk.Thunk));
+ error(IO.mapStringZ(Thunk.Name));
+ error(IO.mapByteVectorTail(Thunk.VariantData));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ TrampolineSym &Tramp) {
+
+ error(IO.mapEnum(Tramp.Type));
+ error(IO.mapInteger(Tramp.Size));
+ error(IO.mapInteger(Tramp.ThunkOffset));
+ error(IO.mapInteger(Tramp.TargetOffset));
+ error(IO.mapInteger(Tramp.ThunkSection));
+ error(IO.mapInteger(Tramp.TargetSection));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ SectionSym &Section) {
+ uint8_t Padding = 0;
+
+ error(IO.mapInteger(Section.SectionNumber));
+ error(IO.mapInteger(Section.Alignment));
+ error(IO.mapInteger(Padding));
+ error(IO.mapInteger(Section.Rva));
+ error(IO.mapInteger(Section.Length));
+ error(IO.mapInteger(Section.Characteristics));
+ error(IO.mapStringZ(Section.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ CoffGroupSym &CoffGroup) {
+
+ error(IO.mapInteger(CoffGroup.Size));
+ error(IO.mapInteger(CoffGroup.Characteristics));
+ error(IO.mapInteger(CoffGroup.Offset));
+ error(IO.mapInteger(CoffGroup.Segment));
+ error(IO.mapStringZ(CoffGroup.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ BPRelativeSym &BPRel) {
+
+ error(IO.mapInteger(BPRel.Offset));
+ error(IO.mapInteger(BPRel.Type));
+ error(IO.mapStringZ(BPRel.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ BuildInfoSym &BuildInfo) {
+
+ error(IO.mapInteger(BuildInfo.BuildId));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ CallSiteInfoSym &CallSiteInfo) {
+ uint16_t Padding = 0;
+
+ error(IO.mapInteger(CallSiteInfo.CodeOffset));
+ error(IO.mapInteger(CallSiteInfo.Segment));
+ error(IO.mapInteger(Padding));
+ error(IO.mapInteger(CallSiteInfo.Type));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ EnvBlockSym &EnvBlock) {
+
+ uint8_t Reserved = 0;
+ error(IO.mapInteger(Reserved));
+ error(IO.mapStringZVectorZ(EnvBlock.Fields));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ FileStaticSym &FileStatic) {
+
+ error(IO.mapInteger(FileStatic.Index));
+ error(IO.mapInteger(FileStatic.ModFilenameOffset));
+ error(IO.mapEnum(FileStatic.Flags));
+ error(IO.mapStringZ(FileStatic.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, ExportSym &Export) {
+
+ error(IO.mapInteger(Export.Ordinal));
+ error(IO.mapEnum(Export.Flags));
+ error(IO.mapStringZ(Export.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ Compile2Sym &Compile2) {
+
+ error(IO.mapEnum(Compile2.Flags));
+ error(IO.mapEnum(Compile2.Machine));
+ error(IO.mapInteger(Compile2.VersionFrontendMajor));
+ error(IO.mapInteger(Compile2.VersionFrontendMinor));
+ error(IO.mapInteger(Compile2.VersionFrontendBuild));
+ error(IO.mapInteger(Compile2.VersionBackendMajor));
+ error(IO.mapInteger(Compile2.VersionBackendMinor));
+ error(IO.mapInteger(Compile2.VersionBackendBuild));
+ error(IO.mapStringZ(Compile2.Version));
+ error(IO.mapStringZVectorZ(Compile2.ExtraStrings));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ Compile3Sym &Compile3) {
+
+ error(IO.mapEnum(Compile3.Flags));
+ error(IO.mapEnum(Compile3.Machine));
+ error(IO.mapInteger(Compile3.VersionFrontendMajor));
+ error(IO.mapInteger(Compile3.VersionFrontendMinor));
+ error(IO.mapInteger(Compile3.VersionFrontendBuild));
+ error(IO.mapInteger(Compile3.VersionFrontendQFE));
+ error(IO.mapInteger(Compile3.VersionBackendMajor));
+ error(IO.mapInteger(Compile3.VersionBackendMinor));
+ error(IO.mapInteger(Compile3.VersionBackendBuild));
+ error(IO.mapInteger(Compile3.VersionBackendQFE));
+ error(IO.mapStringZ(Compile3.Version));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ ConstantSym &Constant) {
+
+ error(IO.mapInteger(Constant.Type));
+ error(IO.mapEncodedInteger(Constant.Value));
+ error(IO.mapStringZ(Constant.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, DataSym &Data) {
+
+ error(IO.mapInteger(Data.Type));
+ error(IO.mapInteger(Data.DataOffset));
+ error(IO.mapInteger(Data.Segment));
+ error(IO.mapStringZ(Data.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(
+ CVSymbol &CVR, DefRangeFramePointerRelSym &DefRangeFramePointerRel) {
+
+ error(IO.mapObject(DefRangeFramePointerRel.Hdr.Offset));
+ error(mapLocalVariableAddrRange(IO, DefRangeFramePointerRel.Range));
+ error(IO.mapVectorTail(DefRangeFramePointerRel.Gaps, MapGap()));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(
+ CVSymbol &CVR,
+ DefRangeFramePointerRelFullScopeSym &DefRangeFramePointerRelFullScope) {
+
+ error(IO.mapInteger(DefRangeFramePointerRelFullScope.Offset));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(
+ CVSymbol &CVR, DefRangeRegisterRelSym &DefRangeRegisterRel) {
+
+ error(IO.mapObject(DefRangeRegisterRel.Hdr.Register));
+ error(IO.mapObject(DefRangeRegisterRel.Hdr.Flags));
+ error(IO.mapObject(DefRangeRegisterRel.Hdr.BasePointerOffset));
+ error(mapLocalVariableAddrRange(IO, DefRangeRegisterRel.Range));
+ error(IO.mapVectorTail(DefRangeRegisterRel.Gaps, MapGap()));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(
+ CVSymbol &CVR, DefRangeRegisterSym &DefRangeRegister) {
+
+ error(IO.mapObject(DefRangeRegister.Hdr.Register));
+ error(IO.mapObject(DefRangeRegister.Hdr.MayHaveNoName));
+ error(mapLocalVariableAddrRange(IO, DefRangeRegister.Range));
+ error(IO.mapVectorTail(DefRangeRegister.Gaps, MapGap()));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(
+ CVSymbol &CVR, DefRangeSubfieldRegisterSym &DefRangeSubfieldRegister) {
+
+ error(IO.mapObject(DefRangeSubfieldRegister.Hdr.Register));
+ error(IO.mapObject(DefRangeSubfieldRegister.Hdr.MayHaveNoName));
+ error(IO.mapObject(DefRangeSubfieldRegister.Hdr.OffsetInParent));
+ error(mapLocalVariableAddrRange(IO, DefRangeSubfieldRegister.Range));
+ error(IO.mapVectorTail(DefRangeSubfieldRegister.Gaps, MapGap()));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(
+ CVSymbol &CVR, DefRangeSubfieldSym &DefRangeSubfield) {
+
+ error(IO.mapInteger(DefRangeSubfield.Program));
+ error(IO.mapInteger(DefRangeSubfield.OffsetInParent));
+ error(mapLocalVariableAddrRange(IO, DefRangeSubfield.Range));
+ error(IO.mapVectorTail(DefRangeSubfield.Gaps, MapGap()));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ DefRangeSym &DefRange) {
+
+ error(IO.mapInteger(DefRange.Program));
+ error(mapLocalVariableAddrRange(IO, DefRange.Range));
+ error(IO.mapVectorTail(DefRange.Gaps, MapGap()));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ FrameCookieSym &FrameCookie) {
+
+ error(IO.mapInteger(FrameCookie.CodeOffset));
+ error(IO.mapInteger(FrameCookie.Register));
+ error(IO.mapEnum(FrameCookie.CookieKind));
+ error(IO.mapInteger(FrameCookie.Flags));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ FrameProcSym &FrameProc) {
+ error(IO.mapInteger(FrameProc.TotalFrameBytes));
+ error(IO.mapInteger(FrameProc.PaddingFrameBytes));
+ error(IO.mapInteger(FrameProc.OffsetToPadding));
+ error(IO.mapInteger(FrameProc.BytesOfCalleeSavedRegisters));
+ error(IO.mapInteger(FrameProc.OffsetOfExceptionHandler));
+ error(IO.mapInteger(FrameProc.SectionIdOfExceptionHandler));
+ error(IO.mapEnum(FrameProc.Flags));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(
+ CVSymbol &CVR, HeapAllocationSiteSym &HeapAllocSite) {
+
+ error(IO.mapInteger(HeapAllocSite.CodeOffset));
+ error(IO.mapInteger(HeapAllocSite.Segment));
+ error(IO.mapInteger(HeapAllocSite.CallInstructionSize));
+ error(IO.mapInteger(HeapAllocSite.Type));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ InlineSiteSym &InlineSite) {
+
+ error(IO.mapInteger(InlineSite.Parent));
+ error(IO.mapInteger(InlineSite.End));
+ error(IO.mapInteger(InlineSite.Inlinee));
+ error(IO.mapByteVectorTail(InlineSite.AnnotationData));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ RegisterSym &Register) {
+
+ error(IO.mapInteger(Register.Index));
+ error(IO.mapEnum(Register.Register));
+ error(IO.mapStringZ(Register.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ PublicSym32 &Public) {
+
+ error(IO.mapEnum(Public.Flags));
+ error(IO.mapInteger(Public.Offset));
+ error(IO.mapInteger(Public.Segment));
+ error(IO.mapStringZ(Public.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ ProcRefSym &ProcRef) {
+
+ error(IO.mapInteger(ProcRef.SumName));
+ error(IO.mapInteger(ProcRef.SymOffset));
+ error(IO.mapInteger(ProcRef.Module));
+ error(IO.mapStringZ(ProcRef.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, LabelSym &Label) {
+
+ error(IO.mapInteger(Label.CodeOffset));
+ error(IO.mapInteger(Label.Segment));
+ error(IO.mapEnum(Label.Flags));
+ error(IO.mapStringZ(Label.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, LocalSym &Local) {
+ error(IO.mapInteger(Local.Type));
+ error(IO.mapEnum(Local.Flags));
+ error(IO.mapStringZ(Local.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ ObjNameSym &ObjName) {
+
+ error(IO.mapInteger(ObjName.Signature));
+ error(IO.mapStringZ(ObjName.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, ProcSym &Proc) {
+ error(IO.mapInteger(Proc.Parent));
+ error(IO.mapInteger(Proc.End));
+ error(IO.mapInteger(Proc.Next));
+ error(IO.mapInteger(Proc.CodeSize));
+ error(IO.mapInteger(Proc.DbgStart));
+ error(IO.mapInteger(Proc.DbgEnd));
+ error(IO.mapInteger(Proc.FunctionType));
+ error(IO.mapInteger(Proc.CodeOffset));
+ error(IO.mapInteger(Proc.Segment));
+ error(IO.mapEnum(Proc.Flags));
+ error(IO.mapStringZ(Proc.Name));
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ ScopeEndSym &ScopeEnd) {
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, CallerSym &Caller) {
+ error(IO.mapVectorN<uint32_t>(
+ Caller.Indices,
+ [](CodeViewRecordIO &IO, TypeIndex &N) { return IO.mapInteger(N); }));
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ RegRelativeSym &RegRel) {
+
+ error(IO.mapInteger(RegRel.Offset));
+ error(IO.mapInteger(RegRel.Type));
+ error(IO.mapEnum(RegRel.Register));
+ error(IO.mapStringZ(RegRel.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ ThreadLocalDataSym &Data) {
+
+ error(IO.mapInteger(Data.Type));
+ error(IO.mapInteger(Data.DataOffset));
+ error(IO.mapInteger(Data.Segment));
+ error(IO.mapStringZ(Data.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR, UDTSym &UDT) {
+
+ error(IO.mapInteger(UDT.Type));
+ error(IO.mapStringZ(UDT.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ UsingNamespaceSym &UN) {
+
+ error(IO.mapStringZ(UN.Name));
+
+ return Error::success();
+}
+
+Error SymbolRecordMapping::visitKnownRecord(CVSymbol &CVR,
+ AnnotationSym &Annot) {
+
+ error(IO.mapInteger(Annot.CodeOffset));
+ error(IO.mapInteger(Annot.Segment));
+ error(IO.mapVectorN<uint16_t>(
+ Annot.Strings,
+ [](CodeViewRecordIO &IO, StringRef &S) { return IO.mapStringZ(S); }));
+
+ return Error::success();
+}
+
+RegisterId codeview::decodeFramePtrReg(EncodedFramePtrReg EncodedReg,
+ CPUType CPU) {
+ assert(unsigned(EncodedReg) < 4);
+ switch (CPU) {
+ // FIXME: Add ARM and AArch64 variants here.
+ default:
+ break;
+ case CPUType::Intel8080:
+ case CPUType::Intel8086:
+ case CPUType::Intel80286:
+ case CPUType::Intel80386:
+ case CPUType::Intel80486:
+ case CPUType::Pentium:
+ case CPUType::PentiumPro:
+ case CPUType::Pentium3:
+ switch (EncodedReg) {
+ case EncodedFramePtrReg::None: return RegisterId::NONE;
+ case EncodedFramePtrReg::StackPtr: return RegisterId::VFRAME;
+ case EncodedFramePtrReg::FramePtr: return RegisterId::EBP;
+ case EncodedFramePtrReg::BasePtr: return RegisterId::EBX;
+ }
+ llvm_unreachable("bad encoding");
+ case CPUType::X64:
+ switch (EncodedReg) {
+ case EncodedFramePtrReg::None: return RegisterId::NONE;
+ case EncodedFramePtrReg::StackPtr: return RegisterId::RSP;
+ case EncodedFramePtrReg::FramePtr: return RegisterId::RBP;
+ case EncodedFramePtrReg::BasePtr: return RegisterId::R13;
+ }
+ llvm_unreachable("bad encoding");
+ }
+ return RegisterId::NONE;
+}
+
+EncodedFramePtrReg codeview::encodeFramePtrReg(RegisterId Reg, CPUType CPU) {
+ switch (CPU) {
+ // FIXME: Add ARM and AArch64 variants here.
+ default:
+ break;
+ case CPUType::Intel8080:
+ case CPUType::Intel8086:
+ case CPUType::Intel80286:
+ case CPUType::Intel80386:
+ case CPUType::Intel80486:
+ case CPUType::Pentium:
+ case CPUType::PentiumPro:
+ case CPUType::Pentium3:
+ switch (Reg) {
+ case RegisterId::VFRAME:
+ return EncodedFramePtrReg::StackPtr;
+ case RegisterId::EBP:
+ return EncodedFramePtrReg::FramePtr;
+ case RegisterId::EBX:
+ return EncodedFramePtrReg::BasePtr;
+ default:
+ break;
+ }
+ break;
+ case CPUType::X64:
+ switch (Reg) {
+ case RegisterId::RSP:
+ return EncodedFramePtrReg::StackPtr;
+ case RegisterId::RBP:
+ return EncodedFramePtrReg::FramePtr;
+ case RegisterId::R13:
+ return EncodedFramePtrReg::BasePtr;
+ default:
+ break;
+ }
+ break;
+ }
+ return EncodedFramePtrReg::None;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/SymbolSerializer.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/SymbolSerializer.cpp
new file mode 100644
index 0000000000..de9bb42b17
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/SymbolSerializer.cpp
@@ -0,0 +1,59 @@
+//===- SymbolSerializer.cpp -----------------------------------------------===//
+//
+// 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/SymbolSerializer.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+SymbolSerializer::SymbolSerializer(BumpPtrAllocator &Allocator,
+ CodeViewContainer Container)
+ : Storage(Allocator), Stream(RecordBuffer, support::little), Writer(Stream),
+ Mapping(Writer, Container) {}
+
+Error SymbolSerializer::visitSymbolBegin(CVSymbol &Record) {
+ assert(!CurrentSymbol.hasValue() && "Already in a symbol mapping!");
+
+ Writer.setOffset(0);
+
+ if (auto EC = writeRecordPrefix(Record.kind()))
+ return EC;
+
+ CurrentSymbol = Record.kind();
+ if (auto EC = Mapping.visitSymbolBegin(Record))
+ return EC;
+
+ return Error::success();
+}
+
+Error SymbolSerializer::visitSymbolEnd(CVSymbol &Record) {
+ assert(CurrentSymbol.hasValue() && "Not in a symbol mapping!");
+
+ if (auto EC = Mapping.visitSymbolEnd(Record))
+ return EC;
+
+ uint32_t RecordEnd = Writer.getOffset();
+ uint16_t Length = RecordEnd - 2;
+ Writer.setOffset(0);
+ if (auto EC = Writer.writeInteger(Length))
+ return EC;
+
+ uint8_t *StableStorage = Storage.Allocate<uint8_t>(RecordEnd);
+ ::memcpy(StableStorage, &RecordBuffer[0], RecordEnd);
+ Record.RecordData = ArrayRef<uint8_t>(StableStorage, RecordEnd);
+ CurrentSymbol.reset();
+
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
new file mode 100644
index 0000000000..d5fea5ee5e
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeDumpVisitor.cpp
@@ -0,0 +1,570 @@
+//===-- TypeDumpVisitor.cpp - CodeView type info dumper ----------*- 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/TypeDumpVisitor.h"
+
+#include "llvm/ADT/SmallString.h"
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/Formatters.h"
+#include "llvm/DebugInfo/CodeView/TypeCollection.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+static const EnumEntry<TypeLeafKind> LeafTypeNames[] = {
+#define CV_TYPE(enum, val) {#enum, enum},
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+};
+
+#define ENUM_ENTRY(enum_class, enum) \
+ { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
+
+static const EnumEntry<uint16_t> ClassOptionNames[] = {
+ ENUM_ENTRY(ClassOptions, Packed),
+ ENUM_ENTRY(ClassOptions, HasConstructorOrDestructor),
+ ENUM_ENTRY(ClassOptions, HasOverloadedOperator),
+ ENUM_ENTRY(ClassOptions, Nested),
+ ENUM_ENTRY(ClassOptions, ContainsNestedClass),
+ ENUM_ENTRY(ClassOptions, HasOverloadedAssignmentOperator),
+ ENUM_ENTRY(ClassOptions, HasConversionOperator),
+ ENUM_ENTRY(ClassOptions, ForwardReference),
+ ENUM_ENTRY(ClassOptions, Scoped),
+ ENUM_ENTRY(ClassOptions, HasUniqueName),
+ ENUM_ENTRY(ClassOptions, Sealed),
+ ENUM_ENTRY(ClassOptions, Intrinsic),
+};
+
+static const EnumEntry<uint8_t> MemberAccessNames[] = {
+ ENUM_ENTRY(MemberAccess, None), ENUM_ENTRY(MemberAccess, Private),
+ ENUM_ENTRY(MemberAccess, Protected), ENUM_ENTRY(MemberAccess, Public),
+};
+
+static const EnumEntry<uint16_t> MethodOptionNames[] = {
+ ENUM_ENTRY(MethodOptions, Pseudo),
+ ENUM_ENTRY(MethodOptions, NoInherit),
+ ENUM_ENTRY(MethodOptions, NoConstruct),
+ ENUM_ENTRY(MethodOptions, CompilerGenerated),
+ ENUM_ENTRY(MethodOptions, Sealed),
+};
+
+static const EnumEntry<uint16_t> MemberKindNames[] = {
+ ENUM_ENTRY(MethodKind, Vanilla),
+ ENUM_ENTRY(MethodKind, Virtual),
+ ENUM_ENTRY(MethodKind, Static),
+ ENUM_ENTRY(MethodKind, Friend),
+ ENUM_ENTRY(MethodKind, IntroducingVirtual),
+ ENUM_ENTRY(MethodKind, PureVirtual),
+ ENUM_ENTRY(MethodKind, PureIntroducingVirtual),
+};
+
+static const EnumEntry<uint8_t> PtrKindNames[] = {
+ ENUM_ENTRY(PointerKind, Near16),
+ ENUM_ENTRY(PointerKind, Far16),
+ ENUM_ENTRY(PointerKind, Huge16),
+ ENUM_ENTRY(PointerKind, BasedOnSegment),
+ ENUM_ENTRY(PointerKind, BasedOnValue),
+ ENUM_ENTRY(PointerKind, BasedOnSegmentValue),
+ ENUM_ENTRY(PointerKind, BasedOnAddress),
+ ENUM_ENTRY(PointerKind, BasedOnSegmentAddress),
+ ENUM_ENTRY(PointerKind, BasedOnType),
+ ENUM_ENTRY(PointerKind, BasedOnSelf),
+ ENUM_ENTRY(PointerKind, Near32),
+ ENUM_ENTRY(PointerKind, Far32),
+ ENUM_ENTRY(PointerKind, Near64),
+};
+
+static const EnumEntry<uint8_t> PtrModeNames[] = {
+ ENUM_ENTRY(PointerMode, Pointer),
+ ENUM_ENTRY(PointerMode, LValueReference),
+ ENUM_ENTRY(PointerMode, PointerToDataMember),
+ ENUM_ENTRY(PointerMode, PointerToMemberFunction),
+ ENUM_ENTRY(PointerMode, RValueReference),
+};
+
+static const EnumEntry<uint16_t> PtrMemberRepNames[] = {
+ ENUM_ENTRY(PointerToMemberRepresentation, Unknown),
+ ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceData),
+ ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceData),
+ ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceData),
+ ENUM_ENTRY(PointerToMemberRepresentation, GeneralData),
+ ENUM_ENTRY(PointerToMemberRepresentation, SingleInheritanceFunction),
+ ENUM_ENTRY(PointerToMemberRepresentation, MultipleInheritanceFunction),
+ ENUM_ENTRY(PointerToMemberRepresentation, VirtualInheritanceFunction),
+ ENUM_ENTRY(PointerToMemberRepresentation, GeneralFunction),
+};
+
+static const EnumEntry<uint16_t> TypeModifierNames[] = {
+ ENUM_ENTRY(ModifierOptions, Const), ENUM_ENTRY(ModifierOptions, Volatile),
+ ENUM_ENTRY(ModifierOptions, Unaligned),
+};
+
+static const EnumEntry<uint8_t> CallingConventions[] = {
+ ENUM_ENTRY(CallingConvention, NearC),
+ ENUM_ENTRY(CallingConvention, FarC),
+ ENUM_ENTRY(CallingConvention, NearPascal),
+ ENUM_ENTRY(CallingConvention, FarPascal),
+ ENUM_ENTRY(CallingConvention, NearFast),
+ ENUM_ENTRY(CallingConvention, FarFast),
+ ENUM_ENTRY(CallingConvention, NearStdCall),
+ ENUM_ENTRY(CallingConvention, FarStdCall),
+ ENUM_ENTRY(CallingConvention, NearSysCall),
+ ENUM_ENTRY(CallingConvention, FarSysCall),
+ ENUM_ENTRY(CallingConvention, ThisCall),
+ ENUM_ENTRY(CallingConvention, MipsCall),
+ ENUM_ENTRY(CallingConvention, Generic),
+ ENUM_ENTRY(CallingConvention, AlphaCall),
+ ENUM_ENTRY(CallingConvention, PpcCall),
+ ENUM_ENTRY(CallingConvention, SHCall),
+ ENUM_ENTRY(CallingConvention, ArmCall),
+ ENUM_ENTRY(CallingConvention, AM33Call),
+ ENUM_ENTRY(CallingConvention, TriCall),
+ ENUM_ENTRY(CallingConvention, SH5Call),
+ ENUM_ENTRY(CallingConvention, M32RCall),
+ ENUM_ENTRY(CallingConvention, ClrCall),
+ ENUM_ENTRY(CallingConvention, Inline),
+ ENUM_ENTRY(CallingConvention, NearVector),
+};
+
+static const EnumEntry<uint8_t> FunctionOptionEnum[] = {
+ ENUM_ENTRY(FunctionOptions, CxxReturnUdt),
+ ENUM_ENTRY(FunctionOptions, Constructor),
+ ENUM_ENTRY(FunctionOptions, ConstructorWithVirtualBases),
+};
+
+static const EnumEntry<uint16_t> LabelTypeEnum[] = {
+ ENUM_ENTRY(LabelType, Near), ENUM_ENTRY(LabelType, Far),
+};
+
+#undef ENUM_ENTRY
+
+static StringRef getLeafTypeName(TypeLeafKind LT) {
+ switch (LT) {
+#define TYPE_RECORD(ename, value, name) \
+ case ename: \
+ return #name;
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+ default:
+ break;
+ }
+ return "UnknownLeaf";
+}
+
+void TypeDumpVisitor::printTypeIndex(StringRef FieldName, TypeIndex TI) const {
+ codeview::printTypeIndex(*W, FieldName, TI, TpiTypes);
+}
+
+void TypeDumpVisitor::printItemIndex(StringRef FieldName, TypeIndex TI) const {
+ codeview::printTypeIndex(*W, FieldName, TI, getSourceTypes());
+}
+
+Error TypeDumpVisitor::visitTypeBegin(CVType &Record) {
+ return visitTypeBegin(Record, TypeIndex::fromArrayIndex(TpiTypes.size()));
+}
+
+Error TypeDumpVisitor::visitTypeBegin(CVType &Record, TypeIndex Index) {
+ W->startLine() << getLeafTypeName(Record.kind());
+ W->getOStream() << " (" << HexNumber(Index.getIndex()) << ")";
+ W->getOStream() << " {\n";
+ W->indent();
+ W->printEnum("TypeLeafKind", unsigned(Record.kind()),
+ makeArrayRef(LeafTypeNames));
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitTypeEnd(CVType &Record) {
+ if (PrintRecordBytes)
+ W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.content()));
+
+ W->unindent();
+ W->startLine() << "}\n";
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitMemberBegin(CVMemberRecord &Record) {
+ W->startLine() << getLeafTypeName(Record.Kind);
+ W->getOStream() << " {\n";
+ W->indent();
+ W->printEnum("TypeLeafKind", unsigned(Record.Kind),
+ makeArrayRef(LeafTypeNames));
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitMemberEnd(CVMemberRecord &Record) {
+ if (PrintRecordBytes)
+ W->printBinaryBlock("LeafData", getBytesAsCharacters(Record.Data));
+
+ W->unindent();
+ W->startLine() << "}\n";
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ FieldListRecord &FieldList) {
+ if (auto EC = codeview::visitMemberRecordStream(FieldList.Data, *this))
+ return EC;
+
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringIdRecord &String) {
+ printItemIndex("Id", String.getId());
+ W->printString("StringData", String.getString());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArgListRecord &Args) {
+ auto Indices = Args.getIndices();
+ uint32_t Size = Indices.size();
+ W->printNumber("NumArgs", Size);
+ ListScope Arguments(*W, "Arguments");
+ for (uint32_t I = 0; I < Size; ++I) {
+ printTypeIndex("ArgType", Indices[I]);
+ }
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, StringListRecord &Strs) {
+ auto Indices = Strs.getIndices();
+ uint32_t Size = Indices.size();
+ W->printNumber("NumStrings", Size);
+ ListScope Arguments(*W, "Strings");
+ for (uint32_t I = 0; I < Size; ++I) {
+ printItemIndex("String", Indices[I]);
+ }
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ClassRecord &Class) {
+ uint16_t Props = static_cast<uint16_t>(Class.getOptions());
+ W->printNumber("MemberCount", Class.getMemberCount());
+ W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
+ printTypeIndex("FieldList", Class.getFieldList());
+ printTypeIndex("DerivedFrom", Class.getDerivationList());
+ printTypeIndex("VShape", Class.getVTableShape());
+ W->printNumber("SizeOf", Class.getSize());
+ W->printString("Name", Class.getName());
+ if (Props & uint16_t(ClassOptions::HasUniqueName))
+ W->printString("LinkageName", Class.getUniqueName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, UnionRecord &Union) {
+ uint16_t Props = static_cast<uint16_t>(Union.getOptions());
+ W->printNumber("MemberCount", Union.getMemberCount());
+ W->printFlags("Properties", Props, makeArrayRef(ClassOptionNames));
+ printTypeIndex("FieldList", Union.getFieldList());
+ W->printNumber("SizeOf", Union.getSize());
+ W->printString("Name", Union.getName());
+ if (Props & uint16_t(ClassOptions::HasUniqueName))
+ W->printString("LinkageName", Union.getUniqueName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, EnumRecord &Enum) {
+ uint16_t Props = static_cast<uint16_t>(Enum.getOptions());
+ W->printNumber("NumEnumerators", Enum.getMemberCount());
+ W->printFlags("Properties", uint16_t(Enum.getOptions()),
+ makeArrayRef(ClassOptionNames));
+ printTypeIndex("UnderlyingType", Enum.getUnderlyingType());
+ printTypeIndex("FieldListType", Enum.getFieldList());
+ W->printString("Name", Enum.getName());
+ if (Props & uint16_t(ClassOptions::HasUniqueName))
+ W->printString("LinkageName", Enum.getUniqueName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ArrayRecord &AT) {
+ printTypeIndex("ElementType", AT.getElementType());
+ printTypeIndex("IndexType", AT.getIndexType());
+ W->printNumber("SizeOf", AT.getSize());
+ W->printString("Name", AT.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, VFTableRecord &VFT) {
+ printTypeIndex("CompleteClass", VFT.getCompleteClass());
+ printTypeIndex("OverriddenVFTable", VFT.getOverriddenVTable());
+ W->printHex("VFPtrOffset", VFT.getVFPtrOffset());
+ W->printString("VFTableName", VFT.getName());
+ for (auto N : VFT.getMethodNames())
+ W->printString("MethodName", N);
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFuncIdRecord &Id) {
+ printTypeIndex("ClassType", Id.getClassType());
+ printTypeIndex("FunctionType", Id.getFunctionType());
+ W->printString("Name", Id.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ProcedureRecord &Proc) {
+ printTypeIndex("ReturnType", Proc.getReturnType());
+ W->printEnum("CallingConvention", uint8_t(Proc.getCallConv()),
+ makeArrayRef(CallingConventions));
+ W->printFlags("FunctionOptions", uint8_t(Proc.getOptions()),
+ makeArrayRef(FunctionOptionEnum));
+ W->printNumber("NumParameters", Proc.getParameterCount());
+ printTypeIndex("ArgListType", Proc.getArgumentList());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, MemberFunctionRecord &MF) {
+ printTypeIndex("ReturnType", MF.getReturnType());
+ printTypeIndex("ClassType", MF.getClassType());
+ printTypeIndex("ThisType", MF.getThisType());
+ W->printEnum("CallingConvention", uint8_t(MF.getCallConv()),
+ makeArrayRef(CallingConventions));
+ W->printFlags("FunctionOptions", uint8_t(MF.getOptions()),
+ makeArrayRef(FunctionOptionEnum));
+ W->printNumber("NumParameters", MF.getParameterCount());
+ printTypeIndex("ArgListType", MF.getArgumentList());
+ W->printNumber("ThisAdjustment", MF.getThisPointerAdjustment());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ MethodOverloadListRecord &MethodList) {
+ for (auto &M : MethodList.getMethods()) {
+ ListScope S(*W, "Method");
+ printMemberAttributes(M.getAccess(), M.getMethodKind(), M.getOptions());
+ printTypeIndex("Type", M.getType());
+ if (M.isIntroducingVirtual())
+ W->printHex("VFTableOffset", M.getVFTableOffset());
+ }
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, FuncIdRecord &Func) {
+ printItemIndex("ParentScope", Func.getParentScope());
+ printTypeIndex("FunctionType", Func.getFunctionType());
+ W->printString("Name", Func.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, TypeServer2Record &TS) {
+ W->printString("Guid", formatv("{0}", TS.getGuid()).str());
+ W->printNumber("Age", TS.getAge());
+ W->printString("Name", TS.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, PointerRecord &Ptr) {
+ printTypeIndex("PointeeType", Ptr.getReferentType());
+ W->printEnum("PtrType", unsigned(Ptr.getPointerKind()),
+ makeArrayRef(PtrKindNames));
+ W->printEnum("PtrMode", unsigned(Ptr.getMode()), makeArrayRef(PtrModeNames));
+
+ W->printNumber("IsFlat", Ptr.isFlat());
+ W->printNumber("IsConst", Ptr.isConst());
+ W->printNumber("IsVolatile", Ptr.isVolatile());
+ W->printNumber("IsUnaligned", Ptr.isUnaligned());
+ W->printNumber("IsRestrict", Ptr.isRestrict());
+ W->printNumber("IsThisPtr&", Ptr.isLValueReferenceThisPtr());
+ W->printNumber("IsThisPtr&&", Ptr.isRValueReferenceThisPtr());
+ W->printNumber("SizeOf", Ptr.getSize());
+
+ if (Ptr.isPointerToMember()) {
+ const MemberPointerInfo &MI = Ptr.getMemberInfo();
+
+ printTypeIndex("ClassType", MI.getContainingType());
+ W->printEnum("Representation", uint16_t(MI.getRepresentation()),
+ makeArrayRef(PtrMemberRepNames));
+ }
+
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, ModifierRecord &Mod) {
+ uint16_t Mods = static_cast<uint16_t>(Mod.getModifiers());
+ printTypeIndex("ModifiedType", Mod.getModifiedType());
+ W->printFlags("Modifiers", Mods, makeArrayRef(TypeModifierNames));
+
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BitFieldRecord &BitField) {
+ printTypeIndex("Type", BitField.getType());
+ W->printNumber("BitSize", BitField.getBitSize());
+ W->printNumber("BitOffset", BitField.getBitOffset());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ VFTableShapeRecord &Shape) {
+ W->printNumber("VFEntryCount", Shape.getEntryCount());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ UdtSourceLineRecord &Line) {
+ printTypeIndex("UDT", Line.getUDT());
+ printItemIndex("SourceFile", Line.getSourceFile());
+ W->printNumber("LineNumber", Line.getLineNumber());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ UdtModSourceLineRecord &Line) {
+ printTypeIndex("UDT", Line.getUDT());
+ printItemIndex("SourceFile", Line.getSourceFile());
+ W->printNumber("LineNumber", Line.getLineNumber());
+ W->printNumber("Module", Line.getModule());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, BuildInfoRecord &Args) {
+ W->printNumber("NumArgs", static_cast<uint32_t>(Args.getArgs().size()));
+
+ ListScope Arguments(*W, "Arguments");
+ for (auto Arg : Args.getArgs()) {
+ printItemIndex("ArgType", Arg);
+ }
+ return Error::success();
+}
+
+void TypeDumpVisitor::printMemberAttributes(MemberAttributes Attrs) {
+ return printMemberAttributes(Attrs.getAccess(), Attrs.getMethodKind(),
+ Attrs.getFlags());
+}
+
+void TypeDumpVisitor::printMemberAttributes(MemberAccess Access,
+ MethodKind Kind,
+ MethodOptions Options) {
+ W->printEnum("AccessSpecifier", uint8_t(Access),
+ makeArrayRef(MemberAccessNames));
+ // Data members will be vanilla. Don't try to print a method kind for them.
+ if (Kind != MethodKind::Vanilla)
+ W->printEnum("MethodKind", unsigned(Kind), makeArrayRef(MemberKindNames));
+ if (Options != MethodOptions::None) {
+ W->printFlags("MethodOptions", unsigned(Options),
+ makeArrayRef(MethodOptionNames));
+ }
+}
+
+Error TypeDumpVisitor::visitUnknownMember(CVMemberRecord &Record) {
+ W->printHex("UnknownMember", unsigned(Record.Kind));
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitUnknownType(CVType &Record) {
+ W->printEnum("Kind", uint16_t(Record.kind()), makeArrayRef(LeafTypeNames));
+ W->printNumber("Length", uint32_t(Record.content().size()));
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ NestedTypeRecord &Nested) {
+ printTypeIndex("Type", Nested.getNestedType());
+ W->printString("Name", Nested.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ OneMethodRecord &Method) {
+ MethodKind K = Method.getMethodKind();
+ printMemberAttributes(Method.getAccess(), K, Method.getOptions());
+ printTypeIndex("Type", Method.getType());
+ // If virtual, then read the vftable offset.
+ if (Method.isIntroducingVirtual())
+ W->printHex("VFTableOffset", Method.getVFTableOffset());
+ W->printString("Name", Method.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ OverloadedMethodRecord &Method) {
+ W->printHex("MethodCount", Method.getNumOverloads());
+ printTypeIndex("MethodListIndex", Method.getMethodList());
+ W->printString("Name", Method.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ DataMemberRecord &Field) {
+ printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ printTypeIndex("Type", Field.getType());
+ W->printHex("FieldOffset", Field.getFieldOffset());
+ W->printString("Name", Field.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ StaticDataMemberRecord &Field) {
+ printMemberAttributes(Field.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ printTypeIndex("Type", Field.getType());
+ W->printString("Name", Field.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ VFPtrRecord &VFTable) {
+ printTypeIndex("Type", VFTable.getType());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ EnumeratorRecord &Enum) {
+ printMemberAttributes(Enum.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ W->printNumber("EnumValue", Enum.getValue());
+ W->printString("Name", Enum.getName());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ BaseClassRecord &Base) {
+ printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ printTypeIndex("BaseType", Base.getBaseType());
+ W->printHex("BaseOffset", Base.getBaseOffset());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ VirtualBaseClassRecord &Base) {
+ printMemberAttributes(Base.getAccess(), MethodKind::Vanilla,
+ MethodOptions::None);
+ printTypeIndex("BaseType", Base.getBaseType());
+ printTypeIndex("VBPtrType", Base.getVBPtrType());
+ W->printHex("VBPtrOffset", Base.getVBPtrOffset());
+ W->printHex("VBTableIndex", Base.getVTableIndex());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownMember(CVMemberRecord &CVR,
+ ListContinuationRecord &Cont) {
+ printTypeIndex("ContinuationIndex", Cont.getContinuationIndex());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR, LabelRecord &LR) {
+ W->printEnum("Mode", uint16_t(LR.Mode), makeArrayRef(LabelTypeEnum));
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ PrecompRecord &Precomp) {
+ W->printHex("StartIndex", Precomp.getStartTypeIndex());
+ W->printHex("Count", Precomp.getTypesCount());
+ W->printHex("Signature", Precomp.getSignature());
+ W->printString("PrecompFile", Precomp.getPrecompFilePath());
+ return Error::success();
+}
+
+Error TypeDumpVisitor::visitKnownRecord(CVType &CVR,
+ EndPrecompRecord &EndPrecomp) {
+ W->printHex("Signature", EndPrecomp.getSignature());
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeHashing.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeHashing.cpp
new file mode 100644
index 0000000000..2dbc11a84f
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeHashing.cpp
@@ -0,0 +1,80 @@
+//===- TypeHashing.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/TypeHashing.h"
+
+#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
+#include "llvm/Support/SHA1.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+LocallyHashedType DenseMapInfo<LocallyHashedType>::Empty{0, {}};
+LocallyHashedType DenseMapInfo<LocallyHashedType>::Tombstone{hash_code(-1), {}};
+
+static std::array<uint8_t, 8> EmptyHash = {
+ {0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+static std::array<uint8_t, 8> TombstoneHash = {
+ {0xFF, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00}};
+
+GloballyHashedType DenseMapInfo<GloballyHashedType>::Empty{EmptyHash};
+GloballyHashedType DenseMapInfo<GloballyHashedType>::Tombstone{TombstoneHash};
+
+LocallyHashedType LocallyHashedType::hashType(ArrayRef<uint8_t> RecordData) {
+ return {llvm::hash_value(RecordData), RecordData};
+}
+
+GloballyHashedType
+GloballyHashedType::hashType(ArrayRef<uint8_t> RecordData,
+ ArrayRef<GloballyHashedType> PreviousTypes,
+ ArrayRef<GloballyHashedType> PreviousIds) {
+ SmallVector<TiReference, 4> Refs;
+ discoverTypeIndices(RecordData, Refs);
+ SHA1 S;
+ S.init();
+ uint32_t Off = 0;
+ S.update(RecordData.take_front(sizeof(RecordPrefix)));
+ RecordData = RecordData.drop_front(sizeof(RecordPrefix));
+ for (const auto &Ref : Refs) {
+ // Hash any data that comes before this TiRef.
+ uint32_t PreLen = Ref.Offset - Off;
+ ArrayRef<uint8_t> PreData = RecordData.slice(Off, PreLen);
+ S.update(PreData);
+ auto Prev = (Ref.Kind == TiRefKind::IndexRef) ? PreviousIds : PreviousTypes;
+
+ auto RefData = RecordData.slice(Ref.Offset, Ref.Count * sizeof(TypeIndex));
+ // For each type index referenced, add in the previously computed hash
+ // value of that type.
+ ArrayRef<TypeIndex> Indices(
+ reinterpret_cast<const TypeIndex *>(RefData.data()), Ref.Count);
+ for (TypeIndex TI : Indices) {
+ ArrayRef<uint8_t> BytesToHash;
+ if (TI.isSimple() || TI.isNoneType()) {
+ const uint8_t *IndexBytes = reinterpret_cast<const uint8_t *>(&TI);
+ BytesToHash = makeArrayRef(IndexBytes, sizeof(TypeIndex));
+ } else {
+ if (TI.toArrayIndex() >= Prev.size() ||
+ Prev[TI.toArrayIndex()].empty()) {
+ // There are references to yet-unhashed records. Suspend hashing for
+ // this record until all the other records are processed.
+ return {};
+ }
+ BytesToHash = Prev[TI.toArrayIndex()].Hash;
+ }
+ S.update(BytesToHash);
+ }
+
+ Off = Ref.Offset + Ref.Count * sizeof(TypeIndex);
+ }
+
+ // Don't forget to add in any trailing bytes.
+ auto TrailingBytes = RecordData.drop_front(Off);
+ S.update(TrailingBytes);
+
+ return {S.final().take_back(8)};
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeIndex.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeIndex.cpp
new file mode 100644
index 0000000000..604d342448
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeIndex.cpp
@@ -0,0 +1,106 @@
+//===-- TypeIndex.cpp - CodeView type index ---------------------*- 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/TypeIndex.h"
+
+#include "llvm/DebugInfo/CodeView/TypeCollection.h"
+#include "llvm/Support/ScopedPrinter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+struct SimpleTypeEntry {
+ StringRef Name;
+ SimpleTypeKind Kind;
+};
+
+/// The names here all end in "*". If the simple type is a pointer type, we
+/// return the whole name. Otherwise we lop off the last character in our
+/// StringRef.
+static const SimpleTypeEntry SimpleTypeNames[] = {
+ {"void*", SimpleTypeKind::Void},
+ {"<not translated>*", SimpleTypeKind::NotTranslated},
+ {"HRESULT*", SimpleTypeKind::HResult},
+ {"signed char*", SimpleTypeKind::SignedCharacter},
+ {"unsigned char*", SimpleTypeKind::UnsignedCharacter},
+ {"char*", SimpleTypeKind::NarrowCharacter},
+ {"wchar_t*", SimpleTypeKind::WideCharacter},
+ {"char16_t*", SimpleTypeKind::Character16},
+ {"char32_t*", SimpleTypeKind::Character32},
+ {"__int8*", SimpleTypeKind::SByte},
+ {"unsigned __int8*", SimpleTypeKind::Byte},
+ {"short*", SimpleTypeKind::Int16Short},
+ {"unsigned short*", SimpleTypeKind::UInt16Short},
+ {"__int16*", SimpleTypeKind::Int16},
+ {"unsigned __int16*", SimpleTypeKind::UInt16},
+ {"long*", SimpleTypeKind::Int32Long},
+ {"unsigned long*", SimpleTypeKind::UInt32Long},
+ {"int*", SimpleTypeKind::Int32},
+ {"unsigned*", SimpleTypeKind::UInt32},
+ {"__int64*", SimpleTypeKind::Int64Quad},
+ {"unsigned __int64*", SimpleTypeKind::UInt64Quad},
+ {"__int64*", SimpleTypeKind::Int64},
+ {"unsigned __int64*", SimpleTypeKind::UInt64},
+ {"__int128*", SimpleTypeKind::Int128},
+ {"unsigned __int128*", SimpleTypeKind::UInt128},
+ {"__half*", SimpleTypeKind::Float16},
+ {"float*", SimpleTypeKind::Float32},
+ {"float*", SimpleTypeKind::Float32PartialPrecision},
+ {"__float48*", SimpleTypeKind::Float48},
+ {"double*", SimpleTypeKind::Float64},
+ {"long double*", SimpleTypeKind::Float80},
+ {"__float128*", SimpleTypeKind::Float128},
+ {"_Complex float*", SimpleTypeKind::Complex32},
+ {"_Complex double*", SimpleTypeKind::Complex64},
+ {"_Complex long double*", SimpleTypeKind::Complex80},
+ {"_Complex __float128*", SimpleTypeKind::Complex128},
+ {"bool*", SimpleTypeKind::Boolean8},
+ {"__bool16*", SimpleTypeKind::Boolean16},
+ {"__bool32*", SimpleTypeKind::Boolean32},
+ {"__bool64*", SimpleTypeKind::Boolean64},
+};
+} // namespace
+
+StringRef TypeIndex::simpleTypeName(TypeIndex TI) {
+ assert(TI.isNoneType() || TI.isSimple());
+
+ if (TI.isNoneType())
+ return "<no type>";
+
+ if (TI == TypeIndex::NullptrT())
+ return "std::nullptr_t";
+
+ // This is a simple type.
+ for (const auto &SimpleTypeName : SimpleTypeNames) {
+ if (SimpleTypeName.Kind == TI.getSimpleKind()) {
+ if (TI.getSimpleMode() == SimpleTypeMode::Direct)
+ return SimpleTypeName.Name.drop_back(1);
+ // Otherwise, this is a pointer type. We gloss over the distinction
+ // between near, far, 64, 32, etc, and just give a pointer type.
+ return SimpleTypeName.Name;
+ }
+ }
+ return "<unknown simple type>";
+}
+
+void llvm::codeview::printTypeIndex(ScopedPrinter &Printer, StringRef FieldName,
+ TypeIndex TI, TypeCollection &Types) {
+ StringRef TypeName;
+ if (!TI.isNoneType()) {
+ if (TI.isSimple())
+ TypeName = TypeIndex::simpleTypeName(TI);
+ else
+ TypeName = Types.getTypeName(TI);
+ }
+
+ if (!TypeName.empty())
+ Printer.printHex(FieldName, TypeName, TI.getIndex());
+ else
+ Printer.printHex(FieldName, TI.getIndex());
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
new file mode 100644
index 0000000000..682747a2b8
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeIndexDiscovery.cpp
@@ -0,0 +1,523 @@
+//===- TypeIndexDiscovery.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/TypeIndexDiscovery.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+static inline MethodKind getMethodKind(uint16_t Attrs) {
+ Attrs &= uint16_t(MethodOptions::MethodKindMask);
+ Attrs >>= 2;
+ return MethodKind(Attrs);
+}
+
+static inline bool isIntroVirtual(uint16_t Attrs) {
+ MethodKind MK = getMethodKind(Attrs);
+ return MK == MethodKind::IntroducingVirtual ||
+ MK == MethodKind::PureIntroducingVirtual;
+}
+
+static inline PointerMode getPointerMode(uint32_t Attrs) {
+ return static_cast<PointerMode>((Attrs >> PointerRecord::PointerModeShift) &
+ PointerRecord::PointerModeMask);
+}
+
+static inline bool isMemberPointer(uint32_t Attrs) {
+ PointerMode Mode = getPointerMode(Attrs);
+ return Mode == PointerMode::PointerToDataMember ||
+ Mode == PointerMode::PointerToMemberFunction;
+}
+
+static inline uint32_t getEncodedIntegerLength(ArrayRef<uint8_t> Data) {
+ uint16_t N = support::endian::read16le(Data.data());
+ if (N < LF_NUMERIC)
+ return 2;
+
+ assert(N <= LF_UQUADWORD);
+
+ constexpr uint32_t Sizes[] = {
+ 1, // LF_CHAR
+ 2, // LF_SHORT
+ 2, // LF_USHORT
+ 4, // LF_LONG
+ 4, // LF_ULONG
+ 4, // LF_REAL32
+ 8, // LF_REAL64
+ 10, // LF_REAL80
+ 16, // LF_REAL128
+ 8, // LF_QUADWORD
+ 8, // LF_UQUADWORD
+ };
+
+ return 2 + Sizes[N - LF_NUMERIC];
+}
+
+static inline uint32_t getCStringLength(ArrayRef<uint8_t> Data) {
+ const char *S = reinterpret_cast<const char *>(Data.data());
+ return strlen(S) + 1;
+}
+
+static void handleMethodOverloadList(ArrayRef<uint8_t> Content,
+ SmallVectorImpl<TiReference> &Refs) {
+ uint32_t Offset = 0;
+
+ while (!Content.empty()) {
+ // Array of:
+ // 0: Attrs
+ // 2: Padding
+ // 4: TypeIndex
+ // if (isIntroVirtual())
+ // 8: VFTableOffset
+
+ // At least 8 bytes are guaranteed. 4 extra bytes come iff function is an
+ // intro virtual.
+ uint32_t Len = 8;
+
+ uint16_t Attrs = support::endian::read16le(Content.data());
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+
+ if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
+ Len += 4;
+ Offset += Len;
+ Content = Content.drop_front(Len);
+ }
+}
+
+static uint32_t handleBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Padding
+ // 4: TypeIndex
+ // 8: Encoded Integer
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+ return 8 + getEncodedIntegerLength(Data.drop_front(8));
+}
+
+static uint32_t handleEnumerator(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Padding
+ // 4: Encoded Integer
+ // <next>: Name
+ uint32_t Size = 4 + getEncodedIntegerLength(Data.drop_front(4));
+ return Size + getCStringLength(Data.drop_front(Size));
+}
+
+static uint32_t handleDataMember(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Padding
+ // 4: TypeIndex
+ // 8: Encoded Integer
+ // <next>: Name
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+ uint32_t Size = 8 + getEncodedIntegerLength(Data.drop_front(8));
+ return Size + getCStringLength(Data.drop_front(Size));
+}
+
+static uint32_t handleOverloadedMethod(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Padding
+ // 4: TypeIndex
+ // 8: Name
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+ return 8 + getCStringLength(Data.drop_front(8));
+}
+
+static uint32_t handleOneMethod(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Attributes
+ // 4: Type
+ // if (isIntroVirtual)
+ // 8: VFTableOffset
+ // <next>: Name
+ uint32_t Size = 8;
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+
+ uint16_t Attrs = support::endian::read16le(Data.drop_front(2).data());
+ if (LLVM_UNLIKELY(isIntroVirtual(Attrs)))
+ Size += 4;
+
+ return Size + getCStringLength(Data.drop_front(Size));
+}
+
+static uint32_t handleNestedType(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Padding
+ // 4: TypeIndex
+ // 8: Name
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+ return 8 + getCStringLength(Data.drop_front(8));
+}
+
+static uint32_t handleStaticDataMember(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Padding
+ // 4: TypeIndex
+ // 8: Name
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+ return 8 + getCStringLength(Data.drop_front(8));
+}
+
+static uint32_t handleVirtualBaseClass(ArrayRef<uint8_t> Data, uint32_t Offset,
+ bool IsIndirect,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Attrs
+ // 4: TypeIndex
+ // 8: TypeIndex
+ // 12: Encoded Integer
+ // <next>: Encoded Integer
+ uint32_t Size = 12;
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 2});
+ Size += getEncodedIntegerLength(Data.drop_front(Size));
+ Size += getEncodedIntegerLength(Data.drop_front(Size));
+ return Size;
+}
+
+static uint32_t handleVFPtr(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Padding
+ // 4: TypeIndex
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+ return 8;
+}
+
+static uint32_t handleListContinuation(ArrayRef<uint8_t> Data, uint32_t Offset,
+ SmallVectorImpl<TiReference> &Refs) {
+ // 0: Kind
+ // 2: Padding
+ // 4: TypeIndex
+ Refs.push_back({TiRefKind::TypeRef, Offset + 4, 1});
+ return 8;
+}
+
+static void handleFieldList(ArrayRef<uint8_t> Content,
+ SmallVectorImpl<TiReference> &Refs) {
+ uint32_t Offset = 0;
+ uint32_t ThisLen = 0;
+ while (!Content.empty()) {
+ TypeLeafKind Kind =
+ static_cast<TypeLeafKind>(support::endian::read16le(Content.data()));
+ switch (Kind) {
+ case LF_BCLASS:
+ ThisLen = handleBaseClass(Content, Offset, Refs);
+ break;
+ case LF_ENUMERATE:
+ ThisLen = handleEnumerator(Content, Offset, Refs);
+ break;
+ case LF_MEMBER:
+ ThisLen = handleDataMember(Content, Offset, Refs);
+ break;
+ case LF_METHOD:
+ ThisLen = handleOverloadedMethod(Content, Offset, Refs);
+ break;
+ case LF_ONEMETHOD:
+ ThisLen = handleOneMethod(Content, Offset, Refs);
+ break;
+ case LF_NESTTYPE:
+ ThisLen = handleNestedType(Content, Offset, Refs);
+ break;
+ case LF_STMEMBER:
+ ThisLen = handleStaticDataMember(Content, Offset, Refs);
+ break;
+ case LF_VBCLASS:
+ case LF_IVBCLASS:
+ ThisLen =
+ handleVirtualBaseClass(Content, Offset, Kind == LF_VBCLASS, Refs);
+ break;
+ case LF_VFUNCTAB:
+ ThisLen = handleVFPtr(Content, Offset, Refs);
+ break;
+ case LF_INDEX:
+ ThisLen = handleListContinuation(Content, Offset, Refs);
+ break;
+ default:
+ return;
+ }
+ Content = Content.drop_front(ThisLen);
+ Offset += ThisLen;
+ if (!Content.empty()) {
+ uint8_t Pad = Content.front();
+ if (Pad >= LF_PAD0) {
+ uint32_t Skip = Pad & 0x0F;
+ Content = Content.drop_front(Skip);
+ Offset += Skip;
+ }
+ }
+ }
+}
+
+static void handlePointer(ArrayRef<uint8_t> Content,
+ SmallVectorImpl<TiReference> &Refs) {
+ Refs.push_back({TiRefKind::TypeRef, 0, 1});
+
+ uint32_t Attrs = support::endian::read32le(Content.drop_front(4).data());
+ if (isMemberPointer(Attrs))
+ Refs.push_back({TiRefKind::TypeRef, 8, 1});
+}
+
+static void discoverTypeIndices(ArrayRef<uint8_t> Content, TypeLeafKind Kind,
+ SmallVectorImpl<TiReference> &Refs) {
+ uint32_t Count;
+ // FIXME: In the future it would be nice if we could avoid hardcoding these
+ // values. One idea is to define some structures representing these types
+ // that would allow the use of offsetof().
+ switch (Kind) {
+ case TypeLeafKind::LF_FUNC_ID:
+ Refs.push_back({TiRefKind::IndexRef, 0, 1});
+ Refs.push_back({TiRefKind::TypeRef, 4, 1});
+ break;
+ case TypeLeafKind::LF_MFUNC_ID:
+ Refs.push_back({TiRefKind::TypeRef, 0, 2});
+ break;
+ case TypeLeafKind::LF_STRING_ID:
+ Refs.push_back({TiRefKind::IndexRef, 0, 1});
+ break;
+ case TypeLeafKind::LF_SUBSTR_LIST:
+ Count = support::endian::read32le(Content.data());
+ if (Count > 0)
+ Refs.push_back({TiRefKind::IndexRef, 4, Count});
+ break;
+ case TypeLeafKind::LF_BUILDINFO:
+ Count = support::endian::read16le(Content.data());
+ if (Count > 0)
+ Refs.push_back({TiRefKind::IndexRef, 2, Count});
+ break;
+ case TypeLeafKind::LF_UDT_SRC_LINE:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1});
+ Refs.push_back({TiRefKind::IndexRef, 4, 1});
+ break;
+ case TypeLeafKind::LF_UDT_MOD_SRC_LINE:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1});
+ break;
+ case TypeLeafKind::LF_MODIFIER:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1});
+ break;
+ case TypeLeafKind::LF_PROCEDURE:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1});
+ Refs.push_back({TiRefKind::TypeRef, 8, 1});
+ break;
+ case TypeLeafKind::LF_MFUNCTION:
+ Refs.push_back({TiRefKind::TypeRef, 0, 3});
+ Refs.push_back({TiRefKind::TypeRef, 16, 1});
+ break;
+ case TypeLeafKind::LF_ARGLIST:
+ Count = support::endian::read32le(Content.data());
+ if (Count > 0)
+ Refs.push_back({TiRefKind::TypeRef, 4, Count});
+ break;
+ case TypeLeafKind::LF_ARRAY:
+ Refs.push_back({TiRefKind::TypeRef, 0, 2});
+ break;
+ case TypeLeafKind::LF_CLASS:
+ case TypeLeafKind::LF_STRUCTURE:
+ case TypeLeafKind::LF_INTERFACE:
+ Refs.push_back({TiRefKind::TypeRef, 4, 3});
+ break;
+ case TypeLeafKind::LF_UNION:
+ Refs.push_back({TiRefKind::TypeRef, 4, 1});
+ break;
+ case TypeLeafKind::LF_ENUM:
+ Refs.push_back({TiRefKind::TypeRef, 4, 2});
+ break;
+ case TypeLeafKind::LF_BITFIELD:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1});
+ break;
+ case TypeLeafKind::LF_VFTABLE:
+ Refs.push_back({TiRefKind::TypeRef, 0, 2});
+ break;
+ case TypeLeafKind::LF_VTSHAPE:
+ break;
+ case TypeLeafKind::LF_METHODLIST:
+ handleMethodOverloadList(Content, Refs);
+ break;
+ case TypeLeafKind::LF_FIELDLIST:
+ handleFieldList(Content, Refs);
+ break;
+ case TypeLeafKind::LF_POINTER:
+ handlePointer(Content, Refs);
+ break;
+ default:
+ break;
+ }
+}
+
+static bool discoverTypeIndices(ArrayRef<uint8_t> Content, SymbolKind Kind,
+ SmallVectorImpl<TiReference> &Refs) {
+ uint32_t Count;
+ // FIXME: In the future it would be nice if we could avoid hardcoding these
+ // values. One idea is to define some structures representing these types
+ // that would allow the use of offsetof().
+ switch (Kind) {
+ case SymbolKind::S_GPROC32_ID:
+ case SymbolKind::S_LPROC32_ID:
+ case SymbolKind::S_LPROC32_DPC:
+ case SymbolKind::S_LPROC32_DPC_ID:
+ Refs.push_back({TiRefKind::IndexRef, 24, 1}); // LF_FUNC_ID
+ break;
+ case SymbolKind::S_GPROC32:
+ case SymbolKind::S_LPROC32:
+ Refs.push_back({TiRefKind::TypeRef, 24, 1}); // Type
+ break;
+ case SymbolKind::S_UDT:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1}); // UDT
+ break;
+ case SymbolKind::S_GDATA32:
+ case SymbolKind::S_LDATA32:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
+ break;
+ case SymbolKind::S_BUILDINFO:
+ Refs.push_back({TiRefKind::IndexRef, 0, 1}); // Compile flags
+ break;
+ case SymbolKind::S_LTHREAD32:
+ case SymbolKind::S_GTHREAD32:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
+ break;
+ case SymbolKind::S_FILESTATIC:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
+ break;
+ case SymbolKind::S_LOCAL:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
+ break;
+ case SymbolKind::S_REGISTER:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
+ break;
+ case SymbolKind::S_CONSTANT:
+ Refs.push_back({TiRefKind::TypeRef, 0, 1}); // Type
+ break;
+ case SymbolKind::S_BPREL32:
+ case SymbolKind::S_REGREL32:
+ Refs.push_back({TiRefKind::TypeRef, 4, 1}); // Type
+ break;
+ case SymbolKind::S_CALLSITEINFO:
+ Refs.push_back({TiRefKind::TypeRef, 8, 1}); // Call signature
+ break;
+ case SymbolKind::S_CALLERS:
+ case SymbolKind::S_CALLEES:
+ case SymbolKind::S_INLINEES:
+ // The record is a count followed by an array of type indices.
+ Count = *reinterpret_cast<const ulittle32_t *>(Content.data());
+ Refs.push_back({TiRefKind::IndexRef, 4, Count}); // Callees
+ break;
+ case SymbolKind::S_INLINESITE:
+ Refs.push_back({TiRefKind::IndexRef, 8, 1}); // ID of inlinee
+ break;
+ case SymbolKind::S_HEAPALLOCSITE:
+ Refs.push_back({TiRefKind::TypeRef, 8, 1}); // UDT allocated
+ break;
+
+ // Defranges don't have types, just registers and code offsets.
+ case SymbolKind::S_DEFRANGE_REGISTER:
+ case SymbolKind::S_DEFRANGE_REGISTER_REL:
+ case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL:
+ case SymbolKind::S_DEFRANGE_FRAMEPOINTER_REL_FULL_SCOPE:
+ case SymbolKind::S_DEFRANGE_SUBFIELD_REGISTER:
+ case SymbolKind::S_DEFRANGE_SUBFIELD:
+ break;
+
+ // No type references.
+ case SymbolKind::S_LABEL32:
+ case SymbolKind::S_OBJNAME:
+ case SymbolKind::S_COMPILE:
+ case SymbolKind::S_COMPILE2:
+ case SymbolKind::S_COMPILE3:
+ case SymbolKind::S_ENVBLOCK:
+ case SymbolKind::S_BLOCK32:
+ case SymbolKind::S_FRAMEPROC:
+ case SymbolKind::S_THUNK32:
+ case SymbolKind::S_FRAMECOOKIE:
+ case SymbolKind::S_UNAMESPACE:
+ break;
+ // Scope ending symbols.
+ case SymbolKind::S_END:
+ case SymbolKind::S_INLINESITE_END:
+ case SymbolKind::S_PROC_ID_END:
+ break;
+ default:
+ return false; // Unknown symbol.
+ }
+ return true;
+}
+
+void llvm::codeview::discoverTypeIndices(const CVType &Type,
+ SmallVectorImpl<TiReference> &Refs) {
+ ::discoverTypeIndices(Type.content(), Type.kind(), Refs);
+}
+
+static void resolveTypeIndexReferences(ArrayRef<uint8_t> RecordData,
+ ArrayRef<TiReference> Refs,
+ SmallVectorImpl<TypeIndex> &Indices) {
+ Indices.clear();
+
+ if (Refs.empty())
+ return;
+
+ RecordData = RecordData.drop_front(sizeof(RecordPrefix));
+
+ BinaryStreamReader Reader(RecordData, support::little);
+ for (const auto &Ref : Refs) {
+ Reader.setOffset(Ref.Offset);
+ FixedStreamArray<TypeIndex> Run;
+ cantFail(Reader.readArray(Run, Ref.Count));
+ Indices.append(Run.begin(), Run.end());
+ }
+}
+
+void llvm::codeview::discoverTypeIndices(const CVType &Type,
+ SmallVectorImpl<TypeIndex> &Indices) {
+ return discoverTypeIndices(Type.RecordData, Indices);
+}
+
+void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
+ SmallVectorImpl<TypeIndex> &Indices) {
+ SmallVector<TiReference, 4> Refs;
+ discoverTypeIndices(RecordData, Refs);
+ resolveTypeIndexReferences(RecordData, Refs, Indices);
+}
+
+void llvm::codeview::discoverTypeIndices(ArrayRef<uint8_t> RecordData,
+ SmallVectorImpl<TiReference> &Refs) {
+ const RecordPrefix *P =
+ reinterpret_cast<const RecordPrefix *>(RecordData.data());
+ TypeLeafKind K = static_cast<TypeLeafKind>(uint16_t(P->RecordKind));
+ ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K, Refs);
+}
+
+bool llvm::codeview::discoverTypeIndicesInSymbol(
+ const CVSymbol &Sym, SmallVectorImpl<TiReference> &Refs) {
+ SymbolKind K = Sym.kind();
+ return ::discoverTypeIndices(Sym.content(), K, Refs);
+}
+
+bool llvm::codeview::discoverTypeIndicesInSymbol(
+ ArrayRef<uint8_t> RecordData, SmallVectorImpl<TiReference> &Refs) {
+ const RecordPrefix *P =
+ reinterpret_cast<const RecordPrefix *>(RecordData.data());
+ SymbolKind K = static_cast<SymbolKind>(uint16_t(P->RecordKind));
+ return ::discoverTypeIndices(RecordData.drop_front(sizeof(RecordPrefix)), K,
+ Refs);
+}
+
+bool llvm::codeview::discoverTypeIndicesInSymbol(
+ ArrayRef<uint8_t> RecordData, SmallVectorImpl<TypeIndex> &Indices) {
+ SmallVector<TiReference, 2> Refs;
+ if (!discoverTypeIndicesInSymbol(RecordData, Refs))
+ return false;
+ resolveTypeIndexReferences(RecordData, Refs, Indices);
+ return true;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp
new file mode 100644
index 0000000000..8e632f3be4
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeRecordHelpers.cpp
@@ -0,0 +1,52 @@
+//===- TypeRecordHelpers.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/TypeRecordHelpers.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/DebugInfo/CodeView/TypeIndexDiscovery.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+template <typename RecordT> static ClassOptions getUdtOptions(CVType CVT) {
+ RecordT Record;
+ if (auto EC = TypeDeserializer::deserializeAs<RecordT>(CVT, Record)) {
+ consumeError(std::move(EC));
+ return ClassOptions::None;
+ }
+ return Record.getOptions();
+}
+
+bool llvm::codeview::isUdtForwardRef(CVType CVT) {
+ ClassOptions UdtOptions = ClassOptions::None;
+ switch (CVT.kind()) {
+ case LF_STRUCTURE:
+ case LF_CLASS:
+ case LF_INTERFACE:
+ UdtOptions = getUdtOptions<ClassRecord>(std::move(CVT));
+ break;
+ case LF_ENUM:
+ UdtOptions = getUdtOptions<EnumRecord>(std::move(CVT));
+ break;
+ case LF_UNION:
+ UdtOptions = getUdtOptions<UnionRecord>(std::move(CVT));
+ break;
+ default:
+ return false;
+ }
+ return (UdtOptions & ClassOptions::ForwardReference) != ClassOptions::None;
+}
+
+TypeIndex llvm::codeview::getModifiedType(const CVType &CVT) {
+ assert(CVT.kind() == LF_MODIFIER);
+ SmallVector<TypeIndex, 1> Refs;
+ discoverTypeIndices(CVT, Refs);
+ return Refs.front();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeRecordMapping.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
new file mode 100644
index 0000000000..d272999bda
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeRecordMapping.cpp
@@ -0,0 +1,735 @@
+//===- TypeRecordMapping.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/TypeRecordMapping.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/Twine.h"
+#include "llvm/DebugInfo/CodeView/EnumTables.h"
+#include "llvm/Support/MD5.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+namespace {
+
+#define error(X) \
+ if (auto EC = X) \
+ return EC;
+
+static const EnumEntry<TypeLeafKind> LeafTypeNames[] = {
+#define CV_TYPE(enum, val) {#enum, enum},
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+};
+
+static StringRef getLeafTypeName(TypeLeafKind LT) {
+ switch (LT) {
+#define TYPE_RECORD(ename, value, name) \
+ case ename: \
+ return #name;
+#include "llvm/DebugInfo/CodeView/CodeViewTypes.def"
+ default:
+ break;
+ }
+ return "UnknownLeaf";
+}
+
+template <typename T>
+static bool compEnumNames(const EnumEntry<T> &lhs, const EnumEntry<T> &rhs) {
+ return lhs.Name < rhs.Name;
+}
+
+template <typename T, typename TFlag>
+static std::string getFlagNames(CodeViewRecordIO &IO, T Value,
+ ArrayRef<EnumEntry<TFlag>> Flags) {
+ if (!IO.isStreaming())
+ return std::string("");
+ typedef EnumEntry<TFlag> FlagEntry;
+ typedef SmallVector<FlagEntry, 10> FlagVector;
+ FlagVector SetFlags;
+ for (const auto &Flag : Flags) {
+ if (Flag.Value == 0)
+ continue;
+ if ((Value & Flag.Value) == Flag.Value) {
+ SetFlags.push_back(Flag);
+ }
+ }
+
+ llvm::sort(SetFlags, &compEnumNames<TFlag>);
+
+ std::string FlagLabel;
+ bool FirstOcc = true;
+ for (const auto &Flag : SetFlags) {
+ if (FirstOcc)
+ FirstOcc = false;
+ else
+ FlagLabel += (" | ");
+
+ FlagLabel += (Flag.Name.str() + " (0x" + utohexstr(Flag.Value) + ")");
+ }
+
+ if (!FlagLabel.empty()) {
+ std::string LabelWithBraces(" ( ");
+ LabelWithBraces += FlagLabel + " )";
+ return LabelWithBraces;
+ } else
+ return FlagLabel;
+}
+
+template <typename T, typename TEnum>
+static StringRef getEnumName(CodeViewRecordIO &IO, T Value,
+ ArrayRef<EnumEntry<TEnum>> EnumValues) {
+ if (!IO.isStreaming())
+ return "";
+ StringRef Name;
+ for (const auto &EnumItem : EnumValues) {
+ if (EnumItem.Value == Value) {
+ Name = EnumItem.Name;
+ break;
+ }
+ }
+
+ return Name;
+}
+
+static std::string getMemberAttributes(CodeViewRecordIO &IO,
+ MemberAccess Access, MethodKind Kind,
+ MethodOptions Options) {
+ if (!IO.isStreaming())
+ return "";
+ std::string AccessSpecifier = std::string(
+ getEnumName(IO, uint8_t(Access), makeArrayRef(getMemberAccessNames())));
+ std::string MemberAttrs(AccessSpecifier);
+ if (Kind != MethodKind::Vanilla) {
+ std::string MethodKind = std::string(
+ getEnumName(IO, unsigned(Kind), makeArrayRef(getMemberKindNames())));
+ MemberAttrs += ", " + MethodKind;
+ }
+ if (Options != MethodOptions::None) {
+ std::string MethodOptions = getFlagNames(
+ IO, unsigned(Options), makeArrayRef(getMethodOptionNames()));
+ MemberAttrs += ", " + MethodOptions;
+ }
+ return MemberAttrs;
+}
+
+struct MapOneMethodRecord {
+ explicit MapOneMethodRecord(bool IsFromOverloadList)
+ : IsFromOverloadList(IsFromOverloadList) {}
+
+ Error operator()(CodeViewRecordIO &IO, OneMethodRecord &Method) const {
+ std::string Attrs = getMemberAttributes(
+ IO, Method.getAccess(), Method.getMethodKind(), Method.getOptions());
+ error(IO.mapInteger(Method.Attrs.Attrs, "Attrs: " + Attrs));
+ if (IsFromOverloadList) {
+ uint16_t Padding = 0;
+ error(IO.mapInteger(Padding));
+ }
+ error(IO.mapInteger(Method.Type, "Type"));
+ if (Method.isIntroducingVirtual()) {
+ error(IO.mapInteger(Method.VFTableOffset, "VFTableOffset"));
+ } else if (IO.isReading())
+ Method.VFTableOffset = -1;
+
+ if (!IsFromOverloadList)
+ error(IO.mapStringZ(Method.Name, "Name"));
+
+ return Error::success();
+ }
+
+private:
+ bool IsFromOverloadList;
+};
+} // namespace
+
+// Computes a string representation of a hash of the specified name, suitable
+// for use when emitting CodeView type names.
+static void computeHashString(StringRef Name,
+ SmallString<32> &StringifiedHash) {
+ llvm::MD5 Hash;
+ llvm::MD5::MD5Result Result;
+ Hash.update(Name);
+ Hash.final(Result);
+ Hash.stringifyResult(Result, StringifiedHash);
+}
+
+static Error mapNameAndUniqueName(CodeViewRecordIO &IO, StringRef &Name,
+ StringRef &UniqueName, bool HasUniqueName) {
+ if (IO.isWriting()) {
+ // Try to be smart about what we write here. We can't write anything too
+ // large, so if we're going to go over the limit, replace lengthy names with
+ // a stringified hash value.
+ size_t BytesLeft = IO.maxFieldLength();
+ if (HasUniqueName) {
+ size_t BytesNeeded = Name.size() + UniqueName.size() + 2;
+ if (BytesNeeded > BytesLeft) {
+ // The minimum space required for emitting hashes of both names.
+ assert(BytesLeft >= 70);
+
+ // Replace the entire unique name with a hash of the unique name.
+ SmallString<32> Hash;
+ computeHashString(UniqueName, Hash);
+ std::string UniqueB = Twine("??@" + Hash + "@").str();
+ assert(UniqueB.size() == 36);
+
+ // Truncate the name if necessary and append a hash of the name.
+ // The name length, hash included, is limited to 4096 bytes.
+ const size_t MaxTakeN = 4096;
+ size_t TakeN = std::min(MaxTakeN, BytesLeft - UniqueB.size() - 2) - 32;
+ computeHashString(Name, Hash);
+ std::string NameB = (Name.take_front(TakeN) + Hash).str();
+
+ StringRef N = NameB;
+ StringRef U = UniqueB;
+ error(IO.mapStringZ(N));
+ error(IO.mapStringZ(U));
+ } else {
+ error(IO.mapStringZ(Name));
+ error(IO.mapStringZ(UniqueName));
+ }
+ } else {
+ // Cap the length of the string at however many bytes we have available,
+ // plus one for the required null terminator.
+ auto N = StringRef(Name).take_front(BytesLeft - 1);
+ error(IO.mapStringZ(N));
+ }
+ } else {
+ // Reading & Streaming mode come after writing mode is executed for each
+ // record. Truncating large names are done during writing, so its not
+ // necessary to do it while reading or streaming.
+ error(IO.mapStringZ(Name, "Name"));
+ if (HasUniqueName)
+ error(IO.mapStringZ(UniqueName, "LinkageName"));
+ }
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitTypeBegin(CVType &CVR) {
+ assert(!TypeKind.hasValue() && "Already in a type mapping!");
+ assert(!MemberKind.hasValue() && "Already in a member mapping!");
+
+ // FieldList and MethodList records can be any length because they can be
+ // split with continuation records. All other record types cannot be
+ // longer than the maximum record length.
+ Optional<uint32_t> MaxLen;
+ if (CVR.kind() != TypeLeafKind::LF_FIELDLIST &&
+ CVR.kind() != TypeLeafKind::LF_METHODLIST)
+ MaxLen = MaxRecordLength - sizeof(RecordPrefix);
+ error(IO.beginRecord(MaxLen));
+ TypeKind = CVR.kind();
+
+ if (IO.isStreaming()) {
+ auto RecordKind = CVR.kind();
+ uint16_t RecordLen = CVR.length() - 2;
+ std::string RecordKindName = std::string(
+ getEnumName(IO, unsigned(RecordKind), makeArrayRef(LeafTypeNames)));
+ error(IO.mapInteger(RecordLen, "Record length"));
+ error(IO.mapEnum(RecordKind, "Record kind: " + RecordKindName));
+ }
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitTypeBegin(CVType &CVR, TypeIndex Index) {
+ if (IO.isStreaming())
+ IO.emitRawComment(" " + getLeafTypeName(CVR.kind()) + " (0x" +
+ utohexstr(Index.getIndex()) + ")");
+ return visitTypeBegin(CVR);
+}
+
+Error TypeRecordMapping::visitTypeEnd(CVType &Record) {
+ assert(TypeKind.hasValue() && "Not in a type mapping!");
+ assert(!MemberKind.hasValue() && "Still in a member mapping!");
+
+ error(IO.endRecord());
+
+ TypeKind.reset();
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitMemberBegin(CVMemberRecord &Record) {
+ assert(TypeKind.hasValue() && "Not in a type mapping!");
+ assert(!MemberKind.hasValue() && "Already in a member mapping!");
+
+ // The largest possible subrecord is one in which there is a record prefix,
+ // followed by the subrecord, followed by a continuation, and that entire
+ // sequence spawns `MaxRecordLength` bytes. So the record's length is
+ // calculated as follows.
+
+ constexpr uint32_t ContinuationLength = 8;
+ error(IO.beginRecord(MaxRecordLength - sizeof(RecordPrefix) -
+ ContinuationLength));
+
+ MemberKind = Record.Kind;
+ if (IO.isStreaming()) {
+ std::string MemberKindName = std::string(getLeafTypeName(Record.Kind));
+ MemberKindName +=
+ " ( " +
+ (getEnumName(IO, unsigned(Record.Kind), makeArrayRef(LeafTypeNames)))
+ .str() +
+ " )";
+ error(IO.mapEnum(Record.Kind, "Member kind: " + MemberKindName));
+ }
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitMemberEnd(CVMemberRecord &Record) {
+ assert(TypeKind.hasValue() && "Not in a type mapping!");
+ assert(MemberKind.hasValue() && "Not in a member mapping!");
+
+ if (IO.isReading()) {
+ if (auto EC = IO.skipPadding())
+ return EC;
+ }
+
+ MemberKind.reset();
+ error(IO.endRecord());
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ModifierRecord &Record) {
+ std::string ModifierNames =
+ getFlagNames(IO, static_cast<uint16_t>(Record.Modifiers),
+ makeArrayRef(getTypeModifierNames()));
+ error(IO.mapInteger(Record.ModifiedType, "ModifiedType"));
+ error(IO.mapEnum(Record.Modifiers, "Modifiers" + ModifierNames));
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ ProcedureRecord &Record) {
+ std::string CallingConvName = std::string(getEnumName(
+ IO, uint8_t(Record.CallConv), makeArrayRef(getCallingConventions())));
+ std::string FuncOptionNames =
+ getFlagNames(IO, static_cast<uint16_t>(Record.Options),
+ makeArrayRef(getFunctionOptionEnum()));
+ error(IO.mapInteger(Record.ReturnType, "ReturnType"));
+ error(IO.mapEnum(Record.CallConv, "CallingConvention: " + CallingConvName));
+ error(IO.mapEnum(Record.Options, "FunctionOptions" + FuncOptionNames));
+ error(IO.mapInteger(Record.ParameterCount, "NumParameters"));
+ error(IO.mapInteger(Record.ArgumentList, "ArgListType"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ MemberFunctionRecord &Record) {
+ std::string CallingConvName = std::string(getEnumName(
+ IO, uint8_t(Record.CallConv), makeArrayRef(getCallingConventions())));
+ std::string FuncOptionNames =
+ getFlagNames(IO, static_cast<uint16_t>(Record.Options),
+ makeArrayRef(getFunctionOptionEnum()));
+ error(IO.mapInteger(Record.ReturnType, "ReturnType"));
+ error(IO.mapInteger(Record.ClassType, "ClassType"));
+ error(IO.mapInteger(Record.ThisType, "ThisType"));
+ error(IO.mapEnum(Record.CallConv, "CallingConvention: " + CallingConvName));
+ error(IO.mapEnum(Record.Options, "FunctionOptions" + FuncOptionNames));
+ error(IO.mapInteger(Record.ParameterCount, "NumParameters"));
+ error(IO.mapInteger(Record.ArgumentList, "ArgListType"));
+ error(IO.mapInteger(Record.ThisPointerAdjustment, "ThisAdjustment"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArgListRecord &Record) {
+ error(IO.mapVectorN<uint32_t>(
+ Record.ArgIndices,
+ [](CodeViewRecordIO &IO, TypeIndex &N) {
+ return IO.mapInteger(N, "Argument");
+ },
+ "NumArgs"));
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ StringListRecord &Record) {
+ error(IO.mapVectorN<uint32_t>(
+ Record.StringIndices,
+ [](CodeViewRecordIO &IO, TypeIndex &N) {
+ return IO.mapInteger(N, "Strings");
+ },
+ "NumStrings"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, PointerRecord &Record) {
+
+ SmallString<128> Attr("Attrs: ");
+
+ if (IO.isStreaming()) {
+ std::string PtrType =
+ std::string(getEnumName(IO, unsigned(Record.getPointerKind()),
+ makeArrayRef(getPtrKindNames())));
+ Attr += "[ Type: " + PtrType;
+
+ std::string PtrMode = std::string(getEnumName(
+ IO, unsigned(Record.getMode()), makeArrayRef(getPtrModeNames())));
+ Attr += ", Mode: " + PtrMode;
+
+ auto PtrSizeOf = Record.getSize();
+ Attr += ", SizeOf: " + itostr(PtrSizeOf);
+
+ if (Record.isFlat())
+ Attr += ", isFlat";
+ if (Record.isConst())
+ Attr += ", isConst";
+ if (Record.isVolatile())
+ Attr += ", isVolatile";
+ if (Record.isUnaligned())
+ Attr += ", isUnaligned";
+ if (Record.isRestrict())
+ Attr += ", isRestricted";
+ if (Record.isLValueReferenceThisPtr())
+ Attr += ", isThisPtr&";
+ if (Record.isRValueReferenceThisPtr())
+ Attr += ", isThisPtr&&";
+ Attr += " ]";
+ }
+
+ error(IO.mapInteger(Record.ReferentType, "PointeeType"));
+ error(IO.mapInteger(Record.Attrs, Attr));
+
+ if (Record.isPointerToMember()) {
+ if (IO.isReading())
+ Record.MemberInfo.emplace();
+
+ MemberPointerInfo &M = *Record.MemberInfo;
+ error(IO.mapInteger(M.ContainingType, "ClassType"));
+ std::string PtrMemberGetRepresentation = std::string(getEnumName(
+ IO, uint16_t(M.Representation), makeArrayRef(getPtrMemberRepNames())));
+ error(IO.mapEnum(M.Representation,
+ "Representation: " + PtrMemberGetRepresentation));
+ }
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ArrayRecord &Record) {
+ error(IO.mapInteger(Record.ElementType, "ElementType"));
+ error(IO.mapInteger(Record.IndexType, "IndexType"));
+ error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, ClassRecord &Record) {
+ assert((CVR.kind() == TypeLeafKind::LF_STRUCTURE) ||
+ (CVR.kind() == TypeLeafKind::LF_CLASS) ||
+ (CVR.kind() == TypeLeafKind::LF_INTERFACE));
+
+ std::string PropertiesNames =
+ getFlagNames(IO, static_cast<uint16_t>(Record.Options),
+ makeArrayRef(getClassOptionNames()));
+ error(IO.mapInteger(Record.MemberCount, "MemberCount"));
+ error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
+ error(IO.mapInteger(Record.FieldList, "FieldList"));
+ error(IO.mapInteger(Record.DerivationList, "DerivedFrom"));
+ error(IO.mapInteger(Record.VTableShape, "VShape"));
+ error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
+ error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
+ Record.hasUniqueName()));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, UnionRecord &Record) {
+ std::string PropertiesNames =
+ getFlagNames(IO, static_cast<uint16_t>(Record.Options),
+ makeArrayRef(getClassOptionNames()));
+ error(IO.mapInteger(Record.MemberCount, "MemberCount"));
+ error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
+ error(IO.mapInteger(Record.FieldList, "FieldList"));
+ error(IO.mapEncodedInteger(Record.Size, "SizeOf"));
+ error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
+ Record.hasUniqueName()));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, EnumRecord &Record) {
+ std::string PropertiesNames =
+ getFlagNames(IO, static_cast<uint16_t>(Record.Options),
+ makeArrayRef(getClassOptionNames()));
+ error(IO.mapInteger(Record.MemberCount, "NumEnumerators"));
+ error(IO.mapEnum(Record.Options, "Properties" + PropertiesNames));
+ error(IO.mapInteger(Record.UnderlyingType, "UnderlyingType"));
+ error(IO.mapInteger(Record.FieldList, "FieldListType"));
+ error(mapNameAndUniqueName(IO, Record.Name, Record.UniqueName,
+ Record.hasUniqueName()));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, BitFieldRecord &Record) {
+ error(IO.mapInteger(Record.Type, "Type"));
+ error(IO.mapInteger(Record.BitSize, "BitSize"));
+ error(IO.mapInteger(Record.BitOffset, "BitOffset"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ VFTableShapeRecord &Record) {
+ uint16_t Size;
+ if (!IO.isReading()) {
+ ArrayRef<VFTableSlotKind> Slots = Record.getSlots();
+ Size = Slots.size();
+ error(IO.mapInteger(Size, "VFEntryCount"));
+
+ for (size_t SlotIndex = 0; SlotIndex < Slots.size(); SlotIndex += 2) {
+ uint8_t Byte = static_cast<uint8_t>(Slots[SlotIndex]) << 4;
+ if ((SlotIndex + 1) < Slots.size()) {
+ Byte |= static_cast<uint8_t>(Slots[SlotIndex + 1]);
+ }
+ error(IO.mapInteger(Byte));
+ }
+ } else {
+ error(IO.mapInteger(Size));
+ for (uint16_t I = 0; I < Size; I += 2) {
+ uint8_t Byte;
+ error(IO.mapInteger(Byte));
+ Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte & 0xF));
+ if ((I + 1) < Size)
+ Record.Slots.push_back(static_cast<VFTableSlotKind>(Byte >> 4));
+ }
+ }
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, VFTableRecord &Record) {
+ error(IO.mapInteger(Record.CompleteClass, "CompleteClass"));
+ error(IO.mapInteger(Record.OverriddenVFTable, "OverriddenVFTable"));
+ error(IO.mapInteger(Record.VFPtrOffset, "VFPtrOffset"));
+ uint32_t NamesLen = 0;
+ if (!IO.isReading()) {
+ for (auto Name : Record.MethodNames)
+ NamesLen += Name.size() + 1;
+ }
+ error(IO.mapInteger(NamesLen));
+ error(IO.mapVectorTail(
+ Record.MethodNames,
+ [](CodeViewRecordIO &IO, StringRef &S) {
+ return IO.mapStringZ(S, "MethodName");
+ },
+ "VFTableName"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, StringIdRecord &Record) {
+ error(IO.mapInteger(Record.Id, "Id"));
+ error(IO.mapStringZ(Record.String, "StringData"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ UdtSourceLineRecord &Record) {
+ error(IO.mapInteger(Record.UDT, "UDT"));
+ error(IO.mapInteger(Record.SourceFile, "SourceFile"));
+ error(IO.mapInteger(Record.LineNumber, "LineNumber"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ UdtModSourceLineRecord &Record) {
+ error(IO.mapInteger(Record.UDT, "UDT"));
+ error(IO.mapInteger(Record.SourceFile, "SourceFile"));
+ error(IO.mapInteger(Record.LineNumber, "LineNumber"));
+ error(IO.mapInteger(Record.Module, "Module"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, FuncIdRecord &Record) {
+ error(IO.mapInteger(Record.ParentScope, "ParentScope"));
+ error(IO.mapInteger(Record.FunctionType, "FunctionType"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ MemberFuncIdRecord &Record) {
+ error(IO.mapInteger(Record.ClassType, "ClassType"));
+ error(IO.mapInteger(Record.FunctionType, "FunctionType"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ BuildInfoRecord &Record) {
+ error(IO.mapVectorN<uint16_t>(
+ Record.ArgIndices,
+ [](CodeViewRecordIO &IO, TypeIndex &N) {
+ return IO.mapInteger(N, "Argument");
+ },
+ "NumArgs"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ MethodOverloadListRecord &Record) {
+ // TODO: Split the list into multiple records if it's longer than 64KB, using
+ // a subrecord of TypeRecordKind::Index to chain the records together.
+ error(IO.mapVectorTail(Record.Methods, MapOneMethodRecord(true), "Method"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ FieldListRecord &Record) {
+ if (IO.isStreaming()) {
+ if (auto EC = codeview::visitMemberRecordStream(Record.Data, *this))
+ return EC;
+ } else
+ error(IO.mapByteVectorTail(Record.Data));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ TypeServer2Record &Record) {
+ error(IO.mapGuid(Record.Guid, "Guid"));
+ error(IO.mapInteger(Record.Age, "Age"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR, LabelRecord &Record) {
+ std::string ModeName = std::string(
+ getEnumName(IO, uint16_t(Record.Mode), makeArrayRef(getLabelTypeEnum())));
+ error(IO.mapEnum(Record.Mode, "Mode: " + ModeName));
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ BaseClassRecord &Record) {
+ std::string Attrs = getMemberAttributes(
+ IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
+ error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
+ error(IO.mapInteger(Record.Type, "BaseType"));
+ error(IO.mapEncodedInteger(Record.Offset, "BaseOffset"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ EnumeratorRecord &Record) {
+ std::string Attrs = getMemberAttributes(
+ IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
+ error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
+
+ // FIXME: Handle full APInt such as __int128.
+ error(IO.mapEncodedInteger(Record.Value, "EnumValue"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ DataMemberRecord &Record) {
+ std::string Attrs = getMemberAttributes(
+ IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
+ error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
+ error(IO.mapInteger(Record.Type, "Type"));
+ error(IO.mapEncodedInteger(Record.FieldOffset, "FieldOffset"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ OverloadedMethodRecord &Record) {
+ error(IO.mapInteger(Record.NumOverloads, "MethodCount"));
+ error(IO.mapInteger(Record.MethodList, "MethodListIndex"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ OneMethodRecord &Record) {
+ const bool IsFromOverloadList = (TypeKind == LF_METHODLIST);
+ MapOneMethodRecord Mapper(IsFromOverloadList);
+ return Mapper(IO, Record);
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ NestedTypeRecord &Record) {
+ uint16_t Padding = 0;
+ error(IO.mapInteger(Padding, "Padding"));
+ error(IO.mapInteger(Record.Type, "Type"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ StaticDataMemberRecord &Record) {
+
+ std::string Attrs = getMemberAttributes(
+ IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
+ error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
+ error(IO.mapInteger(Record.Type, "Type"));
+ error(IO.mapStringZ(Record.Name, "Name"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ VirtualBaseClassRecord &Record) {
+
+ std::string Attrs = getMemberAttributes(
+ IO, Record.getAccess(), MethodKind::Vanilla, MethodOptions::None);
+ error(IO.mapInteger(Record.Attrs.Attrs, "Attrs: " + Attrs));
+ error(IO.mapInteger(Record.BaseType, "BaseType"));
+ error(IO.mapInteger(Record.VBPtrType, "VBPtrType"));
+ error(IO.mapEncodedInteger(Record.VBPtrOffset, "VBPtrOffset"));
+ error(IO.mapEncodedInteger(Record.VTableIndex, "VBTableIndex"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ VFPtrRecord &Record) {
+ uint16_t Padding = 0;
+ error(IO.mapInteger(Padding, "Padding"));
+ error(IO.mapInteger(Record.Type, "Type"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownMember(CVMemberRecord &CVR,
+ ListContinuationRecord &Record) {
+ uint16_t Padding = 0;
+ error(IO.mapInteger(Padding, "Padding"));
+ error(IO.mapInteger(Record.ContinuationIndex, "ContinuationIndex"));
+
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ PrecompRecord &Precomp) {
+ error(IO.mapInteger(Precomp.StartTypeIndex, "StartIndex"));
+ error(IO.mapInteger(Precomp.TypesCount, "Count"));
+ error(IO.mapInteger(Precomp.Signature, "Signature"));
+ error(IO.mapStringZ(Precomp.PrecompFilePath, "PrecompFile"));
+ return Error::success();
+}
+
+Error TypeRecordMapping::visitKnownRecord(CVType &CVR,
+ EndPrecompRecord &EndPrecomp) {
+ error(IO.mapInteger(EndPrecomp.Signature, "Signature"));
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeStreamMerger.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
new file mode 100644
index 0000000000..587a68142a
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeStreamMerger.cpp
@@ -0,0 +1,496 @@
+//===-- 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 occurring 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;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeTableCollection.cpp b/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeTableCollection.cpp
new file mode 100644
index 0000000000..e517e8846d
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/TypeTableCollection.cpp
@@ -0,0 +1,65 @@
+//===- TypeTableCollection.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/TypeTableCollection.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/RecordName.h"
+#include "llvm/Support/BinaryStreamReader.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+
+TypeTableCollection::TypeTableCollection(ArrayRef<ArrayRef<uint8_t>> Records)
+ : NameStorage(Allocator), Records(Records) {
+ Names.resize(Records.size());
+}
+
+Optional<TypeIndex> TypeTableCollection::getFirst() {
+ if (empty())
+ return None;
+ return TypeIndex::fromArrayIndex(0);
+}
+
+Optional<TypeIndex> TypeTableCollection::getNext(TypeIndex Prev) {
+ assert(contains(Prev));
+ ++Prev;
+ if (Prev.toArrayIndex() == size())
+ return None;
+ return Prev;
+}
+
+CVType TypeTableCollection::getType(TypeIndex Index) {
+ assert(Index.toArrayIndex() < Records.size());
+ return CVType(Records[Index.toArrayIndex()]);
+}
+
+StringRef TypeTableCollection::getTypeName(TypeIndex Index) {
+ if (Index.isNoneType() || Index.isSimple())
+ return TypeIndex::simpleTypeName(Index);
+
+ uint32_t I = Index.toArrayIndex();
+ if (Names[I].data() == nullptr) {
+ StringRef Result = NameStorage.save(computeTypeName(*this, Index));
+ Names[I] = Result;
+ }
+ return Names[I];
+}
+
+bool TypeTableCollection::contains(TypeIndex Index) {
+ return Index.toArrayIndex() <= size();
+}
+
+uint32_t TypeTableCollection::size() { return Records.size(); }
+
+uint32_t TypeTableCollection::capacity() { return Records.size(); }
+
+bool TypeTableCollection::replaceType(TypeIndex &Index, CVType Data,
+ bool Stabilize) {
+ llvm_unreachable("Method cannot be called");
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/CodeView/ya.make b/contrib/libs/llvm14/lib/DebugInfo/CodeView/ya.make
new file mode 100644
index 0000000000..5d1ed80b2e
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/CodeView/ya.make
@@ -0,0 +1,65 @@
+# Generated by devtools/yamaker.
+
+LIBRARY()
+
+LICENSE(Apache-2.0 WITH LLVM-exception)
+
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
+PEERDIR(
+ contrib/libs/llvm14
+ contrib/libs/llvm14/lib/Support
+)
+
+ADDINCL(
+ contrib/libs/llvm14/lib/DebugInfo/CodeView
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ AppendingTypeTableBuilder.cpp
+ CVSymbolVisitor.cpp
+ CVTypeVisitor.cpp
+ CodeViewError.cpp
+ CodeViewRecordIO.cpp
+ ContinuationRecordBuilder.cpp
+ DebugChecksumsSubsection.cpp
+ DebugCrossExSubsection.cpp
+ DebugCrossImpSubsection.cpp
+ DebugFrameDataSubsection.cpp
+ DebugInlineeLinesSubsection.cpp
+ DebugLinesSubsection.cpp
+ DebugStringTableSubsection.cpp
+ DebugSubsection.cpp
+ DebugSubsectionRecord.cpp
+ DebugSubsectionVisitor.cpp
+ DebugSymbolRVASubsection.cpp
+ DebugSymbolsSubsection.cpp
+ EnumTables.cpp
+ Formatters.cpp
+ GlobalTypeTableBuilder.cpp
+ LazyRandomTypeCollection.cpp
+ Line.cpp
+ MergingTypeTableBuilder.cpp
+ RecordName.cpp
+ RecordSerialization.cpp
+ SimpleTypeSerializer.cpp
+ StringsAndChecksums.cpp
+ SymbolDumper.cpp
+ SymbolRecordHelpers.cpp
+ SymbolRecordMapping.cpp
+ SymbolSerializer.cpp
+ TypeDumpVisitor.cpp
+ TypeHashing.cpp
+ TypeIndex.cpp
+ TypeIndexDiscovery.cpp
+ TypeRecordHelpers.cpp
+ TypeRecordMapping.cpp
+ TypeStreamMerger.cpp
+ TypeTableCollection.cpp
+)
+
+END()
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
new file mode 100644
index 0000000000..1be5a75245
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFAbbreviationDeclaration.cpp
@@ -0,0 +1,231 @@
+//===- DWARFAbbreviationDeclaration.cpp -----------------------------------===//
+//
+// 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/DWARF/DWARFAbbreviationDeclaration.h"
+
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstddef>
+#include <cstdint>
+
+using namespace llvm;
+using namespace dwarf;
+
+void DWARFAbbreviationDeclaration::clear() {
+ Code = 0;
+ Tag = DW_TAG_null;
+ CodeByteSize = 0;
+ HasChildren = false;
+ AttributeSpecs.clear();
+ FixedAttributeSize.reset();
+}
+
+DWARFAbbreviationDeclaration::DWARFAbbreviationDeclaration() {
+ clear();
+}
+
+bool
+DWARFAbbreviationDeclaration::extract(DataExtractor Data,
+ uint64_t* OffsetPtr) {
+ clear();
+ const uint64_t Offset = *OffsetPtr;
+ Code = Data.getULEB128(OffsetPtr);
+ if (Code == 0) {
+ return false;
+ }
+ CodeByteSize = *OffsetPtr - Offset;
+ Tag = static_cast<llvm::dwarf::Tag>(Data.getULEB128(OffsetPtr));
+ if (Tag == DW_TAG_null) {
+ clear();
+ return false;
+ }
+ uint8_t ChildrenByte = Data.getU8(OffsetPtr);
+ HasChildren = (ChildrenByte == DW_CHILDREN_yes);
+ // Assign a value to our optional FixedAttributeSize member variable. If
+ // this member variable still has a value after the while loop below, then
+ // all attribute data in this abbreviation declaration has a fixed byte size.
+ FixedAttributeSize = FixedSizeInfo();
+
+ // Read all of the abbreviation attributes and forms.
+ while (true) {
+ auto A = static_cast<Attribute>(Data.getULEB128(OffsetPtr));
+ auto F = static_cast<Form>(Data.getULEB128(OffsetPtr));
+ if (A && F) {
+ bool IsImplicitConst = (F == DW_FORM_implicit_const);
+ if (IsImplicitConst) {
+ int64_t V = Data.getSLEB128(OffsetPtr);
+ AttributeSpecs.push_back(AttributeSpec(A, F, V));
+ continue;
+ }
+ Optional<uint8_t> ByteSize;
+ // If this abbrevation still has a fixed byte size, then update the
+ // FixedAttributeSize as needed.
+ switch (F) {
+ case DW_FORM_addr:
+ if (FixedAttributeSize)
+ ++FixedAttributeSize->NumAddrs;
+ break;
+
+ case DW_FORM_ref_addr:
+ if (FixedAttributeSize)
+ ++FixedAttributeSize->NumRefAddrs;
+ break;
+
+ case DW_FORM_strp:
+ case DW_FORM_GNU_ref_alt:
+ case DW_FORM_GNU_strp_alt:
+ case DW_FORM_line_strp:
+ case DW_FORM_sec_offset:
+ case DW_FORM_strp_sup:
+ if (FixedAttributeSize)
+ ++FixedAttributeSize->NumDwarfOffsets;
+ break;
+
+ default:
+ // The form has a byte size that doesn't depend on Params.
+ // If it's a fixed size, keep track of it.
+ if ((ByteSize = dwarf::getFixedFormByteSize(F, dwarf::FormParams()))) {
+ if (FixedAttributeSize)
+ FixedAttributeSize->NumBytes += *ByteSize;
+ break;
+ }
+ // Indicate we no longer have a fixed byte size for this
+ // abbreviation by clearing the FixedAttributeSize optional value
+ // so it doesn't have a value.
+ FixedAttributeSize.reset();
+ break;
+ }
+ // Record this attribute and its fixed size if it has one.
+ AttributeSpecs.push_back(AttributeSpec(A, F, ByteSize));
+ } else if (A == 0 && F == 0) {
+ // We successfully reached the end of this abbreviation declaration
+ // since both attribute and form are zero.
+ break;
+ } else {
+ // Attribute and form pairs must either both be non-zero, in which case
+ // they are added to the abbreviation declaration, or both be zero to
+ // terminate the abbrevation declaration. In this case only one was
+ // zero which is an error.
+ clear();
+ return false;
+ }
+ }
+ return true;
+}
+
+void DWARFAbbreviationDeclaration::dump(raw_ostream &OS) const {
+ OS << '[' << getCode() << "] ";
+ OS << formatv("{0}", getTag());
+ OS << "\tDW_CHILDREN_" << (hasChildren() ? "yes" : "no") << '\n';
+ for (const AttributeSpec &Spec : AttributeSpecs) {
+ OS << formatv("\t{0}\t{1}", Spec.Attr, Spec.Form);
+ if (Spec.isImplicitConst())
+ OS << '\t' << Spec.getImplicitConstValue();
+ OS << '\n';
+ }
+ OS << '\n';
+}
+
+Optional<uint32_t>
+DWARFAbbreviationDeclaration::findAttributeIndex(dwarf::Attribute Attr) const {
+ for (uint32_t i = 0, e = AttributeSpecs.size(); i != e; ++i) {
+ if (AttributeSpecs[i].Attr == Attr)
+ return i;
+ }
+ return None;
+}
+
+uint64_t DWARFAbbreviationDeclaration::getAttributeOffsetFromIndex(
+ uint32_t AttrIndex, uint64_t DIEOffset, const DWARFUnit &U) const {
+ DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();
+
+ // Add the byte size of ULEB that for the abbrev Code so we can start
+ // skipping the attribute data.
+ uint64_t Offset = DIEOffset + CodeByteSize;
+ for (uint32_t CurAttrIdx = 0; CurAttrIdx != AttrIndex; ++CurAttrIdx)
+ // Match Offset along until we get to the attribute we want.
+ if (auto FixedSize = AttributeSpecs[CurAttrIdx].getByteSize(U))
+ Offset += *FixedSize;
+ else
+ DWARFFormValue::skipValue(AttributeSpecs[CurAttrIdx].Form, DebugInfoData,
+ &Offset, U.getFormParams());
+ return Offset;
+}
+
+Optional<DWARFFormValue>
+DWARFAbbreviationDeclaration::getAttributeValueFromOffset(
+ uint32_t AttrIndex, uint64_t Offset, const DWARFUnit &U) const {
+ assert(AttributeSpecs.size() > AttrIndex &&
+ "Attribute Index is out of bounds.");
+
+ // We have arrived at the attribute to extract, extract if from Offset.
+ const AttributeSpec &Spec = AttributeSpecs[AttrIndex];
+ if (Spec.isImplicitConst())
+ return DWARFFormValue::createFromSValue(Spec.Form,
+ Spec.getImplicitConstValue());
+
+ DWARFFormValue FormValue(Spec.Form);
+ DWARFDataExtractor DebugInfoData = U.getDebugInfoExtractor();
+ if (FormValue.extractValue(DebugInfoData, &Offset, U.getFormParams(), &U))
+ return FormValue;
+ return None;
+}
+
+Optional<DWARFFormValue>
+DWARFAbbreviationDeclaration::getAttributeValue(const uint64_t DIEOffset,
+ const dwarf::Attribute Attr,
+ const DWARFUnit &U) const {
+ // Check if this abbreviation has this attribute without needing to skip
+ // any data so we can return quickly if it doesn't.
+ Optional<uint32_t> MatchAttrIndex = findAttributeIndex(Attr);
+ if (!MatchAttrIndex)
+ return None;
+
+ uint64_t Offset = getAttributeOffsetFromIndex(*MatchAttrIndex, DIEOffset, U);
+
+ return getAttributeValueFromOffset(*MatchAttrIndex, Offset, U);
+}
+
+size_t DWARFAbbreviationDeclaration::FixedSizeInfo::getByteSize(
+ const DWARFUnit &U) const {
+ size_t ByteSize = NumBytes;
+ if (NumAddrs)
+ ByteSize += NumAddrs * U.getAddressByteSize();
+ if (NumRefAddrs)
+ ByteSize += NumRefAddrs * U.getRefAddrByteSize();
+ if (NumDwarfOffsets)
+ ByteSize += NumDwarfOffsets * U.getDwarfOffsetByteSize();
+ return ByteSize;
+}
+
+Optional<int64_t> DWARFAbbreviationDeclaration::AttributeSpec::getByteSize(
+ const DWARFUnit &U) const {
+ if (isImplicitConst())
+ return 0;
+ if (ByteSize.HasByteSize)
+ return ByteSize.ByteSize;
+ Optional<int64_t> S;
+ auto FixedByteSize = dwarf::getFixedFormByteSize(Form, U.getFormParams());
+ if (FixedByteSize)
+ S = *FixedByteSize;
+ return S;
+}
+
+Optional<size_t> DWARFAbbreviationDeclaration::getFixedAttributesByteSize(
+ const DWARFUnit &U) const {
+ if (FixedAttributeSize)
+ return FixedAttributeSize->getByteSize(U);
+ return None;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
new file mode 100644
index 0000000000..c77d4d4d98
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFAcceleratorTable.cpp
@@ -0,0 +1,905 @@
+//===- DWARFAcceleratorTable.cpp ------------------------------------------===//
+//
+// 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/DWARF/DWARFAcceleratorTable.h"
+
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DJB.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/ScopedPrinter.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstddef>
+#include <cstdint>
+#include <utility>
+
+using namespace llvm;
+
+namespace {
+struct Atom {
+ unsigned Value;
+};
+
+static raw_ostream &operator<<(raw_ostream &OS, const Atom &A) {
+ StringRef Str = dwarf::AtomTypeString(A.Value);
+ if (!Str.empty())
+ return OS << Str;
+ return OS << "DW_ATOM_unknown_" << format("%x", A.Value);
+}
+} // namespace
+
+static Atom formatAtom(unsigned Atom) { return {Atom}; }
+
+DWARFAcceleratorTable::~DWARFAcceleratorTable() = default;
+
+Error AppleAcceleratorTable::extract() {
+ uint64_t Offset = 0;
+
+ // Check that we can at least read the header.
+ if (!AccelSection.isValidOffset(offsetof(Header, HeaderDataLength) + 4))
+ return createStringError(errc::illegal_byte_sequence,
+ "Section too small: cannot read header.");
+
+ Hdr.Magic = AccelSection.getU32(&Offset);
+ Hdr.Version = AccelSection.getU16(&Offset);
+ Hdr.HashFunction = AccelSection.getU16(&Offset);
+ Hdr.BucketCount = AccelSection.getU32(&Offset);
+ Hdr.HashCount = AccelSection.getU32(&Offset);
+ Hdr.HeaderDataLength = AccelSection.getU32(&Offset);
+
+ // Check that we can read all the hashes and offsets from the
+ // section (see SourceLevelDebugging.rst for the structure of the index).
+ // We need to substract one because we're checking for an *offset* which is
+ // equal to the size for an empty table and hence pointer after the section.
+ if (!AccelSection.isValidOffset(sizeof(Hdr) + Hdr.HeaderDataLength +
+ Hdr.BucketCount * 4 + Hdr.HashCount * 8 - 1))
+ return createStringError(
+ errc::illegal_byte_sequence,
+ "Section too small: cannot read buckets and hashes.");
+
+ HdrData.DIEOffsetBase = AccelSection.getU32(&Offset);
+ uint32_t NumAtoms = AccelSection.getU32(&Offset);
+
+ for (unsigned i = 0; i < NumAtoms; ++i) {
+ uint16_t AtomType = AccelSection.getU16(&Offset);
+ auto AtomForm = static_cast<dwarf::Form>(AccelSection.getU16(&Offset));
+ HdrData.Atoms.push_back(std::make_pair(AtomType, AtomForm));
+ }
+
+ IsValid = true;
+ return Error::success();
+}
+
+uint32_t AppleAcceleratorTable::getNumBuckets() { return Hdr.BucketCount; }
+uint32_t AppleAcceleratorTable::getNumHashes() { return Hdr.HashCount; }
+uint32_t AppleAcceleratorTable::getSizeHdr() { return sizeof(Hdr); }
+uint32_t AppleAcceleratorTable::getHeaderDataLength() {
+ return Hdr.HeaderDataLength;
+}
+
+ArrayRef<std::pair<AppleAcceleratorTable::HeaderData::AtomType,
+ AppleAcceleratorTable::HeaderData::Form>>
+AppleAcceleratorTable::getAtomsDesc() {
+ return HdrData.Atoms;
+}
+
+bool AppleAcceleratorTable::validateForms() {
+ for (auto Atom : getAtomsDesc()) {
+ DWARFFormValue FormValue(Atom.second);
+ switch (Atom.first) {
+ case dwarf::DW_ATOM_die_offset:
+ case dwarf::DW_ATOM_die_tag:
+ case dwarf::DW_ATOM_type_flags:
+ if ((!FormValue.isFormClass(DWARFFormValue::FC_Constant) &&
+ !FormValue.isFormClass(DWARFFormValue::FC_Flag)) ||
+ FormValue.getForm() == dwarf::DW_FORM_sdata)
+ return false;
+ break;
+ default:
+ break;
+ }
+ }
+ return true;
+}
+
+std::pair<uint64_t, dwarf::Tag>
+AppleAcceleratorTable::readAtoms(uint64_t *HashDataOffset) {
+ uint64_t DieOffset = dwarf::DW_INVALID_OFFSET;
+ dwarf::Tag DieTag = dwarf::DW_TAG_null;
+ dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
+
+ for (auto Atom : getAtomsDesc()) {
+ DWARFFormValue FormValue(Atom.second);
+ FormValue.extractValue(AccelSection, HashDataOffset, FormParams);
+ switch (Atom.first) {
+ case dwarf::DW_ATOM_die_offset:
+ DieOffset = *FormValue.getAsUnsignedConstant();
+ break;
+ case dwarf::DW_ATOM_die_tag:
+ DieTag = (dwarf::Tag)*FormValue.getAsUnsignedConstant();
+ break;
+ default:
+ break;
+ }
+ }
+ return {DieOffset, DieTag};
+}
+
+void AppleAcceleratorTable::Header::dump(ScopedPrinter &W) const {
+ DictScope HeaderScope(W, "Header");
+ W.printHex("Magic", Magic);
+ W.printHex("Version", Version);
+ W.printHex("Hash function", HashFunction);
+ W.printNumber("Bucket count", BucketCount);
+ W.printNumber("Hashes count", HashCount);
+ W.printNumber("HeaderData length", HeaderDataLength);
+}
+
+Optional<uint64_t> AppleAcceleratorTable::HeaderData::extractOffset(
+ Optional<DWARFFormValue> Value) const {
+ if (!Value)
+ return None;
+
+ switch (Value->getForm()) {
+ case dwarf::DW_FORM_ref1:
+ case dwarf::DW_FORM_ref2:
+ case dwarf::DW_FORM_ref4:
+ case dwarf::DW_FORM_ref8:
+ case dwarf::DW_FORM_ref_udata:
+ return Value->getRawUValue() + DIEOffsetBase;
+ default:
+ return Value->getAsSectionOffset();
+ }
+}
+
+bool AppleAcceleratorTable::dumpName(ScopedPrinter &W,
+ SmallVectorImpl<DWARFFormValue> &AtomForms,
+ uint64_t *DataOffset) const {
+ dwarf::FormParams FormParams = {Hdr.Version, 0, dwarf::DwarfFormat::DWARF32};
+ uint64_t NameOffset = *DataOffset;
+ if (!AccelSection.isValidOffsetForDataOfSize(*DataOffset, 4)) {
+ W.printString("Incorrectly terminated list.");
+ return false;
+ }
+ uint64_t StringOffset = AccelSection.getRelocatedValue(4, DataOffset);
+ if (!StringOffset)
+ return false; // End of list
+
+ DictScope NameScope(W, ("Name@0x" + Twine::utohexstr(NameOffset)).str());
+ W.startLine() << format("String: 0x%08" PRIx64, StringOffset);
+ W.getOStream() << " \"" << StringSection.getCStr(&StringOffset) << "\"\n";
+
+ unsigned NumData = AccelSection.getU32(DataOffset);
+ for (unsigned Data = 0; Data < NumData; ++Data) {
+ ListScope DataScope(W, ("Data " + Twine(Data)).str());
+ unsigned i = 0;
+ for (auto &Atom : AtomForms) {
+ W.startLine() << format("Atom[%d]: ", i);
+ if (Atom.extractValue(AccelSection, DataOffset, FormParams)) {
+ Atom.dump(W.getOStream());
+ if (Optional<uint64_t> Val = Atom.getAsUnsignedConstant()) {
+ StringRef Str = dwarf::AtomValueString(HdrData.Atoms[i].first, *Val);
+ if (!Str.empty())
+ W.getOStream() << " (" << Str << ")";
+ }
+ } else
+ W.getOStream() << "Error extracting the value";
+ W.getOStream() << "\n";
+ i++;
+ }
+ }
+ return true; // more entries follow
+}
+
+LLVM_DUMP_METHOD void AppleAcceleratorTable::dump(raw_ostream &OS) const {
+ if (!IsValid)
+ return;
+
+ ScopedPrinter W(OS);
+
+ Hdr.dump(W);
+
+ W.printNumber("DIE offset base", HdrData.DIEOffsetBase);
+ W.printNumber("Number of atoms", uint64_t(HdrData.Atoms.size()));
+ SmallVector<DWARFFormValue, 3> AtomForms;
+ {
+ ListScope AtomsScope(W, "Atoms");
+ unsigned i = 0;
+ for (const auto &Atom : HdrData.Atoms) {
+ DictScope AtomScope(W, ("Atom " + Twine(i++)).str());
+ W.startLine() << "Type: " << formatAtom(Atom.first) << '\n';
+ W.startLine() << "Form: " << formatv("{0}", Atom.second) << '\n';
+ AtomForms.push_back(DWARFFormValue(Atom.second));
+ }
+ }
+
+ // Now go through the actual tables and dump them.
+ uint64_t Offset = sizeof(Hdr) + Hdr.HeaderDataLength;
+ uint64_t HashesBase = Offset + Hdr.BucketCount * 4;
+ uint64_t OffsetsBase = HashesBase + Hdr.HashCount * 4;
+
+ for (unsigned Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket) {
+ unsigned Index = AccelSection.getU32(&Offset);
+
+ ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str());
+ if (Index == UINT32_MAX) {
+ W.printString("EMPTY");
+ continue;
+ }
+
+ for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) {
+ uint64_t HashOffset = HashesBase + HashIdx*4;
+ uint64_t OffsetsOffset = OffsetsBase + HashIdx*4;
+ uint32_t Hash = AccelSection.getU32(&HashOffset);
+
+ if (Hash % Hdr.BucketCount != Bucket)
+ break;
+
+ uint64_t DataOffset = AccelSection.getU32(&OffsetsOffset);
+ ListScope HashScope(W, ("Hash 0x" + Twine::utohexstr(Hash)).str());
+ if (!AccelSection.isValidOffset(DataOffset)) {
+ W.printString("Invalid section offset");
+ continue;
+ }
+ while (dumpName(W, AtomForms, &DataOffset))
+ /*empty*/;
+ }
+ }
+}
+
+AppleAcceleratorTable::Entry::Entry(
+ const AppleAcceleratorTable::HeaderData &HdrData)
+ : HdrData(&HdrData) {
+ Values.reserve(HdrData.Atoms.size());
+ for (const auto &Atom : HdrData.Atoms)
+ Values.push_back(DWARFFormValue(Atom.second));
+}
+
+void AppleAcceleratorTable::Entry::extract(
+ const AppleAcceleratorTable &AccelTable, uint64_t *Offset) {
+
+ dwarf::FormParams FormParams = {AccelTable.Hdr.Version, 0,
+ dwarf::DwarfFormat::DWARF32};
+ for (auto &Atom : Values)
+ Atom.extractValue(AccelTable.AccelSection, Offset, FormParams);
+}
+
+Optional<DWARFFormValue>
+AppleAcceleratorTable::Entry::lookup(HeaderData::AtomType Atom) const {
+ assert(HdrData && "Dereferencing end iterator?");
+ assert(HdrData->Atoms.size() == Values.size());
+ for (auto Tuple : zip_first(HdrData->Atoms, Values)) {
+ if (std::get<0>(Tuple).first == Atom)
+ return std::get<1>(Tuple);
+ }
+ return None;
+}
+
+Optional<uint64_t> AppleAcceleratorTable::Entry::getDIESectionOffset() const {
+ return HdrData->extractOffset(lookup(dwarf::DW_ATOM_die_offset));
+}
+
+Optional<uint64_t> AppleAcceleratorTable::Entry::getCUOffset() const {
+ return HdrData->extractOffset(lookup(dwarf::DW_ATOM_cu_offset));
+}
+
+Optional<dwarf::Tag> AppleAcceleratorTable::Entry::getTag() const {
+ Optional<DWARFFormValue> Tag = lookup(dwarf::DW_ATOM_die_tag);
+ if (!Tag)
+ return None;
+ if (Optional<uint64_t> Value = Tag->getAsUnsignedConstant())
+ return dwarf::Tag(*Value);
+ return None;
+}
+
+AppleAcceleratorTable::ValueIterator::ValueIterator(
+ const AppleAcceleratorTable &AccelTable, uint64_t Offset)
+ : AccelTable(&AccelTable), Current(AccelTable.HdrData), DataOffset(Offset) {
+ if (!AccelTable.AccelSection.isValidOffsetForDataOfSize(DataOffset, 4))
+ return;
+
+ // Read the first entry.
+ NumData = AccelTable.AccelSection.getU32(&DataOffset);
+ Next();
+}
+
+void AppleAcceleratorTable::ValueIterator::Next() {
+ assert(NumData > 0 && "attempted to increment iterator past the end");
+ auto &AccelSection = AccelTable->AccelSection;
+ if (Data >= NumData ||
+ !AccelSection.isValidOffsetForDataOfSize(DataOffset, 4)) {
+ NumData = 0;
+ DataOffset = 0;
+ return;
+ }
+ Current.extract(*AccelTable, &DataOffset);
+ ++Data;
+}
+
+iterator_range<AppleAcceleratorTable::ValueIterator>
+AppleAcceleratorTable::equal_range(StringRef Key) const {
+ if (!IsValid)
+ return make_range(ValueIterator(), ValueIterator());
+
+ // Find the bucket.
+ unsigned HashValue = djbHash(Key);
+ unsigned Bucket = HashValue % Hdr.BucketCount;
+ uint64_t BucketBase = sizeof(Hdr) + Hdr.HeaderDataLength;
+ uint64_t HashesBase = BucketBase + Hdr.BucketCount * 4;
+ uint64_t OffsetsBase = HashesBase + Hdr.HashCount * 4;
+
+ uint64_t BucketOffset = BucketBase + Bucket * 4;
+ unsigned Index = AccelSection.getU32(&BucketOffset);
+
+ // Search through all hashes in the bucket.
+ for (unsigned HashIdx = Index; HashIdx < Hdr.HashCount; ++HashIdx) {
+ uint64_t HashOffset = HashesBase + HashIdx * 4;
+ uint64_t OffsetsOffset = OffsetsBase + HashIdx * 4;
+ uint32_t Hash = AccelSection.getU32(&HashOffset);
+
+ if (Hash % Hdr.BucketCount != Bucket)
+ // We are already in the next bucket.
+ break;
+
+ uint64_t DataOffset = AccelSection.getU32(&OffsetsOffset);
+ uint64_t StringOffset = AccelSection.getRelocatedValue(4, &DataOffset);
+ if (!StringOffset)
+ break;
+
+ // Finally, compare the key.
+ if (Key == StringSection.getCStr(&StringOffset))
+ return make_range({*this, DataOffset}, ValueIterator());
+ }
+ return make_range(ValueIterator(), ValueIterator());
+}
+
+void DWARFDebugNames::Header::dump(ScopedPrinter &W) const {
+ DictScope HeaderScope(W, "Header");
+ W.printHex("Length", UnitLength);
+ W.printString("Format", dwarf::FormatString(Format));
+ W.printNumber("Version", Version);
+ W.printNumber("CU count", CompUnitCount);
+ W.printNumber("Local TU count", LocalTypeUnitCount);
+ W.printNumber("Foreign TU count", ForeignTypeUnitCount);
+ W.printNumber("Bucket count", BucketCount);
+ W.printNumber("Name count", NameCount);
+ W.printHex("Abbreviations table size", AbbrevTableSize);
+ W.startLine() << "Augmentation: '" << AugmentationString << "'\n";
+}
+
+Error DWARFDebugNames::Header::extract(const DWARFDataExtractor &AS,
+ uint64_t *Offset) {
+ auto HeaderError = [Offset = *Offset](Error E) {
+ return createStringError(errc::illegal_byte_sequence,
+ "parsing .debug_names header at 0x%" PRIx64 ": %s",
+ Offset, toString(std::move(E)).c_str());
+ };
+
+ DataExtractor::Cursor C(*Offset);
+ std::tie(UnitLength, Format) = AS.getInitialLength(C);
+
+ Version = AS.getU16(C);
+ AS.skip(C, 2); // padding
+ CompUnitCount = AS.getU32(C);
+ LocalTypeUnitCount = AS.getU32(C);
+ ForeignTypeUnitCount = AS.getU32(C);
+ BucketCount = AS.getU32(C);
+ NameCount = AS.getU32(C);
+ AbbrevTableSize = AS.getU32(C);
+ AugmentationStringSize = alignTo(AS.getU32(C), 4);
+
+ if (!C)
+ return HeaderError(C.takeError());
+
+ if (!AS.isValidOffsetForDataOfSize(C.tell(), AugmentationStringSize))
+ return HeaderError(createStringError(errc::illegal_byte_sequence,
+ "cannot read header augmentation"));
+ AugmentationString.resize(AugmentationStringSize);
+ AS.getU8(C, reinterpret_cast<uint8_t *>(AugmentationString.data()),
+ AugmentationStringSize);
+ *Offset = C.tell();
+ return C.takeError();
+}
+
+void DWARFDebugNames::Abbrev::dump(ScopedPrinter &W) const {
+ DictScope AbbrevScope(W, ("Abbreviation 0x" + Twine::utohexstr(Code)).str());
+ W.startLine() << formatv("Tag: {0}\n", Tag);
+
+ for (const auto &Attr : Attributes)
+ W.startLine() << formatv("{0}: {1}\n", Attr.Index, Attr.Form);
+}
+
+static constexpr DWARFDebugNames::AttributeEncoding sentinelAttrEnc() {
+ return {dwarf::Index(0), dwarf::Form(0)};
+}
+
+static bool isSentinel(const DWARFDebugNames::AttributeEncoding &AE) {
+ return AE == sentinelAttrEnc();
+}
+
+static DWARFDebugNames::Abbrev sentinelAbbrev() {
+ return DWARFDebugNames::Abbrev(0, dwarf::Tag(0), {});
+}
+
+static bool isSentinel(const DWARFDebugNames::Abbrev &Abbr) {
+ return Abbr.Code == 0;
+}
+
+DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getEmptyKey() {
+ return sentinelAbbrev();
+}
+
+DWARFDebugNames::Abbrev DWARFDebugNames::AbbrevMapInfo::getTombstoneKey() {
+ return DWARFDebugNames::Abbrev(~0, dwarf::Tag(0), {});
+}
+
+Expected<DWARFDebugNames::AttributeEncoding>
+DWARFDebugNames::NameIndex::extractAttributeEncoding(uint64_t *Offset) {
+ if (*Offset >= EntriesBase) {
+ return createStringError(errc::illegal_byte_sequence,
+ "Incorrectly terminated abbreviation table.");
+ }
+
+ uint32_t Index = Section.AccelSection.getULEB128(Offset);
+ uint32_t Form = Section.AccelSection.getULEB128(Offset);
+ return AttributeEncoding(dwarf::Index(Index), dwarf::Form(Form));
+}
+
+Expected<std::vector<DWARFDebugNames::AttributeEncoding>>
+DWARFDebugNames::NameIndex::extractAttributeEncodings(uint64_t *Offset) {
+ std::vector<AttributeEncoding> Result;
+ for (;;) {
+ auto AttrEncOr = extractAttributeEncoding(Offset);
+ if (!AttrEncOr)
+ return AttrEncOr.takeError();
+ if (isSentinel(*AttrEncOr))
+ return std::move(Result);
+
+ Result.emplace_back(*AttrEncOr);
+ }
+}
+
+Expected<DWARFDebugNames::Abbrev>
+DWARFDebugNames::NameIndex::extractAbbrev(uint64_t *Offset) {
+ if (*Offset >= EntriesBase) {
+ return createStringError(errc::illegal_byte_sequence,
+ "Incorrectly terminated abbreviation table.");
+ }
+
+ uint32_t Code = Section.AccelSection.getULEB128(Offset);
+ if (Code == 0)
+ return sentinelAbbrev();
+
+ uint32_t Tag = Section.AccelSection.getULEB128(Offset);
+ auto AttrEncOr = extractAttributeEncodings(Offset);
+ if (!AttrEncOr)
+ return AttrEncOr.takeError();
+ return Abbrev(Code, dwarf::Tag(Tag), std::move(*AttrEncOr));
+}
+
+Error DWARFDebugNames::NameIndex::extract() {
+ const DWARFDataExtractor &AS = Section.AccelSection;
+ uint64_t Offset = Base;
+ if (Error E = Hdr.extract(AS, &Offset))
+ return E;
+
+ const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format);
+ CUsBase = Offset;
+ Offset += Hdr.CompUnitCount * SectionOffsetSize;
+ Offset += Hdr.LocalTypeUnitCount * SectionOffsetSize;
+ Offset += Hdr.ForeignTypeUnitCount * 8;
+ BucketsBase = Offset;
+ Offset += Hdr.BucketCount * 4;
+ HashesBase = Offset;
+ if (Hdr.BucketCount > 0)
+ Offset += Hdr.NameCount * 4;
+ StringOffsetsBase = Offset;
+ Offset += Hdr.NameCount * SectionOffsetSize;
+ EntryOffsetsBase = Offset;
+ Offset += Hdr.NameCount * SectionOffsetSize;
+
+ if (!AS.isValidOffsetForDataOfSize(Offset, Hdr.AbbrevTableSize))
+ return createStringError(errc::illegal_byte_sequence,
+ "Section too small: cannot read abbreviations.");
+
+ EntriesBase = Offset + Hdr.AbbrevTableSize;
+
+ for (;;) {
+ auto AbbrevOr = extractAbbrev(&Offset);
+ if (!AbbrevOr)
+ return AbbrevOr.takeError();
+ if (isSentinel(*AbbrevOr))
+ return Error::success();
+
+ if (!Abbrevs.insert(std::move(*AbbrevOr)).second)
+ return createStringError(errc::invalid_argument,
+ "Duplicate abbreviation code.");
+ }
+}
+
+DWARFDebugNames::Entry::Entry(const NameIndex &NameIdx, const Abbrev &Abbr)
+ : NameIdx(&NameIdx), Abbr(&Abbr) {
+ // This merely creates form values. It is up to the caller
+ // (NameIndex::getEntry) to populate them.
+ Values.reserve(Abbr.Attributes.size());
+ for (const auto &Attr : Abbr.Attributes)
+ Values.emplace_back(Attr.Form);
+}
+
+Optional<DWARFFormValue>
+DWARFDebugNames::Entry::lookup(dwarf::Index Index) const {
+ assert(Abbr->Attributes.size() == Values.size());
+ for (auto Tuple : zip_first(Abbr->Attributes, Values)) {
+ if (std::get<0>(Tuple).Index == Index)
+ return std::get<1>(Tuple);
+ }
+ return None;
+}
+
+Optional<uint64_t> DWARFDebugNames::Entry::getDIEUnitOffset() const {
+ if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_die_offset))
+ return Off->getAsReferenceUVal();
+ return None;
+}
+
+Optional<uint64_t> DWARFDebugNames::Entry::getCUIndex() const {
+ if (Optional<DWARFFormValue> Off = lookup(dwarf::DW_IDX_compile_unit))
+ return Off->getAsUnsignedConstant();
+ // In a per-CU index, the entries without a DW_IDX_compile_unit attribute
+ // implicitly refer to the single CU.
+ if (NameIdx->getCUCount() == 1)
+ return 0;
+ return None;
+}
+
+Optional<uint64_t> DWARFDebugNames::Entry::getCUOffset() const {
+ Optional<uint64_t> Index = getCUIndex();
+ if (!Index || *Index >= NameIdx->getCUCount())
+ return None;
+ return NameIdx->getCUOffset(*Index);
+}
+
+void DWARFDebugNames::Entry::dump(ScopedPrinter &W) const {
+ W.printHex("Abbrev", Abbr->Code);
+ W.startLine() << formatv("Tag: {0}\n", Abbr->Tag);
+ assert(Abbr->Attributes.size() == Values.size());
+ for (auto Tuple : zip_first(Abbr->Attributes, Values)) {
+ W.startLine() << formatv("{0}: ", std::get<0>(Tuple).Index);
+ std::get<1>(Tuple).dump(W.getOStream());
+ W.getOStream() << '\n';
+ }
+}
+
+char DWARFDebugNames::SentinelError::ID;
+std::error_code DWARFDebugNames::SentinelError::convertToErrorCode() const {
+ return inconvertibleErrorCode();
+}
+
+uint64_t DWARFDebugNames::NameIndex::getCUOffset(uint32_t CU) const {
+ assert(CU < Hdr.CompUnitCount);
+ const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format);
+ uint64_t Offset = CUsBase + SectionOffsetSize * CU;
+ return Section.AccelSection.getRelocatedValue(SectionOffsetSize, &Offset);
+}
+
+uint64_t DWARFDebugNames::NameIndex::getLocalTUOffset(uint32_t TU) const {
+ assert(TU < Hdr.LocalTypeUnitCount);
+ const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format);
+ uint64_t Offset = CUsBase + SectionOffsetSize * (Hdr.CompUnitCount + TU);
+ return Section.AccelSection.getRelocatedValue(SectionOffsetSize, &Offset);
+}
+
+uint64_t DWARFDebugNames::NameIndex::getForeignTUSignature(uint32_t TU) const {
+ assert(TU < Hdr.ForeignTypeUnitCount);
+ const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format);
+ uint64_t Offset =
+ CUsBase +
+ SectionOffsetSize * (Hdr.CompUnitCount + Hdr.LocalTypeUnitCount) + 8 * TU;
+ return Section.AccelSection.getU64(&Offset);
+}
+
+Expected<DWARFDebugNames::Entry>
+DWARFDebugNames::NameIndex::getEntry(uint64_t *Offset) const {
+ const DWARFDataExtractor &AS = Section.AccelSection;
+ if (!AS.isValidOffset(*Offset))
+ return createStringError(errc::illegal_byte_sequence,
+ "Incorrectly terminated entry list.");
+
+ uint32_t AbbrevCode = AS.getULEB128(Offset);
+ if (AbbrevCode == 0)
+ return make_error<SentinelError>();
+
+ const auto AbbrevIt = Abbrevs.find_as(AbbrevCode);
+ if (AbbrevIt == Abbrevs.end())
+ return createStringError(errc::invalid_argument, "Invalid abbreviation.");
+
+ Entry E(*this, *AbbrevIt);
+
+ dwarf::FormParams FormParams = {Hdr.Version, 0, Hdr.Format};
+ for (auto &Value : E.Values) {
+ if (!Value.extractValue(AS, Offset, FormParams))
+ return createStringError(errc::io_error,
+ "Error extracting index attribute values.");
+ }
+ return std::move(E);
+}
+
+DWARFDebugNames::NameTableEntry
+DWARFDebugNames::NameIndex::getNameTableEntry(uint32_t Index) const {
+ assert(0 < Index && Index <= Hdr.NameCount);
+ const unsigned SectionOffsetSize = dwarf::getDwarfOffsetByteSize(Hdr.Format);
+ uint64_t StringOffsetOffset =
+ StringOffsetsBase + SectionOffsetSize * (Index - 1);
+ uint64_t EntryOffsetOffset =
+ EntryOffsetsBase + SectionOffsetSize * (Index - 1);
+ const DWARFDataExtractor &AS = Section.AccelSection;
+
+ uint64_t StringOffset =
+ AS.getRelocatedValue(SectionOffsetSize, &StringOffsetOffset);
+ uint64_t EntryOffset = AS.getUnsigned(&EntryOffsetOffset, SectionOffsetSize);
+ EntryOffset += EntriesBase;
+ return {Section.StringSection, Index, StringOffset, EntryOffset};
+}
+
+uint32_t
+DWARFDebugNames::NameIndex::getBucketArrayEntry(uint32_t Bucket) const {
+ assert(Bucket < Hdr.BucketCount);
+ uint64_t BucketOffset = BucketsBase + 4 * Bucket;
+ return Section.AccelSection.getU32(&BucketOffset);
+}
+
+uint32_t DWARFDebugNames::NameIndex::getHashArrayEntry(uint32_t Index) const {
+ assert(0 < Index && Index <= Hdr.NameCount);
+ uint64_t HashOffset = HashesBase + 4 * (Index - 1);
+ return Section.AccelSection.getU32(&HashOffset);
+}
+
+// Returns true if we should continue scanning for entries, false if this is the
+// last (sentinel) entry). In case of a parsing error we also return false, as
+// it's not possible to recover this entry list (but the other lists may still
+// parse OK).
+bool DWARFDebugNames::NameIndex::dumpEntry(ScopedPrinter &W,
+ uint64_t *Offset) const {
+ uint64_t EntryId = *Offset;
+ auto EntryOr = getEntry(Offset);
+ if (!EntryOr) {
+ handleAllErrors(EntryOr.takeError(), [](const SentinelError &) {},
+ [&W](const ErrorInfoBase &EI) { EI.log(W.startLine()); });
+ return false;
+ }
+
+ DictScope EntryScope(W, ("Entry @ 0x" + Twine::utohexstr(EntryId)).str());
+ EntryOr->dump(W);
+ return true;
+}
+
+void DWARFDebugNames::NameIndex::dumpName(ScopedPrinter &W,
+ const NameTableEntry &NTE,
+ Optional<uint32_t> Hash) const {
+ DictScope NameScope(W, ("Name " + Twine(NTE.getIndex())).str());
+ if (Hash)
+ W.printHex("Hash", *Hash);
+
+ W.startLine() << format("String: 0x%08" PRIx64, NTE.getStringOffset());
+ W.getOStream() << " \"" << NTE.getString() << "\"\n";
+
+ uint64_t EntryOffset = NTE.getEntryOffset();
+ while (dumpEntry(W, &EntryOffset))
+ /*empty*/;
+}
+
+void DWARFDebugNames::NameIndex::dumpCUs(ScopedPrinter &W) const {
+ ListScope CUScope(W, "Compilation Unit offsets");
+ for (uint32_t CU = 0; CU < Hdr.CompUnitCount; ++CU)
+ W.startLine() << format("CU[%u]: 0x%08" PRIx64 "\n", CU, getCUOffset(CU));
+}
+
+void DWARFDebugNames::NameIndex::dumpLocalTUs(ScopedPrinter &W) const {
+ if (Hdr.LocalTypeUnitCount == 0)
+ return;
+
+ ListScope TUScope(W, "Local Type Unit offsets");
+ for (uint32_t TU = 0; TU < Hdr.LocalTypeUnitCount; ++TU)
+ W.startLine() << format("LocalTU[%u]: 0x%08" PRIx64 "\n", TU,
+ getLocalTUOffset(TU));
+}
+
+void DWARFDebugNames::NameIndex::dumpForeignTUs(ScopedPrinter &W) const {
+ if (Hdr.ForeignTypeUnitCount == 0)
+ return;
+
+ ListScope TUScope(W, "Foreign Type Unit signatures");
+ for (uint32_t TU = 0; TU < Hdr.ForeignTypeUnitCount; ++TU) {
+ W.startLine() << format("ForeignTU[%u]: 0x%016" PRIx64 "\n", TU,
+ getForeignTUSignature(TU));
+ }
+}
+
+void DWARFDebugNames::NameIndex::dumpAbbreviations(ScopedPrinter &W) const {
+ ListScope AbbrevsScope(W, "Abbreviations");
+ for (const auto &Abbr : Abbrevs)
+ Abbr.dump(W);
+}
+
+void DWARFDebugNames::NameIndex::dumpBucket(ScopedPrinter &W,
+ uint32_t Bucket) const {
+ ListScope BucketScope(W, ("Bucket " + Twine(Bucket)).str());
+ uint32_t Index = getBucketArrayEntry(Bucket);
+ if (Index == 0) {
+ W.printString("EMPTY");
+ return;
+ }
+ if (Index > Hdr.NameCount) {
+ W.printString("Name index is invalid");
+ return;
+ }
+
+ for (; Index <= Hdr.NameCount; ++Index) {
+ uint32_t Hash = getHashArrayEntry(Index);
+ if (Hash % Hdr.BucketCount != Bucket)
+ break;
+
+ dumpName(W, getNameTableEntry(Index), Hash);
+ }
+}
+
+LLVM_DUMP_METHOD void DWARFDebugNames::NameIndex::dump(ScopedPrinter &W) const {
+ DictScope UnitScope(W, ("Name Index @ 0x" + Twine::utohexstr(Base)).str());
+ Hdr.dump(W);
+ dumpCUs(W);
+ dumpLocalTUs(W);
+ dumpForeignTUs(W);
+ dumpAbbreviations(W);
+
+ if (Hdr.BucketCount > 0) {
+ for (uint32_t Bucket = 0; Bucket < Hdr.BucketCount; ++Bucket)
+ dumpBucket(W, Bucket);
+ return;
+ }
+
+ W.startLine() << "Hash table not present\n";
+ for (const NameTableEntry &NTE : *this)
+ dumpName(W, NTE, None);
+}
+
+Error DWARFDebugNames::extract() {
+ uint64_t Offset = 0;
+ while (AccelSection.isValidOffset(Offset)) {
+ NameIndex Next(*this, Offset);
+ if (Error E = Next.extract())
+ return E;
+ Offset = Next.getNextUnitOffset();
+ NameIndices.push_back(std::move(Next));
+ }
+ return Error::success();
+}
+
+iterator_range<DWARFDebugNames::ValueIterator>
+DWARFDebugNames::NameIndex::equal_range(StringRef Key) const {
+ return make_range(ValueIterator(*this, Key), ValueIterator());
+}
+
+LLVM_DUMP_METHOD void DWARFDebugNames::dump(raw_ostream &OS) const {
+ ScopedPrinter W(OS);
+ for (const NameIndex &NI : NameIndices)
+ NI.dump(W);
+}
+
+Optional<uint64_t>
+DWARFDebugNames::ValueIterator::findEntryOffsetInCurrentIndex() {
+ const Header &Hdr = CurrentIndex->Hdr;
+ if (Hdr.BucketCount == 0) {
+ // No Hash Table, We need to search through all names in the Name Index.
+ for (const NameTableEntry &NTE : *CurrentIndex) {
+ if (NTE.getString() == Key)
+ return NTE.getEntryOffset();
+ }
+ return None;
+ }
+
+ // The Name Index has a Hash Table, so use that to speed up the search.
+ // Compute the Key Hash, if it has not been done already.
+ if (!Hash)
+ Hash = caseFoldingDjbHash(Key);
+ uint32_t Bucket = *Hash % Hdr.BucketCount;
+ uint32_t Index = CurrentIndex->getBucketArrayEntry(Bucket);
+ if (Index == 0)
+ return None; // Empty bucket
+
+ for (; Index <= Hdr.NameCount; ++Index) {
+ uint32_t Hash = CurrentIndex->getHashArrayEntry(Index);
+ if (Hash % Hdr.BucketCount != Bucket)
+ return None; // End of bucket
+
+ NameTableEntry NTE = CurrentIndex->getNameTableEntry(Index);
+ if (NTE.getString() == Key)
+ return NTE.getEntryOffset();
+ }
+ return None;
+}
+
+bool DWARFDebugNames::ValueIterator::getEntryAtCurrentOffset() {
+ auto EntryOr = CurrentIndex->getEntry(&DataOffset);
+ if (!EntryOr) {
+ consumeError(EntryOr.takeError());
+ return false;
+ }
+ CurrentEntry = std::move(*EntryOr);
+ return true;
+}
+
+bool DWARFDebugNames::ValueIterator::findInCurrentIndex() {
+ Optional<uint64_t> Offset = findEntryOffsetInCurrentIndex();
+ if (!Offset)
+ return false;
+ DataOffset = *Offset;
+ return getEntryAtCurrentOffset();
+}
+
+void DWARFDebugNames::ValueIterator::searchFromStartOfCurrentIndex() {
+ for (const NameIndex *End = CurrentIndex->Section.NameIndices.end();
+ CurrentIndex != End; ++CurrentIndex) {
+ if (findInCurrentIndex())
+ return;
+ }
+ setEnd();
+}
+
+void DWARFDebugNames::ValueIterator::next() {
+ assert(CurrentIndex && "Incrementing an end() iterator?");
+
+ // First try the next entry in the current Index.
+ if (getEntryAtCurrentOffset())
+ return;
+
+ // If we're a local iterator or we have reached the last Index, we're done.
+ if (IsLocal || CurrentIndex == &CurrentIndex->Section.NameIndices.back()) {
+ setEnd();
+ return;
+ }
+
+ // Otherwise, try the next index.
+ ++CurrentIndex;
+ searchFromStartOfCurrentIndex();
+}
+
+DWARFDebugNames::ValueIterator::ValueIterator(const DWARFDebugNames &AccelTable,
+ StringRef Key)
+ : CurrentIndex(AccelTable.NameIndices.begin()), IsLocal(false),
+ Key(std::string(Key)) {
+ searchFromStartOfCurrentIndex();
+}
+
+DWARFDebugNames::ValueIterator::ValueIterator(
+ const DWARFDebugNames::NameIndex &NI, StringRef Key)
+ : CurrentIndex(&NI), IsLocal(true), Key(std::string(Key)) {
+ if (!findInCurrentIndex())
+ setEnd();
+}
+
+iterator_range<DWARFDebugNames::ValueIterator>
+DWARFDebugNames::equal_range(StringRef Key) const {
+ if (NameIndices.empty())
+ return make_range(ValueIterator(), ValueIterator());
+ return make_range(ValueIterator(*this, Key), ValueIterator());
+}
+
+const DWARFDebugNames::NameIndex *
+DWARFDebugNames::getCUNameIndex(uint64_t CUOffset) {
+ if (CUToNameIndex.size() == 0 && NameIndices.size() > 0) {
+ for (const auto &NI : *this) {
+ for (uint32_t CU = 0; CU < NI.getCUCount(); ++CU)
+ CUToNameIndex.try_emplace(NI.getCUOffset(CU), &NI);
+ }
+ }
+ return CUToNameIndex.lookup(CUOffset);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFAddressRange.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFAddressRange.cpp
new file mode 100644
index 0000000000..25d2e852a7
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFAddressRange.cpp
@@ -0,0 +1,33 @@
+//===- DWARFDebugAranges.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/DWARF/DWARFAddressRange.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+void DWARFAddressRange::dump(raw_ostream &OS, uint32_t AddressSize,
+ DIDumpOptions DumpOpts,
+ const DWARFObject *Obj) const {
+
+ OS << (DumpOpts.DisplayRawContents ? " " : "[");
+ DWARFFormValue::dumpAddress(OS, AddressSize, LowPC);
+ OS << ", ";
+ DWARFFormValue::dumpAddress(OS, AddressSize, HighPC);
+ OS << (DumpOpts.DisplayRawContents ? "" : ")");
+
+ if (Obj)
+ DWARFFormValue::dumpAddressSection(*Obj, OS, DumpOpts, SectionIndex);
+}
+
+raw_ostream &llvm::operator<<(raw_ostream &OS, const DWARFAddressRange &R) {
+ R.dump(OS, /* AddressSize */ 8);
+ return OS;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
new file mode 100644
index 0000000000..d68ecd4f8a
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFCompileUnit.cpp
@@ -0,0 +1,44 @@
+//===-- DWARFCompileUnit.cpp ----------------------------------------------===//
+//
+// 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/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+void DWARFCompileUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
+ if (DumpOpts.SummarizeTypes)
+ return;
+ int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(getFormat());
+ OS << format("0x%08" PRIx64, getOffset()) << ": Compile Unit:"
+ << " length = " << format("0x%0*" PRIx64, OffsetDumpWidth, getLength())
+ << ", format = " << dwarf::FormatString(getFormat())
+ << ", version = " << format("0x%04x", getVersion());
+ if (getVersion() >= 5)
+ OS << ", unit_type = " << dwarf::UnitTypeString(getUnitType());
+ OS << ", abbr_offset = " << format("0x%04" PRIx64, getAbbrOffset());
+ if (!getAbbreviations())
+ OS << " (invalid)";
+ OS << ", addr_size = " << format("0x%02x", getAddressByteSize());
+ if (getVersion() >= 5 && (getUnitType() == dwarf::DW_UT_skeleton ||
+ getUnitType() == dwarf::DW_UT_split_compile))
+ OS << ", DWO_id = " << format("0x%016" PRIx64, *getDWOId());
+ OS << " (next unit at " << format("0x%08" PRIx64, getNextUnitOffset())
+ << ")\n";
+
+ if (DWARFDie CUDie = getUnitDIE(false))
+ CUDie.dump(OS, 0, DumpOpts);
+ else
+ OS << "<compile unit can't be parsed!>\n\n";
+}
+
+// VTable anchor.
+DWARFCompileUnit::~DWARFCompileUnit() = default;
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFContext.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFContext.cpp
new file mode 100644
index 0000000000..ef50ad5365
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -0,0 +1,2046 @@
+//===- DWARFContext.cpp ---------------------------------------------------===//
+//
+// 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/DWARF/DWARFContext.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFAcceleratorTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAddr.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAranges.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugFrame.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLoc.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugMacro.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugPubTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFGdbIndex.h"
+#include "llvm/DebugInfo/DWARF/DWARFSection.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
+#include "llvm/DebugInfo/DWARF/DWARFVerifier.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/MC/TargetRegistry.h"
+#include "llvm/Object/Decompressor.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/RelocationResolver.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cstdint>
+#include <deque>
+#include <map>
+#include <string>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+using namespace object;
+
+#define DEBUG_TYPE "dwarf"
+
+using DWARFLineTable = DWARFDebugLine::LineTable;
+using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind;
+using FunctionNameKind = DILineInfoSpecifier::FunctionNameKind;
+
+DWARFContext::DWARFContext(std::unique_ptr<const DWARFObject> DObj,
+ std::string DWPName,
+ std::function<void(Error)> RecoverableErrorHandler,
+ std::function<void(Error)> WarningHandler)
+ : DIContext(CK_DWARF), DWPName(std::move(DWPName)),
+ RecoverableErrorHandler(RecoverableErrorHandler),
+ WarningHandler(WarningHandler), DObj(std::move(DObj)) {}
+
+DWARFContext::~DWARFContext() = default;
+
+/// Dump the UUID load command.
+static void dumpUUID(raw_ostream &OS, const ObjectFile &Obj) {
+ auto *MachO = dyn_cast<MachOObjectFile>(&Obj);
+ if (!MachO)
+ return;
+ for (auto LC : MachO->load_commands()) {
+ raw_ostream::uuid_t UUID;
+ if (LC.C.cmd == MachO::LC_UUID) {
+ if (LC.C.cmdsize < sizeof(UUID) + sizeof(LC.C)) {
+ OS << "error: UUID load command is too short.\n";
+ return;
+ }
+ OS << "UUID: ";
+ memcpy(&UUID, LC.Ptr+sizeof(LC.C), sizeof(UUID));
+ OS.write_uuid(UUID);
+ Triple T = MachO->getArchTriple();
+ OS << " (" << T.getArchName() << ')';
+ OS << ' ' << MachO->getFileName() << '\n';
+ }
+ }
+}
+
+using ContributionCollection =
+ std::vector<Optional<StrOffsetsContributionDescriptor>>;
+
+// Collect all the contributions to the string offsets table from all units,
+// sort them by their starting offsets and remove duplicates.
+static ContributionCollection
+collectContributionData(DWARFContext::unit_iterator_range Units) {
+ ContributionCollection Contributions;
+ for (const auto &U : Units)
+ if (const auto &C = U->getStringOffsetsTableContribution())
+ Contributions.push_back(C);
+ // Sort the contributions so that any invalid ones are placed at
+ // the start of the contributions vector. This way they are reported
+ // first.
+ llvm::sort(Contributions,
+ [](const Optional<StrOffsetsContributionDescriptor> &L,
+ const Optional<StrOffsetsContributionDescriptor> &R) {
+ if (L && R)
+ return L->Base < R->Base;
+ return R.hasValue();
+ });
+
+ // Uniquify contributions, as it is possible that units (specifically
+ // type units in dwo or dwp files) share contributions. We don't want
+ // to report them more than once.
+ Contributions.erase(
+ std::unique(Contributions.begin(), Contributions.end(),
+ [](const Optional<StrOffsetsContributionDescriptor> &L,
+ const Optional<StrOffsetsContributionDescriptor> &R) {
+ if (L && R)
+ return L->Base == R->Base && L->Size == R->Size;
+ return false;
+ }),
+ Contributions.end());
+ return Contributions;
+}
+
+// Dump a DWARF string offsets section. This may be a DWARF v5 formatted
+// string offsets section, where each compile or type unit contributes a
+// number of entries (string offsets), with each contribution preceded by
+// a header containing size and version number. Alternatively, it may be a
+// monolithic series of string offsets, as generated by the pre-DWARF v5
+// implementation of split DWARF; however, in that case we still need to
+// collect contributions of units because the size of the offsets (4 or 8
+// bytes) depends on the format of the referencing unit (DWARF32 or DWARF64).
+static void dumpStringOffsetsSection(raw_ostream &OS, DIDumpOptions DumpOpts,
+ StringRef SectionName,
+ const DWARFObject &Obj,
+ const DWARFSection &StringOffsetsSection,
+ StringRef StringSection,
+ DWARFContext::unit_iterator_range Units,
+ bool LittleEndian) {
+ auto Contributions = collectContributionData(Units);
+ DWARFDataExtractor StrOffsetExt(Obj, StringOffsetsSection, LittleEndian, 0);
+ DataExtractor StrData(StringSection, LittleEndian, 0);
+ uint64_t SectionSize = StringOffsetsSection.Data.size();
+ uint64_t Offset = 0;
+ for (auto &Contribution : Contributions) {
+ // Report an ill-formed contribution.
+ if (!Contribution) {
+ OS << "error: invalid contribution to string offsets table in section ."
+ << SectionName << ".\n";
+ return;
+ }
+
+ dwarf::DwarfFormat Format = Contribution->getFormat();
+ int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format);
+ uint16_t Version = Contribution->getVersion();
+ uint64_t ContributionHeader = Contribution->Base;
+ // In DWARF v5 there is a contribution header that immediately precedes
+ // the string offsets base (the location we have previously retrieved from
+ // the CU DIE's DW_AT_str_offsets attribute). The header is located either
+ // 8 or 16 bytes before the base, depending on the contribution's format.
+ if (Version >= 5)
+ ContributionHeader -= Format == DWARF32 ? 8 : 16;
+
+ // Detect overlapping contributions.
+ if (Offset > ContributionHeader) {
+ DumpOpts.RecoverableErrorHandler(createStringError(
+ errc::invalid_argument,
+ "overlapping contributions to string offsets table in section .%s.",
+ SectionName.data()));
+ }
+ // Report a gap in the table.
+ if (Offset < ContributionHeader) {
+ OS << format("0x%8.8" PRIx64 ": Gap, length = ", Offset);
+ OS << (ContributionHeader - Offset) << "\n";
+ }
+ OS << format("0x%8.8" PRIx64 ": ", ContributionHeader);
+ // In DWARF v5 the contribution size in the descriptor does not equal
+ // the originally encoded length (it does not contain the length of the
+ // version field and the padding, a total of 4 bytes). Add them back in
+ // for reporting.
+ OS << "Contribution size = " << (Contribution->Size + (Version < 5 ? 0 : 4))
+ << ", Format = " << dwarf::FormatString(Format)
+ << ", Version = " << Version << "\n";
+
+ Offset = Contribution->Base;
+ unsigned EntrySize = Contribution->getDwarfOffsetByteSize();
+ while (Offset - Contribution->Base < Contribution->Size) {
+ OS << format("0x%8.8" PRIx64 ": ", Offset);
+ uint64_t StringOffset =
+ StrOffsetExt.getRelocatedValue(EntrySize, &Offset);
+ OS << format("%0*" PRIx64 " ", OffsetDumpWidth, StringOffset);
+ const char *S = StrData.getCStr(&StringOffset);
+ if (S)
+ OS << format("\"%s\"", S);
+ OS << "\n";
+ }
+ }
+ // Report a gap at the end of the table.
+ if (Offset < SectionSize) {
+ OS << format("0x%8.8" PRIx64 ": Gap, length = ", Offset);
+ OS << (SectionSize - Offset) << "\n";
+ }
+}
+
+// Dump the .debug_addr section.
+static void dumpAddrSection(raw_ostream &OS, DWARFDataExtractor &AddrData,
+ DIDumpOptions DumpOpts, uint16_t Version,
+ uint8_t AddrSize) {
+ uint64_t Offset = 0;
+ while (AddrData.isValidOffset(Offset)) {
+ DWARFDebugAddrTable AddrTable;
+ uint64_t TableOffset = Offset;
+ if (Error Err = AddrTable.extract(AddrData, &Offset, Version, AddrSize,
+ DumpOpts.WarningHandler)) {
+ DumpOpts.RecoverableErrorHandler(std::move(Err));
+ // Keep going after an error, if we can, assuming that the length field
+ // could be read. If it couldn't, stop reading the section.
+ if (auto TableLength = AddrTable.getFullLength()) {
+ Offset = TableOffset + *TableLength;
+ continue;
+ }
+ break;
+ }
+ AddrTable.dump(OS, DumpOpts);
+ }
+}
+
+// Dump the .debug_rnglists or .debug_rnglists.dwo section (DWARF v5).
+static void dumpRnglistsSection(
+ raw_ostream &OS, DWARFDataExtractor &rnglistData,
+ llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)>
+ LookupPooledAddress,
+ DIDumpOptions DumpOpts) {
+ uint64_t Offset = 0;
+ while (rnglistData.isValidOffset(Offset)) {
+ llvm::DWARFDebugRnglistTable Rnglists;
+ uint64_t TableOffset = Offset;
+ if (Error Err = Rnglists.extract(rnglistData, &Offset)) {
+ DumpOpts.RecoverableErrorHandler(std::move(Err));
+ uint64_t Length = Rnglists.length();
+ // Keep going after an error, if we can, assuming that the length field
+ // could be read. If it couldn't, stop reading the section.
+ if (Length == 0)
+ break;
+ Offset = TableOffset + Length;
+ } else {
+ Rnglists.dump(rnglistData, OS, LookupPooledAddress, DumpOpts);
+ }
+ }
+}
+
+std::unique_ptr<DWARFDebugMacro>
+DWARFContext::parseMacroOrMacinfo(MacroSecType SectionType) {
+ auto Macro = std::make_unique<DWARFDebugMacro>();
+ auto ParseAndDump = [&](DWARFDataExtractor &Data, bool IsMacro) {
+ if (Error Err = IsMacro ? Macro->parseMacro(SectionType == MacroSection
+ ? compile_units()
+ : dwo_compile_units(),
+ SectionType == MacroSection
+ ? getStringExtractor()
+ : getStringDWOExtractor(),
+ Data)
+ : Macro->parseMacinfo(Data)) {
+ RecoverableErrorHandler(std::move(Err));
+ Macro = nullptr;
+ }
+ };
+ switch (SectionType) {
+ case MacinfoSection: {
+ DWARFDataExtractor Data(DObj->getMacinfoSection(), isLittleEndian(), 0);
+ ParseAndDump(Data, /*IsMacro=*/false);
+ break;
+ }
+ case MacinfoDwoSection: {
+ DWARFDataExtractor Data(DObj->getMacinfoDWOSection(), isLittleEndian(), 0);
+ ParseAndDump(Data, /*IsMacro=*/false);
+ break;
+ }
+ case MacroSection: {
+ DWARFDataExtractor Data(*DObj, DObj->getMacroSection(), isLittleEndian(),
+ 0);
+ ParseAndDump(Data, /*IsMacro=*/true);
+ break;
+ }
+ case MacroDwoSection: {
+ DWARFDataExtractor Data(DObj->getMacroDWOSection(), isLittleEndian(), 0);
+ ParseAndDump(Data, /*IsMacro=*/true);
+ break;
+ }
+ }
+ return Macro;
+}
+
+static void dumpLoclistsSection(raw_ostream &OS, DIDumpOptions DumpOpts,
+ DWARFDataExtractor Data,
+ const MCRegisterInfo *MRI,
+ const DWARFObject &Obj,
+ Optional<uint64_t> DumpOffset) {
+ uint64_t Offset = 0;
+
+ while (Data.isValidOffset(Offset)) {
+ DWARFListTableHeader Header(".debug_loclists", "locations");
+ if (Error E = Header.extract(Data, &Offset)) {
+ DumpOpts.RecoverableErrorHandler(std::move(E));
+ return;
+ }
+
+ Header.dump(Data, OS, DumpOpts);
+
+ uint64_t EndOffset = Header.length() + Header.getHeaderOffset();
+ Data.setAddressSize(Header.getAddrSize());
+ DWARFDebugLoclists Loc(Data, Header.getVersion());
+ if (DumpOffset) {
+ if (DumpOffset >= Offset && DumpOffset < EndOffset) {
+ Offset = *DumpOffset;
+ Loc.dumpLocationList(&Offset, OS, /*BaseAddr=*/None, MRI, Obj, nullptr,
+ DumpOpts, /*Indent=*/0);
+ OS << "\n";
+ return;
+ }
+ } else {
+ Loc.dumpRange(Offset, EndOffset - Offset, OS, MRI, Obj, DumpOpts);
+ }
+ Offset = EndOffset;
+ }
+}
+
+static void dumpPubTableSection(raw_ostream &OS, DIDumpOptions DumpOpts,
+ DWARFDataExtractor Data, bool GnuStyle) {
+ DWARFDebugPubTable Table;
+ Table.extract(Data, GnuStyle, DumpOpts.RecoverableErrorHandler);
+ Table.dump(OS);
+}
+
+void DWARFContext::dump(
+ raw_ostream &OS, DIDumpOptions DumpOpts,
+ std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets) {
+ uint64_t DumpType = DumpOpts.DumpType;
+
+ StringRef Extension = sys::path::extension(DObj->getFileName());
+ bool IsDWO = (Extension == ".dwo") || (Extension == ".dwp");
+
+ // Print UUID header.
+ const auto *ObjFile = DObj->getFile();
+ if (DumpType & DIDT_UUID)
+ dumpUUID(OS, *ObjFile);
+
+ // Print a header for each explicitly-requested section.
+ // Otherwise just print one for non-empty sections.
+ // Only print empty .dwo section headers when dumping a .dwo file.
+ bool Explicit = DumpType != DIDT_All && !IsDWO;
+ bool ExplicitDWO = Explicit && IsDWO;
+ auto shouldDump = [&](bool Explicit, const char *Name, unsigned ID,
+ StringRef Section) -> Optional<uint64_t> * {
+ unsigned Mask = 1U << ID;
+ bool Should = (DumpType & Mask) && (Explicit || !Section.empty());
+ if (!Should)
+ return nullptr;
+ OS << "\n" << Name << " contents:\n";
+ return &DumpOffsets[ID];
+ };
+
+ // Dump individual sections.
+ if (shouldDump(Explicit, ".debug_abbrev", DIDT_ID_DebugAbbrev,
+ DObj->getAbbrevSection()))
+ getDebugAbbrev()->dump(OS);
+ if (shouldDump(ExplicitDWO, ".debug_abbrev.dwo", DIDT_ID_DebugAbbrev,
+ DObj->getAbbrevDWOSection()))
+ getDebugAbbrevDWO()->dump(OS);
+
+ auto dumpDebugInfo = [&](const char *Name, unit_iterator_range Units) {
+ OS << '\n' << Name << " contents:\n";
+ if (auto DumpOffset = DumpOffsets[DIDT_ID_DebugInfo])
+ for (const auto &U : Units)
+ U->getDIEForOffset(DumpOffset.getValue())
+ .dump(OS, 0, DumpOpts.noImplicitRecursion());
+ else
+ for (const auto &U : Units)
+ U->dump(OS, DumpOpts);
+ };
+ if ((DumpType & DIDT_DebugInfo)) {
+ if (Explicit || getNumCompileUnits())
+ dumpDebugInfo(".debug_info", info_section_units());
+ if (ExplicitDWO || getNumDWOCompileUnits())
+ dumpDebugInfo(".debug_info.dwo", dwo_info_section_units());
+ }
+
+ auto dumpDebugType = [&](const char *Name, unit_iterator_range Units) {
+ OS << '\n' << Name << " contents:\n";
+ for (const auto &U : Units)
+ if (auto DumpOffset = DumpOffsets[DIDT_ID_DebugTypes])
+ U->getDIEForOffset(*DumpOffset)
+ .dump(OS, 0, DumpOpts.noImplicitRecursion());
+ else
+ U->dump(OS, DumpOpts);
+ };
+ if ((DumpType & DIDT_DebugTypes)) {
+ if (Explicit || getNumTypeUnits())
+ dumpDebugType(".debug_types", types_section_units());
+ if (ExplicitDWO || getNumDWOTypeUnits())
+ dumpDebugType(".debug_types.dwo", dwo_types_section_units());
+ }
+
+ DIDumpOptions LLDumpOpts = DumpOpts;
+ if (LLDumpOpts.Verbose)
+ LLDumpOpts.DisplayRawContents = true;
+
+ if (const auto *Off = shouldDump(Explicit, ".debug_loc", DIDT_ID_DebugLoc,
+ DObj->getLocSection().Data)) {
+ getDebugLoc()->dump(OS, getRegisterInfo(), *DObj, LLDumpOpts, *Off);
+ }
+ if (const auto *Off =
+ shouldDump(Explicit, ".debug_loclists", DIDT_ID_DebugLoclists,
+ DObj->getLoclistsSection().Data)) {
+ DWARFDataExtractor Data(*DObj, DObj->getLoclistsSection(), isLittleEndian(),
+ 0);
+ dumpLoclistsSection(OS, LLDumpOpts, Data, getRegisterInfo(), *DObj, *Off);
+ }
+ if (const auto *Off =
+ shouldDump(ExplicitDWO, ".debug_loclists.dwo", DIDT_ID_DebugLoclists,
+ DObj->getLoclistsDWOSection().Data)) {
+ DWARFDataExtractor Data(*DObj, DObj->getLoclistsDWOSection(),
+ isLittleEndian(), 0);
+ dumpLoclistsSection(OS, LLDumpOpts, Data, getRegisterInfo(), *DObj, *Off);
+ }
+
+ if (const auto *Off =
+ shouldDump(ExplicitDWO, ".debug_loc.dwo", DIDT_ID_DebugLoc,
+ DObj->getLocDWOSection().Data)) {
+ DWARFDataExtractor Data(*DObj, DObj->getLocDWOSection(), isLittleEndian(),
+ 4);
+ DWARFDebugLoclists Loc(Data, /*Version=*/4);
+ if (*Off) {
+ uint64_t Offset = **Off;
+ Loc.dumpLocationList(&Offset, OS,
+ /*BaseAddr=*/None, getRegisterInfo(), *DObj, nullptr,
+ LLDumpOpts, /*Indent=*/0);
+ OS << "\n";
+ } else {
+ Loc.dumpRange(0, Data.getData().size(), OS, getRegisterInfo(), *DObj,
+ LLDumpOpts);
+ }
+ }
+
+ if (const Optional<uint64_t> *Off =
+ shouldDump(Explicit, ".debug_frame", DIDT_ID_DebugFrame,
+ DObj->getFrameSection().Data)) {
+ if (Expected<const DWARFDebugFrame *> DF = getDebugFrame())
+ (*DF)->dump(OS, DumpOpts, getRegisterInfo(), *Off);
+ else
+ RecoverableErrorHandler(DF.takeError());
+ }
+
+ if (const Optional<uint64_t> *Off =
+ shouldDump(Explicit, ".eh_frame", DIDT_ID_DebugFrame,
+ DObj->getEHFrameSection().Data)) {
+ if (Expected<const DWARFDebugFrame *> DF = getEHFrame())
+ (*DF)->dump(OS, DumpOpts, getRegisterInfo(), *Off);
+ else
+ RecoverableErrorHandler(DF.takeError());
+ }
+
+ if (shouldDump(Explicit, ".debug_macro", DIDT_ID_DebugMacro,
+ DObj->getMacroSection().Data)) {
+ if (auto Macro = getDebugMacro())
+ Macro->dump(OS);
+ }
+
+ if (shouldDump(Explicit, ".debug_macro.dwo", DIDT_ID_DebugMacro,
+ DObj->getMacroDWOSection())) {
+ if (auto MacroDWO = getDebugMacroDWO())
+ MacroDWO->dump(OS);
+ }
+
+ if (shouldDump(Explicit, ".debug_macinfo", DIDT_ID_DebugMacro,
+ DObj->getMacinfoSection())) {
+ if (auto Macinfo = getDebugMacinfo())
+ Macinfo->dump(OS);
+ }
+
+ if (shouldDump(Explicit, ".debug_macinfo.dwo", DIDT_ID_DebugMacro,
+ DObj->getMacinfoDWOSection())) {
+ if (auto MacinfoDWO = getDebugMacinfoDWO())
+ MacinfoDWO->dump(OS);
+ }
+
+ if (shouldDump(Explicit, ".debug_aranges", DIDT_ID_DebugAranges,
+ DObj->getArangesSection())) {
+ uint64_t offset = 0;
+ DWARFDataExtractor arangesData(DObj->getArangesSection(), isLittleEndian(),
+ 0);
+ DWARFDebugArangeSet set;
+ while (arangesData.isValidOffset(offset)) {
+ if (Error E =
+ set.extract(arangesData, &offset, DumpOpts.WarningHandler)) {
+ RecoverableErrorHandler(std::move(E));
+ break;
+ }
+ set.dump(OS);
+ }
+ }
+
+ auto DumpLineSection = [&](DWARFDebugLine::SectionParser Parser,
+ DIDumpOptions DumpOpts,
+ Optional<uint64_t> DumpOffset) {
+ while (!Parser.done()) {
+ if (DumpOffset && Parser.getOffset() != *DumpOffset) {
+ Parser.skip(DumpOpts.WarningHandler, DumpOpts.WarningHandler);
+ continue;
+ }
+ OS << "debug_line[" << format("0x%8.8" PRIx64, Parser.getOffset())
+ << "]\n";
+ Parser.parseNext(DumpOpts.WarningHandler, DumpOpts.WarningHandler, &OS,
+ DumpOpts.Verbose);
+ }
+ };
+
+ auto DumpStrSection = [&](StringRef Section) {
+ DataExtractor StrData(Section, isLittleEndian(), 0);
+ uint64_t Offset = 0;
+ uint64_t StrOffset = 0;
+ while (StrData.isValidOffset(Offset)) {
+ Error Err = Error::success();
+ const char *CStr = StrData.getCStr(&Offset, &Err);
+ if (Err) {
+ DumpOpts.WarningHandler(std::move(Err));
+ return;
+ }
+ OS << format("0x%8.8" PRIx64 ": \"", StrOffset);
+ OS.write_escaped(CStr);
+ OS << "\"\n";
+ StrOffset = Offset;
+ }
+ };
+
+ if (const auto *Off = shouldDump(Explicit, ".debug_line", DIDT_ID_DebugLine,
+ DObj->getLineSection().Data)) {
+ DWARFDataExtractor LineData(*DObj, DObj->getLineSection(), isLittleEndian(),
+ 0);
+ DWARFDebugLine::SectionParser Parser(LineData, *this, normal_units());
+ DumpLineSection(Parser, DumpOpts, *Off);
+ }
+
+ if (const auto *Off =
+ shouldDump(ExplicitDWO, ".debug_line.dwo", DIDT_ID_DebugLine,
+ DObj->getLineDWOSection().Data)) {
+ DWARFDataExtractor LineData(*DObj, DObj->getLineDWOSection(),
+ isLittleEndian(), 0);
+ DWARFDebugLine::SectionParser Parser(LineData, *this, dwo_units());
+ DumpLineSection(Parser, DumpOpts, *Off);
+ }
+
+ if (shouldDump(Explicit, ".debug_cu_index", DIDT_ID_DebugCUIndex,
+ DObj->getCUIndexSection())) {
+ getCUIndex().dump(OS);
+ }
+
+ if (shouldDump(Explicit, ".debug_tu_index", DIDT_ID_DebugTUIndex,
+ DObj->getTUIndexSection())) {
+ getTUIndex().dump(OS);
+ }
+
+ if (shouldDump(Explicit, ".debug_str", DIDT_ID_DebugStr,
+ DObj->getStrSection()))
+ DumpStrSection(DObj->getStrSection());
+
+ if (shouldDump(ExplicitDWO, ".debug_str.dwo", DIDT_ID_DebugStr,
+ DObj->getStrDWOSection()))
+ DumpStrSection(DObj->getStrDWOSection());
+
+ if (shouldDump(Explicit, ".debug_line_str", DIDT_ID_DebugLineStr,
+ DObj->getLineStrSection()))
+ DumpStrSection(DObj->getLineStrSection());
+
+ if (shouldDump(Explicit, ".debug_addr", DIDT_ID_DebugAddr,
+ DObj->getAddrSection().Data)) {
+ DWARFDataExtractor AddrData(*DObj, DObj->getAddrSection(),
+ isLittleEndian(), 0);
+ dumpAddrSection(OS, AddrData, DumpOpts, getMaxVersion(), getCUAddrSize());
+ }
+
+ if (shouldDump(Explicit, ".debug_ranges", DIDT_ID_DebugRanges,
+ DObj->getRangesSection().Data)) {
+ uint8_t savedAddressByteSize = getCUAddrSize();
+ DWARFDataExtractor rangesData(*DObj, DObj->getRangesSection(),
+ isLittleEndian(), savedAddressByteSize);
+ uint64_t offset = 0;
+ DWARFDebugRangeList rangeList;
+ while (rangesData.isValidOffset(offset)) {
+ if (Error E = rangeList.extract(rangesData, &offset)) {
+ DumpOpts.RecoverableErrorHandler(std::move(E));
+ break;
+ }
+ rangeList.dump(OS);
+ }
+ }
+
+ auto LookupPooledAddress = [&](uint32_t Index) -> Optional<SectionedAddress> {
+ const auto &CUs = compile_units();
+ auto I = CUs.begin();
+ if (I == CUs.end())
+ return None;
+ return (*I)->getAddrOffsetSectionItem(Index);
+ };
+
+ if (shouldDump(Explicit, ".debug_rnglists", DIDT_ID_DebugRnglists,
+ DObj->getRnglistsSection().Data)) {
+ DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsSection(),
+ isLittleEndian(), 0);
+ dumpRnglistsSection(OS, RnglistData, LookupPooledAddress, DumpOpts);
+ }
+
+ if (shouldDump(ExplicitDWO, ".debug_rnglists.dwo", DIDT_ID_DebugRnglists,
+ DObj->getRnglistsDWOSection().Data)) {
+ DWARFDataExtractor RnglistData(*DObj, DObj->getRnglistsDWOSection(),
+ isLittleEndian(), 0);
+ dumpRnglistsSection(OS, RnglistData, LookupPooledAddress, DumpOpts);
+ }
+
+ if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames,
+ DObj->getPubnamesSection().Data)) {
+ DWARFDataExtractor PubTableData(*DObj, DObj->getPubnamesSection(),
+ isLittleEndian(), 0);
+ dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/false);
+ }
+
+ if (shouldDump(Explicit, ".debug_pubtypes", DIDT_ID_DebugPubtypes,
+ DObj->getPubtypesSection().Data)) {
+ DWARFDataExtractor PubTableData(*DObj, DObj->getPubtypesSection(),
+ isLittleEndian(), 0);
+ dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/false);
+ }
+
+ if (shouldDump(Explicit, ".debug_gnu_pubnames", DIDT_ID_DebugGnuPubnames,
+ DObj->getGnuPubnamesSection().Data)) {
+ DWARFDataExtractor PubTableData(*DObj, DObj->getGnuPubnamesSection(),
+ isLittleEndian(), 0);
+ dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/true);
+ }
+
+ if (shouldDump(Explicit, ".debug_gnu_pubtypes", DIDT_ID_DebugGnuPubtypes,
+ DObj->getGnuPubtypesSection().Data)) {
+ DWARFDataExtractor PubTableData(*DObj, DObj->getGnuPubtypesSection(),
+ isLittleEndian(), 0);
+ dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/true);
+ }
+
+ if (shouldDump(Explicit, ".debug_str_offsets", DIDT_ID_DebugStrOffsets,
+ DObj->getStrOffsetsSection().Data))
+ dumpStringOffsetsSection(
+ OS, DumpOpts, "debug_str_offsets", *DObj, DObj->getStrOffsetsSection(),
+ DObj->getStrSection(), normal_units(), isLittleEndian());
+ if (shouldDump(ExplicitDWO, ".debug_str_offsets.dwo", DIDT_ID_DebugStrOffsets,
+ DObj->getStrOffsetsDWOSection().Data))
+ dumpStringOffsetsSection(OS, DumpOpts, "debug_str_offsets.dwo", *DObj,
+ DObj->getStrOffsetsDWOSection(),
+ DObj->getStrDWOSection(), dwo_units(),
+ isLittleEndian());
+
+ if (shouldDump(Explicit, ".gdb_index", DIDT_ID_GdbIndex,
+ DObj->getGdbIndexSection())) {
+ getGdbIndex().dump(OS);
+ }
+
+ if (shouldDump(Explicit, ".apple_names", DIDT_ID_AppleNames,
+ DObj->getAppleNamesSection().Data))
+ getAppleNames().dump(OS);
+
+ if (shouldDump(Explicit, ".apple_types", DIDT_ID_AppleTypes,
+ DObj->getAppleTypesSection().Data))
+ getAppleTypes().dump(OS);
+
+ if (shouldDump(Explicit, ".apple_namespaces", DIDT_ID_AppleNamespaces,
+ DObj->getAppleNamespacesSection().Data))
+ getAppleNamespaces().dump(OS);
+
+ if (shouldDump(Explicit, ".apple_objc", DIDT_ID_AppleObjC,
+ DObj->getAppleObjCSection().Data))
+ getAppleObjC().dump(OS);
+ if (shouldDump(Explicit, ".debug_names", DIDT_ID_DebugNames,
+ DObj->getNamesSection().Data))
+ getDebugNames().dump(OS);
+}
+
+DWARFTypeUnit *DWARFContext::getTypeUnitForHash(uint16_t Version, uint64_t Hash,
+ bool IsDWO) {
+ parseDWOUnits(LazyParse);
+
+ if (const auto &TUI = getTUIndex()) {
+ if (const auto *R = TUI.getFromHash(Hash))
+ return dyn_cast_or_null<DWARFTypeUnit>(
+ DWOUnits.getUnitForIndexEntry(*R));
+ return nullptr;
+ }
+
+ struct UnitContainers {
+ const DWARFUnitVector &Units;
+ Optional<DenseMap<uint64_t, DWARFTypeUnit *>> &Map;
+ };
+ UnitContainers Units = IsDWO ? UnitContainers{DWOUnits, DWOTypeUnits}
+ : UnitContainers{NormalUnits, NormalTypeUnits};
+ if (!Units.Map) {
+ Units.Map.emplace();
+ for (const auto &U : IsDWO ? dwo_units() : normal_units()) {
+ if (DWARFTypeUnit *TU = dyn_cast<DWARFTypeUnit>(U.get()))
+ (*Units.Map)[TU->getTypeHash()] = TU;
+ }
+ }
+
+ return (*Units.Map)[Hash];
+}
+
+DWARFCompileUnit *DWARFContext::getDWOCompileUnitForHash(uint64_t Hash) {
+ parseDWOUnits(LazyParse);
+
+ if (const auto &CUI = getCUIndex()) {
+ if (const auto *R = CUI.getFromHash(Hash))
+ return dyn_cast_or_null<DWARFCompileUnit>(
+ DWOUnits.getUnitForIndexEntry(*R));
+ return nullptr;
+ }
+
+ // If there's no index, just search through the CUs in the DWO - there's
+ // probably only one unless this is something like LTO - though an in-process
+ // built/cached lookup table could be used in that case to improve repeated
+ // lookups of different CUs in the DWO.
+ for (const auto &DWOCU : dwo_compile_units()) {
+ // Might not have parsed DWO ID yet.
+ if (!DWOCU->getDWOId()) {
+ if (Optional<uint64_t> DWOId =
+ toUnsigned(DWOCU->getUnitDIE().find(DW_AT_GNU_dwo_id)))
+ DWOCU->setDWOId(*DWOId);
+ else
+ // No DWO ID?
+ continue;
+ }
+ if (DWOCU->getDWOId() == Hash)
+ return dyn_cast<DWARFCompileUnit>(DWOCU.get());
+ }
+ return nullptr;
+}
+
+DWARFDie DWARFContext::getDIEForOffset(uint64_t Offset) {
+ parseNormalUnits();
+ if (auto *CU = NormalUnits.getUnitForOffset(Offset))
+ return CU->getDIEForOffset(Offset);
+ return DWARFDie();
+}
+
+bool DWARFContext::verify(raw_ostream &OS, DIDumpOptions DumpOpts) {
+ bool Success = true;
+ DWARFVerifier verifier(OS, *this, DumpOpts);
+
+ Success &= verifier.handleDebugAbbrev();
+ if (DumpOpts.DumpType & DIDT_DebugInfo)
+ Success &= verifier.handleDebugInfo();
+ if (DumpOpts.DumpType & DIDT_DebugLine)
+ Success &= verifier.handleDebugLine();
+ Success &= verifier.handleAccelTables();
+ return Success;
+}
+
+const DWARFUnitIndex &DWARFContext::getCUIndex() {
+ if (CUIndex)
+ return *CUIndex;
+
+ DataExtractor CUIndexData(DObj->getCUIndexSection(), isLittleEndian(), 0);
+
+ CUIndex = std::make_unique<DWARFUnitIndex>(DW_SECT_INFO);
+ CUIndex->parse(CUIndexData);
+ return *CUIndex;
+}
+
+const DWARFUnitIndex &DWARFContext::getTUIndex() {
+ if (TUIndex)
+ return *TUIndex;
+
+ DataExtractor TUIndexData(DObj->getTUIndexSection(), isLittleEndian(), 0);
+
+ TUIndex = std::make_unique<DWARFUnitIndex>(DW_SECT_EXT_TYPES);
+ TUIndex->parse(TUIndexData);
+ return *TUIndex;
+}
+
+DWARFGdbIndex &DWARFContext::getGdbIndex() {
+ if (GdbIndex)
+ return *GdbIndex;
+
+ DataExtractor GdbIndexData(DObj->getGdbIndexSection(), true /*LE*/, 0);
+ GdbIndex = std::make_unique<DWARFGdbIndex>();
+ GdbIndex->parse(GdbIndexData);
+ return *GdbIndex;
+}
+
+const DWARFDebugAbbrev *DWARFContext::getDebugAbbrev() {
+ if (Abbrev)
+ return Abbrev.get();
+
+ DataExtractor abbrData(DObj->getAbbrevSection(), isLittleEndian(), 0);
+
+ Abbrev.reset(new DWARFDebugAbbrev());
+ Abbrev->extract(abbrData);
+ return Abbrev.get();
+}
+
+const DWARFDebugAbbrev *DWARFContext::getDebugAbbrevDWO() {
+ if (AbbrevDWO)
+ return AbbrevDWO.get();
+
+ DataExtractor abbrData(DObj->getAbbrevDWOSection(), isLittleEndian(), 0);
+ AbbrevDWO.reset(new DWARFDebugAbbrev());
+ AbbrevDWO->extract(abbrData);
+ return AbbrevDWO.get();
+}
+
+const DWARFDebugLoc *DWARFContext::getDebugLoc() {
+ if (Loc)
+ return Loc.get();
+
+ // Assume all units have the same address byte size.
+ auto LocData =
+ getNumCompileUnits()
+ ? DWARFDataExtractor(*DObj, DObj->getLocSection(), isLittleEndian(),
+ getUnitAtIndex(0)->getAddressByteSize())
+ : DWARFDataExtractor("", isLittleEndian(), 0);
+ Loc.reset(new DWARFDebugLoc(std::move(LocData)));
+ return Loc.get();
+}
+
+const DWARFDebugAranges *DWARFContext::getDebugAranges() {
+ if (Aranges)
+ return Aranges.get();
+
+ Aranges.reset(new DWARFDebugAranges());
+ Aranges->generate(this);
+ return Aranges.get();
+}
+
+Expected<const DWARFDebugFrame *> DWARFContext::getDebugFrame() {
+ if (DebugFrame)
+ return DebugFrame.get();
+
+ const DWARFSection &DS = DObj->getFrameSection();
+
+ // There's a "bug" in the DWARFv3 standard with respect to the target address
+ // size within debug frame sections. While DWARF is supposed to be independent
+ // of its container, FDEs have fields with size being "target address size",
+ // which isn't specified in DWARF in general. It's only specified for CUs, but
+ // .eh_frame can appear without a .debug_info section. Follow the example of
+ // other tools (libdwarf) and extract this from the container (ObjectFile
+ // provides this information). This problem is fixed in DWARFv4
+ // See this dwarf-discuss discussion for more details:
+ // http://lists.dwarfstd.org/htdig.cgi/dwarf-discuss-dwarfstd.org/2011-December/001173.html
+ DWARFDataExtractor DebugFrameData(*DObj, DS, isLittleEndian(),
+ DObj->getAddressSize());
+ auto DF =
+ std::make_unique<DWARFDebugFrame>(getArch(), /*IsEH=*/false, DS.Address);
+ if (Error E = DF->parse(DebugFrameData))
+ return std::move(E);
+
+ DebugFrame.swap(DF);
+ return DebugFrame.get();
+}
+
+Expected<const DWARFDebugFrame *> DWARFContext::getEHFrame() {
+ if (EHFrame)
+ return EHFrame.get();
+
+ const DWARFSection &DS = DObj->getEHFrameSection();
+ DWARFDataExtractor DebugFrameData(*DObj, DS, isLittleEndian(),
+ DObj->getAddressSize());
+
+ auto DF =
+ std::make_unique<DWARFDebugFrame>(getArch(), /*IsEH=*/true, DS.Address);
+ if (Error E = DF->parse(DebugFrameData))
+ return std::move(E);
+ DebugFrame.swap(DF);
+ return DebugFrame.get();
+}
+
+const DWARFDebugMacro *DWARFContext::getDebugMacro() {
+ if (!Macro)
+ Macro = parseMacroOrMacinfo(MacroSection);
+ return Macro.get();
+}
+
+const DWARFDebugMacro *DWARFContext::getDebugMacroDWO() {
+ if (!MacroDWO)
+ MacroDWO = parseMacroOrMacinfo(MacroDwoSection);
+ return MacroDWO.get();
+}
+
+const DWARFDebugMacro *DWARFContext::getDebugMacinfo() {
+ if (!Macinfo)
+ Macinfo = parseMacroOrMacinfo(MacinfoSection);
+ return Macinfo.get();
+}
+
+const DWARFDebugMacro *DWARFContext::getDebugMacinfoDWO() {
+ if (!MacinfoDWO)
+ MacinfoDWO = parseMacroOrMacinfo(MacinfoDwoSection);
+ return MacinfoDWO.get();
+}
+
+template <typename T>
+static T &getAccelTable(std::unique_ptr<T> &Cache, const DWARFObject &Obj,
+ const DWARFSection &Section, StringRef StringSection,
+ bool IsLittleEndian) {
+ if (Cache)
+ return *Cache;
+ DWARFDataExtractor AccelSection(Obj, Section, IsLittleEndian, 0);
+ DataExtractor StrData(StringSection, IsLittleEndian, 0);
+ Cache.reset(new T(AccelSection, StrData));
+ if (Error E = Cache->extract())
+ llvm::consumeError(std::move(E));
+ return *Cache;
+}
+
+const DWARFDebugNames &DWARFContext::getDebugNames() {
+ return getAccelTable(Names, *DObj, DObj->getNamesSection(),
+ DObj->getStrSection(), isLittleEndian());
+}
+
+const AppleAcceleratorTable &DWARFContext::getAppleNames() {
+ return getAccelTable(AppleNames, *DObj, DObj->getAppleNamesSection(),
+ DObj->getStrSection(), isLittleEndian());
+}
+
+const AppleAcceleratorTable &DWARFContext::getAppleTypes() {
+ return getAccelTable(AppleTypes, *DObj, DObj->getAppleTypesSection(),
+ DObj->getStrSection(), isLittleEndian());
+}
+
+const AppleAcceleratorTable &DWARFContext::getAppleNamespaces() {
+ return getAccelTable(AppleNamespaces, *DObj,
+ DObj->getAppleNamespacesSection(),
+ DObj->getStrSection(), isLittleEndian());
+}
+
+const AppleAcceleratorTable &DWARFContext::getAppleObjC() {
+ return getAccelTable(AppleObjC, *DObj, DObj->getAppleObjCSection(),
+ DObj->getStrSection(), isLittleEndian());
+}
+
+const DWARFDebugLine::LineTable *
+DWARFContext::getLineTableForUnit(DWARFUnit *U) {
+ Expected<const DWARFDebugLine::LineTable *> ExpectedLineTable =
+ getLineTableForUnit(U, WarningHandler);
+ if (!ExpectedLineTable) {
+ WarningHandler(ExpectedLineTable.takeError());
+ return nullptr;
+ }
+ return *ExpectedLineTable;
+}
+
+Expected<const DWARFDebugLine::LineTable *> DWARFContext::getLineTableForUnit(
+ DWARFUnit *U, function_ref<void(Error)> RecoverableErrorHandler) {
+ if (!Line)
+ Line.reset(new DWARFDebugLine);
+
+ auto UnitDIE = U->getUnitDIE();
+ if (!UnitDIE)
+ return nullptr;
+
+ auto Offset = toSectionOffset(UnitDIE.find(DW_AT_stmt_list));
+ if (!Offset)
+ return nullptr; // No line table for this compile unit.
+
+ uint64_t stmtOffset = *Offset + U->getLineTableOffset();
+ // See if the line table is cached.
+ if (const DWARFLineTable *lt = Line->getLineTable(stmtOffset))
+ return lt;
+
+ // Make sure the offset is good before we try to parse.
+ if (stmtOffset >= U->getLineSection().Data.size())
+ return nullptr;
+
+ // We have to parse it first.
+ DWARFDataExtractor lineData(*DObj, U->getLineSection(), isLittleEndian(),
+ U->getAddressByteSize());
+ return Line->getOrParseLineTable(lineData, stmtOffset, *this, U,
+ RecoverableErrorHandler);
+}
+
+void DWARFContext::parseNormalUnits() {
+ if (!NormalUnits.empty())
+ return;
+ DObj->forEachInfoSections([&](const DWARFSection &S) {
+ NormalUnits.addUnitsForSection(*this, S, DW_SECT_INFO);
+ });
+ NormalUnits.finishedInfoUnits();
+ DObj->forEachTypesSections([&](const DWARFSection &S) {
+ NormalUnits.addUnitsForSection(*this, S, DW_SECT_EXT_TYPES);
+ });
+}
+
+void DWARFContext::parseDWOUnits(bool Lazy) {
+ if (!DWOUnits.empty())
+ return;
+ DObj->forEachInfoDWOSections([&](const DWARFSection &S) {
+ DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_INFO, Lazy);
+ });
+ DWOUnits.finishedInfoUnits();
+ DObj->forEachTypesDWOSections([&](const DWARFSection &S) {
+ DWOUnits.addUnitsForDWOSection(*this, S, DW_SECT_EXT_TYPES, Lazy);
+ });
+}
+
+DWARFCompileUnit *DWARFContext::getCompileUnitForOffset(uint64_t Offset) {
+ parseNormalUnits();
+ return dyn_cast_or_null<DWARFCompileUnit>(
+ NormalUnits.getUnitForOffset(Offset));
+}
+
+DWARFCompileUnit *DWARFContext::getCompileUnitForAddress(uint64_t Address) {
+ // First, get the offset of the compile unit.
+ uint64_t CUOffset = getDebugAranges()->findAddress(Address);
+ // Retrieve the compile unit.
+ return getCompileUnitForOffset(CUOffset);
+}
+
+DWARFContext::DIEsForAddress DWARFContext::getDIEsForAddress(uint64_t Address) {
+ DIEsForAddress Result;
+
+ DWARFCompileUnit *CU = getCompileUnitForAddress(Address);
+ if (!CU)
+ return Result;
+
+ Result.CompileUnit = CU;
+ Result.FunctionDIE = CU->getSubroutineForAddress(Address);
+
+ std::vector<DWARFDie> Worklist;
+ Worklist.push_back(Result.FunctionDIE);
+ while (!Worklist.empty()) {
+ DWARFDie DIE = Worklist.back();
+ Worklist.pop_back();
+
+ if (!DIE.isValid())
+ continue;
+
+ if (DIE.getTag() == DW_TAG_lexical_block &&
+ DIE.addressRangeContainsAddress(Address)) {
+ Result.BlockDIE = DIE;
+ break;
+ }
+
+ append_range(Worklist, DIE);
+ }
+
+ return Result;
+}
+
+/// TODO: change input parameter from "uint64_t Address"
+/// into "SectionedAddress Address"
+static bool getFunctionNameAndStartLineForAddress(
+ DWARFCompileUnit *CU, uint64_t Address, FunctionNameKind Kind,
+ DILineInfoSpecifier::FileLineInfoKind FileNameKind,
+ std::string &FunctionName, std::string &StartFile, uint32_t &StartLine,
+ Optional<uint64_t> &StartAddress) {
+ // The address may correspond to instruction in some inlined function,
+ // so we have to build the chain of inlined functions and take the
+ // name of the topmost function in it.
+ SmallVector<DWARFDie, 4> InlinedChain;
+ CU->getInlinedChainForAddress(Address, InlinedChain);
+ if (InlinedChain.empty())
+ return false;
+
+ const DWARFDie &DIE = InlinedChain[0];
+ bool FoundResult = false;
+ const char *Name = nullptr;
+ if (Kind != FunctionNameKind::None && (Name = DIE.getSubroutineName(Kind))) {
+ FunctionName = Name;
+ FoundResult = true;
+ }
+ std::string DeclFile = DIE.getDeclFile(FileNameKind);
+ if (!DeclFile.empty()) {
+ StartFile = DeclFile;
+ FoundResult = true;
+ }
+ if (auto DeclLineResult = DIE.getDeclLine()) {
+ StartLine = DeclLineResult;
+ FoundResult = true;
+ }
+ if (auto LowPcAddr = toSectionedAddress(DIE.find(DW_AT_low_pc)))
+ StartAddress = LowPcAddr->Address;
+ return FoundResult;
+}
+
+static Optional<uint64_t> getTypeSize(DWARFDie Type, uint64_t PointerSize) {
+ if (auto SizeAttr = Type.find(DW_AT_byte_size))
+ if (Optional<uint64_t> Size = SizeAttr->getAsUnsignedConstant())
+ return Size;
+
+ switch (Type.getTag()) {
+ case DW_TAG_pointer_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_rvalue_reference_type:
+ return PointerSize;
+ case DW_TAG_ptr_to_member_type: {
+ if (DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type))
+ if (BaseType.getTag() == DW_TAG_subroutine_type)
+ return 2 * PointerSize;
+ return PointerSize;
+ }
+ case DW_TAG_const_type:
+ case DW_TAG_immutable_type:
+ case DW_TAG_volatile_type:
+ case DW_TAG_restrict_type:
+ case DW_TAG_typedef: {
+ if (DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type))
+ return getTypeSize(BaseType, PointerSize);
+ break;
+ }
+ case DW_TAG_array_type: {
+ DWARFDie BaseType = Type.getAttributeValueAsReferencedDie(DW_AT_type);
+ if (!BaseType)
+ return Optional<uint64_t>();
+ Optional<uint64_t> BaseSize = getTypeSize(BaseType, PointerSize);
+ if (!BaseSize)
+ return Optional<uint64_t>();
+ uint64_t Size = *BaseSize;
+ for (DWARFDie Child : Type) {
+ if (Child.getTag() != DW_TAG_subrange_type)
+ continue;
+
+ if (auto ElemCountAttr = Child.find(DW_AT_count))
+ if (Optional<uint64_t> ElemCount =
+ ElemCountAttr->getAsUnsignedConstant())
+ Size *= *ElemCount;
+ if (auto UpperBoundAttr = Child.find(DW_AT_upper_bound))
+ if (Optional<int64_t> UpperBound =
+ UpperBoundAttr->getAsSignedConstant()) {
+ int64_t LowerBound = 0;
+ if (auto LowerBoundAttr = Child.find(DW_AT_lower_bound))
+ LowerBound = LowerBoundAttr->getAsSignedConstant().getValueOr(0);
+ Size *= *UpperBound - LowerBound + 1;
+ }
+ }
+ return Size;
+ }
+ default:
+ break;
+ }
+ return Optional<uint64_t>();
+}
+
+static Optional<int64_t>
+getExpressionFrameOffset(ArrayRef<uint8_t> Expr,
+ Optional<unsigned> FrameBaseReg) {
+ if (!Expr.empty() &&
+ (Expr[0] == DW_OP_fbreg ||
+ (FrameBaseReg && Expr[0] == DW_OP_breg0 + *FrameBaseReg))) {
+ unsigned Count;
+ int64_t Offset = decodeSLEB128(Expr.data() + 1, &Count, Expr.end());
+ // A single DW_OP_fbreg or DW_OP_breg.
+ if (Expr.size() == Count + 1)
+ return Offset;
+ // Same + DW_OP_deref (Fortran arrays look like this).
+ if (Expr.size() == Count + 2 && Expr[Count + 1] == DW_OP_deref)
+ return Offset;
+ // Fallthrough. Do not accept ex. (DW_OP_breg W29, DW_OP_stack_value)
+ }
+ return None;
+}
+
+void DWARFContext::addLocalsForDie(DWARFCompileUnit *CU, DWARFDie Subprogram,
+ DWARFDie Die, std::vector<DILocal> &Result) {
+ if (Die.getTag() == DW_TAG_variable ||
+ Die.getTag() == DW_TAG_formal_parameter) {
+ DILocal Local;
+ if (const char *Name = Subprogram.getSubroutineName(DINameKind::ShortName))
+ Local.FunctionName = Name;
+
+ Optional<unsigned> FrameBaseReg;
+ if (auto FrameBase = Subprogram.find(DW_AT_frame_base))
+ if (Optional<ArrayRef<uint8_t>> Expr = FrameBase->getAsBlock())
+ if (!Expr->empty() && (*Expr)[0] >= DW_OP_reg0 &&
+ (*Expr)[0] <= DW_OP_reg31) {
+ FrameBaseReg = (*Expr)[0] - DW_OP_reg0;
+ }
+
+ if (Expected<std::vector<DWARFLocationExpression>> Loc =
+ Die.getLocations(DW_AT_location)) {
+ for (const auto &Entry : *Loc) {
+ if (Optional<int64_t> FrameOffset =
+ getExpressionFrameOffset(Entry.Expr, FrameBaseReg)) {
+ Local.FrameOffset = *FrameOffset;
+ break;
+ }
+ }
+ } else {
+ // FIXME: missing DW_AT_location is OK here, but other errors should be
+ // reported to the user.
+ consumeError(Loc.takeError());
+ }
+
+ if (auto TagOffsetAttr = Die.find(DW_AT_LLVM_tag_offset))
+ Local.TagOffset = TagOffsetAttr->getAsUnsignedConstant();
+
+ if (auto Origin =
+ Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin))
+ Die = Origin;
+ if (auto NameAttr = Die.find(DW_AT_name))
+ if (Optional<const char *> Name = dwarf::toString(*NameAttr))
+ Local.Name = *Name;
+ if (auto Type = Die.getAttributeValueAsReferencedDie(DW_AT_type))
+ Local.Size = getTypeSize(Type, getCUAddrSize());
+ if (auto DeclFileAttr = Die.find(DW_AT_decl_file)) {
+ if (const auto *LT = CU->getContext().getLineTableForUnit(CU))
+ LT->getFileNameByIndex(
+ DeclFileAttr->getAsUnsignedConstant().getValue(),
+ CU->getCompilationDir(),
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
+ Local.DeclFile);
+ }
+ if (auto DeclLineAttr = Die.find(DW_AT_decl_line))
+ Local.DeclLine = DeclLineAttr->getAsUnsignedConstant().getValue();
+
+ Result.push_back(Local);
+ return;
+ }
+
+ if (Die.getTag() == DW_TAG_inlined_subroutine)
+ if (auto Origin =
+ Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin))
+ Subprogram = Origin;
+
+ for (auto Child : Die)
+ addLocalsForDie(CU, Subprogram, Child, Result);
+}
+
+std::vector<DILocal>
+DWARFContext::getLocalsForAddress(object::SectionedAddress Address) {
+ std::vector<DILocal> Result;
+ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address);
+ if (!CU)
+ return Result;
+
+ DWARFDie Subprogram = CU->getSubroutineForAddress(Address.Address);
+ if (Subprogram.isValid())
+ addLocalsForDie(CU, Subprogram, Subprogram, Result);
+ return Result;
+}
+
+DILineInfo DWARFContext::getLineInfoForAddress(object::SectionedAddress Address,
+ DILineInfoSpecifier Spec) {
+ DILineInfo Result;
+
+ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address);
+ if (!CU)
+ return Result;
+
+ getFunctionNameAndStartLineForAddress(
+ CU, Address.Address, Spec.FNKind, Spec.FLIKind, Result.FunctionName,
+ Result.StartFileName, Result.StartLine, Result.StartAddress);
+ if (Spec.FLIKind != FileLineInfoKind::None) {
+ if (const DWARFLineTable *LineTable = getLineTableForUnit(CU)) {
+ LineTable->getFileLineInfoForAddress(
+ {Address.Address, Address.SectionIndex}, CU->getCompilationDir(),
+ Spec.FLIKind, Result);
+ }
+ }
+ return Result;
+}
+
+DILineInfoTable DWARFContext::getLineInfoForAddressRange(
+ object::SectionedAddress Address, uint64_t Size, DILineInfoSpecifier Spec) {
+ DILineInfoTable Lines;
+ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address);
+ if (!CU)
+ return Lines;
+
+ uint32_t StartLine = 0;
+ std::string StartFileName;
+ std::string FunctionName(DILineInfo::BadString);
+ Optional<uint64_t> StartAddress;
+ getFunctionNameAndStartLineForAddress(CU, Address.Address, Spec.FNKind,
+ Spec.FLIKind, FunctionName,
+ StartFileName, StartLine, StartAddress);
+
+ // If the Specifier says we don't need FileLineInfo, just
+ // return the top-most function at the starting address.
+ if (Spec.FLIKind == FileLineInfoKind::None) {
+ DILineInfo Result;
+ Result.FunctionName = FunctionName;
+ Result.StartFileName = StartFileName;
+ Result.StartLine = StartLine;
+ Result.StartAddress = StartAddress;
+ Lines.push_back(std::make_pair(Address.Address, Result));
+ return Lines;
+ }
+
+ const DWARFLineTable *LineTable = getLineTableForUnit(CU);
+
+ // Get the index of row we're looking for in the line table.
+ std::vector<uint32_t> RowVector;
+ if (!LineTable->lookupAddressRange({Address.Address, Address.SectionIndex},
+ Size, RowVector)) {
+ return Lines;
+ }
+
+ for (uint32_t RowIndex : RowVector) {
+ // Take file number and line/column from the row.
+ const DWARFDebugLine::Row &Row = LineTable->Rows[RowIndex];
+ DILineInfo Result;
+ LineTable->getFileNameByIndex(Row.File, CU->getCompilationDir(),
+ Spec.FLIKind, Result.FileName);
+ Result.FunctionName = FunctionName;
+ Result.Line = Row.Line;
+ Result.Column = Row.Column;
+ Result.StartFileName = StartFileName;
+ Result.StartLine = StartLine;
+ Result.StartAddress = StartAddress;
+ Lines.push_back(std::make_pair(Row.Address.Address, Result));
+ }
+
+ return Lines;
+}
+
+DIInliningInfo
+DWARFContext::getInliningInfoForAddress(object::SectionedAddress Address,
+ DILineInfoSpecifier Spec) {
+ DIInliningInfo InliningInfo;
+
+ DWARFCompileUnit *CU = getCompileUnitForAddress(Address.Address);
+ if (!CU)
+ return InliningInfo;
+
+ const DWARFLineTable *LineTable = nullptr;
+ SmallVector<DWARFDie, 4> InlinedChain;
+ CU->getInlinedChainForAddress(Address.Address, InlinedChain);
+ if (InlinedChain.size() == 0) {
+ // If there is no DIE for address (e.g. it is in unavailable .dwo file),
+ // try to at least get file/line info from symbol table.
+ if (Spec.FLIKind != FileLineInfoKind::None) {
+ DILineInfo Frame;
+ LineTable = getLineTableForUnit(CU);
+ if (LineTable && LineTable->getFileLineInfoForAddress(
+ {Address.Address, Address.SectionIndex},
+ CU->getCompilationDir(), Spec.FLIKind, Frame))
+ InliningInfo.addFrame(Frame);
+ }
+ return InliningInfo;
+ }
+
+ uint32_t CallFile = 0, CallLine = 0, CallColumn = 0, CallDiscriminator = 0;
+ for (uint32_t i = 0, n = InlinedChain.size(); i != n; i++) {
+ DWARFDie &FunctionDIE = InlinedChain[i];
+ DILineInfo Frame;
+ // Get function name if necessary.
+ if (const char *Name = FunctionDIE.getSubroutineName(Spec.FNKind))
+ Frame.FunctionName = Name;
+ if (auto DeclLineResult = FunctionDIE.getDeclLine())
+ Frame.StartLine = DeclLineResult;
+ Frame.StartFileName = FunctionDIE.getDeclFile(Spec.FLIKind);
+ if (auto LowPcAddr = toSectionedAddress(FunctionDIE.find(DW_AT_low_pc)))
+ Frame.StartAddress = LowPcAddr->Address;
+ if (Spec.FLIKind != FileLineInfoKind::None) {
+ if (i == 0) {
+ // For the topmost frame, initialize the line table of this
+ // compile unit and fetch file/line info from it.
+ LineTable = getLineTableForUnit(CU);
+ // For the topmost routine, get file/line info from line table.
+ if (LineTable)
+ LineTable->getFileLineInfoForAddress(
+ {Address.Address, Address.SectionIndex}, CU->getCompilationDir(),
+ Spec.FLIKind, Frame);
+ } else {
+ // Otherwise, use call file, call line and call column from
+ // previous DIE in inlined chain.
+ if (LineTable)
+ LineTable->getFileNameByIndex(CallFile, CU->getCompilationDir(),
+ Spec.FLIKind, Frame.FileName);
+ Frame.Line = CallLine;
+ Frame.Column = CallColumn;
+ Frame.Discriminator = CallDiscriminator;
+ }
+ // Get call file/line/column of a current DIE.
+ if (i + 1 < n) {
+ FunctionDIE.getCallerFrame(CallFile, CallLine, CallColumn,
+ CallDiscriminator);
+ }
+ }
+ InliningInfo.addFrame(Frame);
+ }
+ return InliningInfo;
+}
+
+std::shared_ptr<DWARFContext>
+DWARFContext::getDWOContext(StringRef AbsolutePath) {
+ if (auto S = DWP.lock()) {
+ DWARFContext *Ctxt = S->Context.get();
+ return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
+ }
+
+ std::weak_ptr<DWOFile> *Entry = &DWOFiles[AbsolutePath];
+
+ if (auto S = Entry->lock()) {
+ DWARFContext *Ctxt = S->Context.get();
+ return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
+ }
+
+ Expected<OwningBinary<ObjectFile>> Obj = [&] {
+ if (!CheckedForDWP) {
+ SmallString<128> DWPName;
+ auto Obj = object::ObjectFile::createObjectFile(
+ this->DWPName.empty()
+ ? (DObj->getFileName() + ".dwp").toStringRef(DWPName)
+ : StringRef(this->DWPName));
+ if (Obj) {
+ Entry = &DWP;
+ return Obj;
+ } else {
+ CheckedForDWP = true;
+ // TODO: Should this error be handled (maybe in a high verbosity mode)
+ // before falling back to .dwo files?
+ consumeError(Obj.takeError());
+ }
+ }
+
+ return object::ObjectFile::createObjectFile(AbsolutePath);
+ }();
+
+ if (!Obj) {
+ // TODO: Actually report errors helpfully.
+ consumeError(Obj.takeError());
+ return nullptr;
+ }
+
+ auto S = std::make_shared<DWOFile>();
+ S->File = std::move(Obj.get());
+ S->Context = DWARFContext::create(*S->File.getBinary(),
+ ProcessDebugRelocations::Ignore);
+ *Entry = S;
+ auto *Ctxt = S->Context.get();
+ return std::shared_ptr<DWARFContext>(std::move(S), Ctxt);
+}
+
+static Error createError(const Twine &Reason, llvm::Error E) {
+ return make_error<StringError>(Reason + toString(std::move(E)),
+ inconvertibleErrorCode());
+}
+
+/// SymInfo contains information about symbol: it's address
+/// and section index which is -1LL for absolute symbols.
+struct SymInfo {
+ uint64_t Address;
+ uint64_t SectionIndex;
+};
+
+/// Returns the address of symbol relocation used against and a section index.
+/// Used for futher relocations computation. Symbol's section load address is
+static Expected<SymInfo> getSymbolInfo(const object::ObjectFile &Obj,
+ const RelocationRef &Reloc,
+ const LoadedObjectInfo *L,
+ std::map<SymbolRef, SymInfo> &Cache) {
+ SymInfo Ret = {0, (uint64_t)-1LL};
+ object::section_iterator RSec = Obj.section_end();
+ object::symbol_iterator Sym = Reloc.getSymbol();
+
+ std::map<SymbolRef, SymInfo>::iterator CacheIt = Cache.end();
+ // First calculate the address of the symbol or section as it appears
+ // in the object file
+ if (Sym != Obj.symbol_end()) {
+ bool New;
+ std::tie(CacheIt, New) = Cache.insert({*Sym, {0, 0}});
+ if (!New)
+ return CacheIt->second;
+
+ Expected<uint64_t> SymAddrOrErr = Sym->getAddress();
+ if (!SymAddrOrErr)
+ return createError("failed to compute symbol address: ",
+ SymAddrOrErr.takeError());
+
+ // Also remember what section this symbol is in for later
+ auto SectOrErr = Sym->getSection();
+ if (!SectOrErr)
+ return createError("failed to get symbol section: ",
+ SectOrErr.takeError());
+
+ RSec = *SectOrErr;
+ Ret.Address = *SymAddrOrErr;
+ } else if (auto *MObj = dyn_cast<MachOObjectFile>(&Obj)) {
+ RSec = MObj->getRelocationSection(Reloc.getRawDataRefImpl());
+ Ret.Address = RSec->getAddress();
+ }
+
+ if (RSec != Obj.section_end())
+ Ret.SectionIndex = RSec->getIndex();
+
+ // If we are given load addresses for the sections, we need to adjust:
+ // SymAddr = (Address of Symbol Or Section in File) -
+ // (Address of Section in File) +
+ // (Load Address of Section)
+ // RSec is now either the section being targeted or the section
+ // containing the symbol being targeted. In either case,
+ // we need to perform the same computation.
+ if (L && RSec != Obj.section_end())
+ if (uint64_t SectionLoadAddress = L->getSectionLoadAddress(*RSec))
+ Ret.Address += SectionLoadAddress - RSec->getAddress();
+
+ if (CacheIt != Cache.end())
+ CacheIt->second = Ret;
+
+ return Ret;
+}
+
+static bool isRelocScattered(const object::ObjectFile &Obj,
+ const RelocationRef &Reloc) {
+ const MachOObjectFile *MachObj = dyn_cast<MachOObjectFile>(&Obj);
+ if (!MachObj)
+ return false;
+ // MachO also has relocations that point to sections and
+ // scattered relocations.
+ auto RelocInfo = MachObj->getRelocation(Reloc.getRawDataRefImpl());
+ return MachObj->isRelocationScattered(RelocInfo);
+}
+
+namespace {
+struct DWARFSectionMap final : public DWARFSection {
+ RelocAddrMap Relocs;
+};
+
+class DWARFObjInMemory final : public DWARFObject {
+ bool IsLittleEndian;
+ uint8_t AddressSize;
+ StringRef FileName;
+ const object::ObjectFile *Obj = nullptr;
+ std::vector<SectionName> SectionNames;
+
+ using InfoSectionMap = MapVector<object::SectionRef, DWARFSectionMap,
+ std::map<object::SectionRef, unsigned>>;
+
+ InfoSectionMap InfoSections;
+ InfoSectionMap TypesSections;
+ InfoSectionMap InfoDWOSections;
+ InfoSectionMap TypesDWOSections;
+
+ DWARFSectionMap LocSection;
+ DWARFSectionMap LoclistsSection;
+ DWARFSectionMap LoclistsDWOSection;
+ DWARFSectionMap LineSection;
+ DWARFSectionMap RangesSection;
+ DWARFSectionMap RnglistsSection;
+ DWARFSectionMap StrOffsetsSection;
+ DWARFSectionMap LineDWOSection;
+ DWARFSectionMap FrameSection;
+ DWARFSectionMap EHFrameSection;
+ DWARFSectionMap LocDWOSection;
+ DWARFSectionMap StrOffsetsDWOSection;
+ DWARFSectionMap RangesDWOSection;
+ DWARFSectionMap RnglistsDWOSection;
+ DWARFSectionMap AddrSection;
+ DWARFSectionMap AppleNamesSection;
+ DWARFSectionMap AppleTypesSection;
+ DWARFSectionMap AppleNamespacesSection;
+ DWARFSectionMap AppleObjCSection;
+ DWARFSectionMap NamesSection;
+ DWARFSectionMap PubnamesSection;
+ DWARFSectionMap PubtypesSection;
+ DWARFSectionMap GnuPubnamesSection;
+ DWARFSectionMap GnuPubtypesSection;
+ DWARFSectionMap MacroSection;
+
+ DWARFSectionMap *mapNameToDWARFSection(StringRef Name) {
+ return StringSwitch<DWARFSectionMap *>(Name)
+ .Case("debug_loc", &LocSection)
+ .Case("debug_loclists", &LoclistsSection)
+ .Case("debug_loclists.dwo", &LoclistsDWOSection)
+ .Case("debug_line", &LineSection)
+ .Case("debug_frame", &FrameSection)
+ .Case("eh_frame", &EHFrameSection)
+ .Case("debug_str_offsets", &StrOffsetsSection)
+ .Case("debug_ranges", &RangesSection)
+ .Case("debug_rnglists", &RnglistsSection)
+ .Case("debug_loc.dwo", &LocDWOSection)
+ .Case("debug_line.dwo", &LineDWOSection)
+ .Case("debug_names", &NamesSection)
+ .Case("debug_rnglists.dwo", &RnglistsDWOSection)
+ .Case("debug_str_offsets.dwo", &StrOffsetsDWOSection)
+ .Case("debug_addr", &AddrSection)
+ .Case("apple_names", &AppleNamesSection)
+ .Case("debug_pubnames", &PubnamesSection)
+ .Case("debug_pubtypes", &PubtypesSection)
+ .Case("debug_gnu_pubnames", &GnuPubnamesSection)
+ .Case("debug_gnu_pubtypes", &GnuPubtypesSection)
+ .Case("apple_types", &AppleTypesSection)
+ .Case("apple_namespaces", &AppleNamespacesSection)
+ .Case("apple_namespac", &AppleNamespacesSection)
+ .Case("apple_objc", &AppleObjCSection)
+ .Case("debug_macro", &MacroSection)
+ .Default(nullptr);
+ }
+
+ StringRef AbbrevSection;
+ StringRef ArangesSection;
+ StringRef StrSection;
+ StringRef MacinfoSection;
+ StringRef MacinfoDWOSection;
+ StringRef MacroDWOSection;
+ StringRef AbbrevDWOSection;
+ StringRef StrDWOSection;
+ StringRef CUIndexSection;
+ StringRef GdbIndexSection;
+ StringRef TUIndexSection;
+ StringRef LineStrSection;
+
+ // A deque holding section data whose iterators are not invalidated when
+ // new decompressed sections are inserted at the end.
+ std::deque<SmallString<0>> UncompressedSections;
+
+ StringRef *mapSectionToMember(StringRef Name) {
+ if (DWARFSection *Sec = mapNameToDWARFSection(Name))
+ return &Sec->Data;
+ return StringSwitch<StringRef *>(Name)
+ .Case("debug_abbrev", &AbbrevSection)
+ .Case("debug_aranges", &ArangesSection)
+ .Case("debug_str", &StrSection)
+ .Case("debug_macinfo", &MacinfoSection)
+ .Case("debug_macinfo.dwo", &MacinfoDWOSection)
+ .Case("debug_macro.dwo", &MacroDWOSection)
+ .Case("debug_abbrev.dwo", &AbbrevDWOSection)
+ .Case("debug_str.dwo", &StrDWOSection)
+ .Case("debug_cu_index", &CUIndexSection)
+ .Case("debug_tu_index", &TUIndexSection)
+ .Case("gdb_index", &GdbIndexSection)
+ .Case("debug_line_str", &LineStrSection)
+ // Any more debug info sections go here.
+ .Default(nullptr);
+ }
+
+ /// If Sec is compressed section, decompresses and updates its contents
+ /// provided by Data. Otherwise leaves it unchanged.
+ Error maybeDecompress(const object::SectionRef &Sec, StringRef Name,
+ StringRef &Data) {
+ if (!Decompressor::isCompressed(Sec))
+ return Error::success();
+
+ Expected<Decompressor> Decompressor =
+ Decompressor::create(Name, Data, IsLittleEndian, AddressSize == 8);
+ if (!Decompressor)
+ return Decompressor.takeError();
+
+ SmallString<0> Out;
+ if (auto Err = Decompressor->resizeAndDecompress(Out))
+ return Err;
+
+ UncompressedSections.push_back(std::move(Out));
+ Data = UncompressedSections.back();
+
+ return Error::success();
+ }
+
+public:
+ DWARFObjInMemory(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
+ uint8_t AddrSize, bool IsLittleEndian)
+ : IsLittleEndian(IsLittleEndian) {
+ for (const auto &SecIt : Sections) {
+ if (StringRef *SectionData = mapSectionToMember(SecIt.first()))
+ *SectionData = SecIt.second->getBuffer();
+ else if (SecIt.first() == "debug_info")
+ // Find debug_info and debug_types data by section rather than name as
+ // there are multiple, comdat grouped, of these sections.
+ InfoSections[SectionRef()].Data = SecIt.second->getBuffer();
+ else if (SecIt.first() == "debug_info.dwo")
+ InfoDWOSections[SectionRef()].Data = SecIt.second->getBuffer();
+ else if (SecIt.first() == "debug_types")
+ TypesSections[SectionRef()].Data = SecIt.second->getBuffer();
+ else if (SecIt.first() == "debug_types.dwo")
+ TypesDWOSections[SectionRef()].Data = SecIt.second->getBuffer();
+ }
+ }
+ DWARFObjInMemory(const object::ObjectFile &Obj, const LoadedObjectInfo *L,
+ function_ref<void(Error)> HandleError,
+ function_ref<void(Error)> HandleWarning,
+ DWARFContext::ProcessDebugRelocations RelocAction)
+ : IsLittleEndian(Obj.isLittleEndian()),
+ AddressSize(Obj.getBytesInAddress()), FileName(Obj.getFileName()),
+ Obj(&Obj) {
+
+ StringMap<unsigned> SectionAmountMap;
+ for (const SectionRef &Section : Obj.sections()) {
+ StringRef Name;
+ if (auto NameOrErr = Section.getName())
+ Name = *NameOrErr;
+ else
+ consumeError(NameOrErr.takeError());
+
+ ++SectionAmountMap[Name];
+ SectionNames.push_back({ Name, true });
+
+ // Skip BSS and Virtual sections, they aren't interesting.
+ if (Section.isBSS() || Section.isVirtual())
+ continue;
+
+ // Skip sections stripped by dsymutil.
+ if (Section.isStripped())
+ continue;
+
+ StringRef Data;
+ Expected<section_iterator> SecOrErr = Section.getRelocatedSection();
+ if (!SecOrErr) {
+ HandleError(createError("failed to get relocated section: ",
+ SecOrErr.takeError()));
+ continue;
+ }
+
+ // Try to obtain an already relocated version of this section.
+ // Else use the unrelocated section from the object file. We'll have to
+ // apply relocations ourselves later.
+ section_iterator RelocatedSection =
+ Obj.isRelocatableObject() ? *SecOrErr : Obj.section_end();
+ if (!L || !L->getLoadedSectionContents(*RelocatedSection, Data)) {
+ Expected<StringRef> E = Section.getContents();
+ if (E)
+ Data = *E;
+ else
+ // maybeDecompress below will error.
+ consumeError(E.takeError());
+ }
+
+ if (auto Err = maybeDecompress(Section, Name, Data)) {
+ HandleError(createError("failed to decompress '" + Name + "', ",
+ std::move(Err)));
+ continue;
+ }
+
+ // Compressed sections names in GNU style starts from ".z",
+ // at this point section is decompressed and we drop compression prefix.
+ Name = Name.substr(
+ Name.find_first_not_of("._z")); // Skip ".", "z" and "_" prefixes.
+
+ // Map platform specific debug section names to DWARF standard section
+ // names.
+ Name = Obj.mapDebugSectionName(Name);
+
+ if (StringRef *SectionData = mapSectionToMember(Name)) {
+ *SectionData = Data;
+ if (Name == "debug_ranges") {
+ // FIXME: Use the other dwo range section when we emit it.
+ RangesDWOSection.Data = Data;
+ } else if (Name == "debug_frame" || Name == "eh_frame") {
+ if (DWARFSection *S = mapNameToDWARFSection(Name))
+ S->Address = Section.getAddress();
+ }
+ } else if (InfoSectionMap *Sections =
+ StringSwitch<InfoSectionMap *>(Name)
+ .Case("debug_info", &InfoSections)
+ .Case("debug_info.dwo", &InfoDWOSections)
+ .Case("debug_types", &TypesSections)
+ .Case("debug_types.dwo", &TypesDWOSections)
+ .Default(nullptr)) {
+ // Find debug_info and debug_types data by section rather than name as
+ // there are multiple, comdat grouped, of these sections.
+ DWARFSectionMap &S = (*Sections)[Section];
+ S.Data = Data;
+ }
+
+ if (RelocatedSection != Obj.section_end() && Name.contains(".dwo"))
+ HandleWarning(
+ createError("Unexpected relocations for dwo section " + Name));
+
+ if (RelocatedSection == Obj.section_end() ||
+ (RelocAction == DWARFContext::ProcessDebugRelocations::Ignore))
+ continue;
+
+ StringRef RelSecName;
+ if (auto NameOrErr = RelocatedSection->getName())
+ RelSecName = *NameOrErr;
+ else
+ consumeError(NameOrErr.takeError());
+
+ // If the section we're relocating was relocated already by the JIT,
+ // then we used the relocated version above, so we do not need to process
+ // relocations for it now.
+ StringRef RelSecData;
+ if (L && L->getLoadedSectionContents(*RelocatedSection, RelSecData))
+ continue;
+
+ // In Mach-o files, the relocations do not need to be applied if
+ // there is no load offset to apply. The value read at the
+ // relocation point already factors in the section address
+ // (actually applying the relocations will produce wrong results
+ // as the section address will be added twice).
+ if (!L && isa<MachOObjectFile>(&Obj))
+ continue;
+
+ RelSecName = RelSecName.substr(
+ RelSecName.find_first_not_of("._z")); // Skip . and _ prefixes.
+
+ // TODO: Add support for relocations in other sections as needed.
+ // Record relocations for the debug_info and debug_line sections.
+ DWARFSectionMap *Sec = mapNameToDWARFSection(RelSecName);
+ RelocAddrMap *Map = Sec ? &Sec->Relocs : nullptr;
+ if (!Map) {
+ // Find debug_info and debug_types relocs by section rather than name
+ // as there are multiple, comdat grouped, of these sections.
+ if (RelSecName == "debug_info")
+ Map = &static_cast<DWARFSectionMap &>(InfoSections[*RelocatedSection])
+ .Relocs;
+ else if (RelSecName == "debug_types")
+ Map =
+ &static_cast<DWARFSectionMap &>(TypesSections[*RelocatedSection])
+ .Relocs;
+ else
+ continue;
+ }
+
+ if (Section.relocation_begin() == Section.relocation_end())
+ continue;
+
+ // Symbol to [address, section index] cache mapping.
+ std::map<SymbolRef, SymInfo> AddrCache;
+ SupportsRelocation Supports;
+ RelocationResolver Resolver;
+ std::tie(Supports, Resolver) = getRelocationResolver(Obj);
+ for (const RelocationRef &Reloc : Section.relocations()) {
+ // FIXME: it's not clear how to correctly handle scattered
+ // relocations.
+ if (isRelocScattered(Obj, Reloc))
+ continue;
+
+ Expected<SymInfo> SymInfoOrErr =
+ getSymbolInfo(Obj, Reloc, L, AddrCache);
+ if (!SymInfoOrErr) {
+ HandleError(SymInfoOrErr.takeError());
+ continue;
+ }
+
+ // Check if Resolver can handle this relocation type early so as not to
+ // handle invalid cases in DWARFDataExtractor.
+ //
+ // TODO Don't store Resolver in every RelocAddrEntry.
+ if (Supports && Supports(Reloc.getType())) {
+ auto I = Map->try_emplace(
+ Reloc.getOffset(),
+ RelocAddrEntry{SymInfoOrErr->SectionIndex, Reloc,
+ SymInfoOrErr->Address,
+ Optional<object::RelocationRef>(), 0, Resolver});
+ // If we didn't successfully insert that's because we already had a
+ // relocation for that offset. Store it as a second relocation in the
+ // same RelocAddrEntry instead.
+ if (!I.second) {
+ RelocAddrEntry &entry = I.first->getSecond();
+ if (entry.Reloc2) {
+ HandleError(createError(
+ "At most two relocations per offset are supported"));
+ }
+ entry.Reloc2 = Reloc;
+ entry.SymbolValue2 = SymInfoOrErr->Address;
+ }
+ } else {
+ SmallString<32> Type;
+ Reloc.getTypeName(Type);
+ // FIXME: Support more relocations & change this to an error
+ HandleWarning(
+ createError("failed to compute relocation: " + Type + ", ",
+ errorCodeToError(object_error::parse_failed)));
+ }
+ }
+ }
+
+ for (SectionName &S : SectionNames)
+ if (SectionAmountMap[S.Name] > 1)
+ S.IsNameUnique = false;
+ }
+
+ Optional<RelocAddrEntry> find(const DWARFSection &S,
+ uint64_t Pos) const override {
+ auto &Sec = static_cast<const DWARFSectionMap &>(S);
+ RelocAddrMap::const_iterator AI = Sec.Relocs.find(Pos);
+ if (AI == Sec.Relocs.end())
+ return None;
+ return AI->second;
+ }
+
+ const object::ObjectFile *getFile() const override { return Obj; }
+
+ ArrayRef<SectionName> getSectionNames() const override {
+ return SectionNames;
+ }
+
+ bool isLittleEndian() const override { return IsLittleEndian; }
+ StringRef getAbbrevDWOSection() const override { return AbbrevDWOSection; }
+ const DWARFSection &getLineDWOSection() const override {
+ return LineDWOSection;
+ }
+ const DWARFSection &getLocDWOSection() const override {
+ return LocDWOSection;
+ }
+ StringRef getStrDWOSection() const override { return StrDWOSection; }
+ const DWARFSection &getStrOffsetsDWOSection() const override {
+ return StrOffsetsDWOSection;
+ }
+ const DWARFSection &getRangesDWOSection() const override {
+ return RangesDWOSection;
+ }
+ const DWARFSection &getRnglistsDWOSection() const override {
+ return RnglistsDWOSection;
+ }
+ const DWARFSection &getLoclistsDWOSection() const override {
+ return LoclistsDWOSection;
+ }
+ const DWARFSection &getAddrSection() const override { return AddrSection; }
+ StringRef getCUIndexSection() const override { return CUIndexSection; }
+ StringRef getGdbIndexSection() const override { return GdbIndexSection; }
+ StringRef getTUIndexSection() const override { return TUIndexSection; }
+
+ // DWARF v5
+ const DWARFSection &getStrOffsetsSection() const override {
+ return StrOffsetsSection;
+ }
+ StringRef getLineStrSection() const override { return LineStrSection; }
+
+ // Sections for DWARF5 split dwarf proposal.
+ void forEachInfoDWOSections(
+ function_ref<void(const DWARFSection &)> F) const override {
+ for (auto &P : InfoDWOSections)
+ F(P.second);
+ }
+ void forEachTypesDWOSections(
+ function_ref<void(const DWARFSection &)> F) const override {
+ for (auto &P : TypesDWOSections)
+ F(P.second);
+ }
+
+ StringRef getAbbrevSection() const override { return AbbrevSection; }
+ const DWARFSection &getLocSection() const override { return LocSection; }
+ const DWARFSection &getLoclistsSection() const override { return LoclistsSection; }
+ StringRef getArangesSection() const override { return ArangesSection; }
+ const DWARFSection &getFrameSection() const override {
+ return FrameSection;
+ }
+ const DWARFSection &getEHFrameSection() const override {
+ return EHFrameSection;
+ }
+ const DWARFSection &getLineSection() const override { return LineSection; }
+ StringRef getStrSection() const override { return StrSection; }
+ const DWARFSection &getRangesSection() const override { return RangesSection; }
+ const DWARFSection &getRnglistsSection() const override {
+ return RnglistsSection;
+ }
+ const DWARFSection &getMacroSection() const override { return MacroSection; }
+ StringRef getMacroDWOSection() const override { return MacroDWOSection; }
+ StringRef getMacinfoSection() const override { return MacinfoSection; }
+ StringRef getMacinfoDWOSection() const override { return MacinfoDWOSection; }
+ const DWARFSection &getPubnamesSection() const override { return PubnamesSection; }
+ const DWARFSection &getPubtypesSection() const override { return PubtypesSection; }
+ const DWARFSection &getGnuPubnamesSection() const override {
+ return GnuPubnamesSection;
+ }
+ const DWARFSection &getGnuPubtypesSection() const override {
+ return GnuPubtypesSection;
+ }
+ const DWARFSection &getAppleNamesSection() const override {
+ return AppleNamesSection;
+ }
+ const DWARFSection &getAppleTypesSection() const override {
+ return AppleTypesSection;
+ }
+ const DWARFSection &getAppleNamespacesSection() const override {
+ return AppleNamespacesSection;
+ }
+ const DWARFSection &getAppleObjCSection() const override {
+ return AppleObjCSection;
+ }
+ const DWARFSection &getNamesSection() const override {
+ return NamesSection;
+ }
+
+ StringRef getFileName() const override { return FileName; }
+ uint8_t getAddressSize() const override { return AddressSize; }
+ void forEachInfoSections(
+ function_ref<void(const DWARFSection &)> F) const override {
+ for (auto &P : InfoSections)
+ F(P.second);
+ }
+ void forEachTypesSections(
+ function_ref<void(const DWARFSection &)> F) const override {
+ for (auto &P : TypesSections)
+ F(P.second);
+ }
+};
+} // namespace
+
+std::unique_ptr<DWARFContext>
+DWARFContext::create(const object::ObjectFile &Obj,
+ ProcessDebugRelocations RelocAction,
+ const LoadedObjectInfo *L, std::string DWPName,
+ std::function<void(Error)> RecoverableErrorHandler,
+ std::function<void(Error)> WarningHandler) {
+ auto DObj = std::make_unique<DWARFObjInMemory>(
+ Obj, L, RecoverableErrorHandler, WarningHandler, RelocAction);
+ return std::make_unique<DWARFContext>(std::move(DObj), std::move(DWPName),
+ RecoverableErrorHandler,
+ WarningHandler);
+}
+
+std::unique_ptr<DWARFContext>
+DWARFContext::create(const StringMap<std::unique_ptr<MemoryBuffer>> &Sections,
+ uint8_t AddrSize, bool isLittleEndian,
+ std::function<void(Error)> RecoverableErrorHandler,
+ std::function<void(Error)> WarningHandler) {
+ auto DObj =
+ std::make_unique<DWARFObjInMemory>(Sections, AddrSize, isLittleEndian);
+ return std::make_unique<DWARFContext>(
+ std::move(DObj), "", RecoverableErrorHandler, WarningHandler);
+}
+
+Error DWARFContext::loadRegisterInfo(const object::ObjectFile &Obj) {
+ // Detect the architecture from the object file. We usually don't need OS
+ // info to lookup a target and create register info.
+ Triple TT;
+ TT.setArch(Triple::ArchType(Obj.getArch()));
+ TT.setVendor(Triple::UnknownVendor);
+ TT.setOS(Triple::UnknownOS);
+ std::string TargetLookupError;
+ const Target *TheTarget =
+ TargetRegistry::lookupTarget(TT.str(), TargetLookupError);
+ if (!TargetLookupError.empty())
+ return createStringError(errc::invalid_argument,
+ TargetLookupError.c_str());
+ RegInfo.reset(TheTarget->createMCRegInfo(TT.str()));
+ return Error::success();
+}
+
+uint8_t DWARFContext::getCUAddrSize() {
+ // In theory, different compile units may have different address byte
+ // sizes, but for simplicity we just use the address byte size of the
+ // first compile unit. In practice the address size field is repeated across
+ // various DWARF headers (at least in version 5) to make it easier to dump
+ // them independently, not to enable varying the address size.
+ auto CUs = compile_units();
+ return CUs.empty() ? 0 : (*CUs.begin())->getAddressByteSize();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
new file mode 100644
index 0000000000..da6f6ad903
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDataExtractor.cpp
@@ -0,0 +1,135 @@
+//===- DWARFDataExtractor.cpp ---------------------------------------------===//
+//
+// 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/DWARF/DWARFDataExtractor.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+
+using namespace llvm;
+
+std::pair<uint64_t, dwarf::DwarfFormat>
+DWARFDataExtractor::getInitialLength(uint64_t *Off, Error *Err) const {
+ ErrorAsOutParameter ErrAsOut(Err);
+ if (Err && *Err)
+ return {0, dwarf::DWARF32};
+
+ Cursor C(*Off);
+ uint64_t Length = getRelocatedValue(C, 4);
+ dwarf::DwarfFormat Format = dwarf::DWARF32;
+ if (Length == dwarf::DW_LENGTH_DWARF64) {
+ Length = getRelocatedValue(C, 8);
+ Format = dwarf::DWARF64;
+ } else if (Length >= dwarf::DW_LENGTH_lo_reserved) {
+ cantFail(C.takeError());
+ if (Err)
+ *Err = createStringError(
+ errc::invalid_argument,
+ "unsupported reserved unit length of value 0x%8.8" PRIx64, Length);
+ return {0, dwarf::DWARF32};
+ }
+
+ if (C) {
+ *Off = C.tell();
+ return {Length, Format};
+ }
+ if (Err)
+ *Err = C.takeError();
+ else
+ consumeError(C.takeError());
+ return {0, dwarf::DWARF32};
+}
+
+uint64_t DWARFDataExtractor::getRelocatedValue(uint32_t Size, uint64_t *Off,
+ uint64_t *SecNdx,
+ Error *Err) const {
+ if (SecNdx)
+ *SecNdx = object::SectionedAddress::UndefSection;
+ if (!Section)
+ return getUnsigned(Off, Size, Err);
+
+ ErrorAsOutParameter ErrAsOut(Err);
+ Optional<RelocAddrEntry> E = Obj->find(*Section, *Off);
+ uint64_t LocData = getUnsigned(Off, Size, Err);
+ if (!E || (Err && *Err))
+ return LocData;
+ if (SecNdx)
+ *SecNdx = E->SectionIndex;
+
+ uint64_t R =
+ object::resolveRelocation(E->Resolver, E->Reloc, E->SymbolValue, LocData);
+ if (E->Reloc2)
+ R = object::resolveRelocation(E->Resolver, *E->Reloc2, E->SymbolValue2, R);
+ return R;
+}
+
+Optional<uint64_t>
+DWARFDataExtractor::getEncodedPointer(uint64_t *Offset, uint8_t Encoding,
+ uint64_t PCRelOffset) const {
+ if (Encoding == dwarf::DW_EH_PE_omit)
+ return None;
+
+ uint64_t Result = 0;
+ uint64_t OldOffset = *Offset;
+ // First get value
+ switch (Encoding & 0x0F) {
+ case dwarf::DW_EH_PE_absptr:
+ switch (getAddressSize()) {
+ case 2:
+ case 4:
+ case 8:
+ Result = getUnsigned(Offset, getAddressSize());
+ break;
+ default:
+ return None;
+ }
+ break;
+ case dwarf::DW_EH_PE_uleb128:
+ Result = getULEB128(Offset);
+ break;
+ case dwarf::DW_EH_PE_sleb128:
+ Result = getSLEB128(Offset);
+ break;
+ case dwarf::DW_EH_PE_udata2:
+ Result = getUnsigned(Offset, 2);
+ break;
+ case dwarf::DW_EH_PE_udata4:
+ Result = getUnsigned(Offset, 4);
+ break;
+ case dwarf::DW_EH_PE_udata8:
+ Result = getUnsigned(Offset, 8);
+ break;
+ case dwarf::DW_EH_PE_sdata2:
+ Result = getSigned(Offset, 2);
+ break;
+ case dwarf::DW_EH_PE_sdata4:
+ Result = SignExtend64<32>(getRelocatedValue(4, Offset));
+ break;
+ case dwarf::DW_EH_PE_sdata8:
+ Result = getRelocatedValue(8, Offset);
+ break;
+ default:
+ return None;
+ }
+ // Then add relative offset, if required
+ switch (Encoding & 0x70) {
+ case dwarf::DW_EH_PE_absptr:
+ // do nothing
+ break;
+ case dwarf::DW_EH_PE_pcrel:
+ Result += PCRelOffset;
+ break;
+ case dwarf::DW_EH_PE_datarel:
+ case dwarf::DW_EH_PE_textrel:
+ case dwarf::DW_EH_PE_funcrel:
+ case dwarf::DW_EH_PE_aligned:
+ default:
+ *Offset = OldOffset;
+ return None;
+ }
+
+ return Result;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
new file mode 100644
index 0000000000..ee54fc7548
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugAbbrev.cpp
@@ -0,0 +1,167 @@
+//===- DWARFDebugAbbrev.cpp -----------------------------------------------===//
+//
+// 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/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cinttypes>
+#include <cstdint>
+
+using namespace llvm;
+
+DWARFAbbreviationDeclarationSet::DWARFAbbreviationDeclarationSet() {
+ clear();
+}
+
+void DWARFAbbreviationDeclarationSet::clear() {
+ Offset = 0;
+ FirstAbbrCode = 0;
+ Decls.clear();
+}
+
+bool DWARFAbbreviationDeclarationSet::extract(DataExtractor Data,
+ uint64_t *OffsetPtr) {
+ clear();
+ const uint64_t BeginOffset = *OffsetPtr;
+ Offset = BeginOffset;
+ DWARFAbbreviationDeclaration AbbrDecl;
+ uint32_t PrevAbbrCode = 0;
+ while (AbbrDecl.extract(Data, OffsetPtr)) {
+ if (FirstAbbrCode == 0) {
+ FirstAbbrCode = AbbrDecl.getCode();
+ } else {
+ if (PrevAbbrCode + 1 != AbbrDecl.getCode()) {
+ // Codes are not consecutive, can't do O(1) lookups.
+ FirstAbbrCode = UINT32_MAX;
+ }
+ }
+ PrevAbbrCode = AbbrDecl.getCode();
+ Decls.push_back(std::move(AbbrDecl));
+ }
+ return BeginOffset != *OffsetPtr;
+}
+
+void DWARFAbbreviationDeclarationSet::dump(raw_ostream &OS) const {
+ for (const auto &Decl : Decls)
+ Decl.dump(OS);
+}
+
+const DWARFAbbreviationDeclaration *
+DWARFAbbreviationDeclarationSet::getAbbreviationDeclaration(
+ uint32_t AbbrCode) const {
+ if (FirstAbbrCode == UINT32_MAX) {
+ for (const auto &Decl : Decls) {
+ if (Decl.getCode() == AbbrCode)
+ return &Decl;
+ }
+ return nullptr;
+ }
+ if (AbbrCode < FirstAbbrCode || AbbrCode >= FirstAbbrCode + Decls.size())
+ return nullptr;
+ return &Decls[AbbrCode - FirstAbbrCode];
+}
+
+std::string DWARFAbbreviationDeclarationSet::getCodeRange() const {
+ // Create a sorted list of all abbrev codes.
+ std::vector<uint32_t> Codes;
+ Codes.reserve(Decls.size());
+ for (const auto &Decl : Decls)
+ Codes.push_back(Decl.getCode());
+
+ std::string Buffer;
+ raw_string_ostream Stream(Buffer);
+ // Each iteration through this loop represents a single contiguous range in
+ // the set of codes.
+ for (auto Current = Codes.begin(), End = Codes.end(); Current != End;) {
+ uint32_t RangeStart = *Current;
+ // Add the current range start.
+ Stream << *Current;
+ uint32_t RangeEnd = RangeStart;
+ // Find the end of the current range.
+ while (++Current != End && *Current == RangeEnd + 1)
+ ++RangeEnd;
+ // If there is more than one value in the range, add the range end too.
+ if (RangeStart != RangeEnd)
+ Stream << "-" << RangeEnd;
+ // If there is at least one more range, add a separator.
+ if (Current != End)
+ Stream << ", ";
+ }
+ return Buffer;
+}
+
+DWARFDebugAbbrev::DWARFDebugAbbrev() { clear(); }
+
+void DWARFDebugAbbrev::clear() {
+ AbbrDeclSets.clear();
+ PrevAbbrOffsetPos = AbbrDeclSets.end();
+}
+
+void DWARFDebugAbbrev::extract(DataExtractor Data) {
+ clear();
+ this->Data = Data;
+}
+
+void DWARFDebugAbbrev::parse() const {
+ if (!Data)
+ return;
+ uint64_t Offset = 0;
+ auto I = AbbrDeclSets.begin();
+ while (Data->isValidOffset(Offset)) {
+ while (I != AbbrDeclSets.end() && I->first < Offset)
+ ++I;
+ uint64_t CUAbbrOffset = Offset;
+ DWARFAbbreviationDeclarationSet AbbrDecls;
+ if (!AbbrDecls.extract(*Data, &Offset))
+ break;
+ AbbrDeclSets.insert(I, std::make_pair(CUAbbrOffset, std::move(AbbrDecls)));
+ }
+ Data = None;
+}
+
+void DWARFDebugAbbrev::dump(raw_ostream &OS) const {
+ parse();
+
+ if (AbbrDeclSets.empty()) {
+ OS << "< EMPTY >\n";
+ return;
+ }
+
+ for (const auto &I : AbbrDeclSets) {
+ OS << format("Abbrev table for offset: 0x%8.8" PRIx64 "\n", I.first);
+ I.second.dump(OS);
+ }
+}
+
+const DWARFAbbreviationDeclarationSet*
+DWARFDebugAbbrev::getAbbreviationDeclarationSet(uint64_t CUAbbrOffset) const {
+ const auto End = AbbrDeclSets.end();
+ if (PrevAbbrOffsetPos != End && PrevAbbrOffsetPos->first == CUAbbrOffset) {
+ return &(PrevAbbrOffsetPos->second);
+ }
+
+ const auto Pos = AbbrDeclSets.find(CUAbbrOffset);
+ if (Pos != End) {
+ PrevAbbrOffsetPos = Pos;
+ return &(Pos->second);
+ }
+
+ if (Data && CUAbbrOffset < Data->getData().size()) {
+ uint64_t Offset = CUAbbrOffset;
+ DWARFAbbreviationDeclarationSet AbbrDecls;
+ if (!AbbrDecls.extract(*Data, &Offset))
+ return nullptr;
+ PrevAbbrOffsetPos =
+ AbbrDeclSets.insert(std::make_pair(CUAbbrOffset, std::move(AbbrDecls)))
+ .first;
+ return &PrevAbbrOffsetPos->second;
+ }
+
+ return nullptr;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp
new file mode 100644
index 0000000000..5b1c62e6a2
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugAddr.cpp
@@ -0,0 +1,184 @@
+//===- DWARFDebugAddr.cpp -------------------------------------------------===//
+//
+// 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/DWARF/DWARFDebugAddr.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+
+using namespace llvm;
+
+Error DWARFDebugAddrTable::extractAddresses(const DWARFDataExtractor &Data,
+ uint64_t *OffsetPtr,
+ uint64_t EndOffset) {
+ assert(EndOffset >= *OffsetPtr);
+ uint64_t DataSize = EndOffset - *OffsetPtr;
+ assert(Data.isValidOffsetForDataOfSize(*OffsetPtr, DataSize));
+ if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
+ AddrSize, errc::not_supported, "address table at offset 0x%" PRIx64,
+ Offset))
+ return SizeErr;
+ if (DataSize % AddrSize != 0) {
+ invalidateLength();
+ return createStringError(errc::invalid_argument,
+ "address table at offset 0x%" PRIx64
+ " contains data of size 0x%" PRIx64
+ " which is not a multiple of addr size %" PRIu8,
+ Offset, DataSize, AddrSize);
+ }
+ Addrs.clear();
+ size_t Count = DataSize / AddrSize;
+ Addrs.reserve(Count);
+ while (Count--)
+ Addrs.push_back(Data.getRelocatedValue(AddrSize, OffsetPtr));
+ return Error::success();
+}
+
+Error DWARFDebugAddrTable::extractV5(const DWARFDataExtractor &Data,
+ uint64_t *OffsetPtr, uint8_t CUAddrSize,
+ std::function<void(Error)> WarnCallback) {
+ Offset = *OffsetPtr;
+ llvm::Error Err = Error::success();
+ std::tie(Length, Format) = Data.getInitialLength(OffsetPtr, &Err);
+ if (Err) {
+ invalidateLength();
+ return createStringError(errc::invalid_argument,
+ "parsing address table at offset 0x%" PRIx64
+ ": %s",
+ Offset, toString(std::move(Err)).c_str());
+ }
+
+ if (!Data.isValidOffsetForDataOfSize(*OffsetPtr, Length)) {
+ uint64_t DiagnosticLength = Length;
+ invalidateLength();
+ return createStringError(
+ errc::invalid_argument,
+ "section is not large enough to contain an address table "
+ "at offset 0x%" PRIx64 " with a unit_length value of 0x%" PRIx64,
+ Offset, DiagnosticLength);
+ }
+ uint64_t EndOffset = *OffsetPtr + Length;
+ // Ensure that we can read the remaining header fields.
+ if (Length < 4) {
+ uint64_t DiagnosticLength = Length;
+ invalidateLength();
+ return createStringError(
+ errc::invalid_argument,
+ "address table at offset 0x%" PRIx64
+ " has a unit_length value of 0x%" PRIx64
+ ", which is too small to contain a complete header",
+ Offset, DiagnosticLength);
+ }
+
+ Version = Data.getU16(OffsetPtr);
+ AddrSize = Data.getU8(OffsetPtr);
+ SegSize = Data.getU8(OffsetPtr);
+
+ // Perform a basic validation of the header fields.
+ if (Version != 5)
+ return createStringError(errc::not_supported,
+ "address table at offset 0x%" PRIx64
+ " has unsupported version %" PRIu16,
+ Offset, Version);
+ // TODO: add support for non-zero segment selector size.
+ if (SegSize != 0)
+ return createStringError(errc::not_supported,
+ "address table at offset 0x%" PRIx64
+ " has unsupported segment selector size %" PRIu8,
+ Offset, SegSize);
+
+ if (Error Err = extractAddresses(Data, OffsetPtr, EndOffset))
+ return Err;
+ if (CUAddrSize && AddrSize != CUAddrSize) {
+ WarnCallback(createStringError(
+ errc::invalid_argument,
+ "address table at offset 0x%" PRIx64 " has address size %" PRIu8
+ " which is different from CU address size %" PRIu8,
+ Offset, AddrSize, CUAddrSize));
+ }
+ return Error::success();
+}
+
+Error DWARFDebugAddrTable::extractPreStandard(const DWARFDataExtractor &Data,
+ uint64_t *OffsetPtr,
+ uint16_t CUVersion,
+ uint8_t CUAddrSize) {
+ assert(CUVersion > 0 && CUVersion < 5);
+
+ Offset = *OffsetPtr;
+ Length = 0;
+ Version = CUVersion;
+ AddrSize = CUAddrSize;
+ SegSize = 0;
+
+ return extractAddresses(Data, OffsetPtr, Data.size());
+}
+
+Error DWARFDebugAddrTable::extract(const DWARFDataExtractor &Data,
+ uint64_t *OffsetPtr,
+ uint16_t CUVersion,
+ uint8_t CUAddrSize,
+ std::function<void(Error)> WarnCallback) {
+ if (CUVersion > 0 && CUVersion < 5)
+ return extractPreStandard(Data, OffsetPtr, CUVersion, CUAddrSize);
+ if (CUVersion == 0)
+ WarnCallback(createStringError(errc::invalid_argument,
+ "DWARF version is not defined in CU,"
+ " assuming version 5"));
+ return extractV5(Data, OffsetPtr, CUAddrSize, WarnCallback);
+}
+
+void DWARFDebugAddrTable::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
+ if (DumpOpts.Verbose)
+ OS << format("0x%8.8" PRIx64 ": ", Offset);
+ if (Length) {
+ int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format);
+ OS << "Address table header: "
+ << format("length = 0x%0*" PRIx64, OffsetDumpWidth, Length)
+ << ", format = " << dwarf::FormatString(Format)
+ << format(", version = 0x%4.4" PRIx16, Version)
+ << format(", addr_size = 0x%2.2" PRIx8, AddrSize)
+ << format(", seg_size = 0x%2.2" PRIx8, SegSize) << "\n";
+ }
+
+ if (Addrs.size() > 0) {
+ const char *AddrFmt;
+ switch (AddrSize) {
+ case 2:
+ AddrFmt = "0x%4.4" PRIx64 "\n";
+ break;
+ case 4:
+ AddrFmt = "0x%8.8" PRIx64 "\n";
+ break;
+ case 8:
+ AddrFmt = "0x%16.16" PRIx64 "\n";
+ break;
+ default:
+ llvm_unreachable("unsupported address size");
+ }
+ OS << "Addrs: [\n";
+ for (uint64_t Addr : Addrs)
+ OS << format(AddrFmt, Addr);
+ OS << "]\n";
+ }
+}
+
+Expected<uint64_t> DWARFDebugAddrTable::getAddrEntry(uint32_t Index) const {
+ if (Index < Addrs.size())
+ return Addrs[Index];
+ return createStringError(errc::invalid_argument,
+ "Index %" PRIu32 " is out of range of the "
+ "address table at offset 0x%" PRIx64,
+ Index, Offset);
+}
+
+Optional<uint64_t> DWARFDebugAddrTable::getFullLength() const {
+ if (Length == 0)
+ return None;
+ return Length + dwarf::getUnitLengthFieldByteSize(Format);
+}
+
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp
new file mode 100644
index 0000000000..c60c9d9d72
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugArangeSet.cpp
@@ -0,0 +1,178 @@
+//===- DWARFDebugArangeSet.cpp --------------------------------------------===//
+//
+// 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/DWARF/DWARFDebugArangeSet.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+#include <cinttypes>
+#include <cstdint>
+#include <cstring>
+
+using namespace llvm;
+
+void DWARFDebugArangeSet::Descriptor::dump(raw_ostream &OS,
+ uint32_t AddressSize) const {
+ OS << '[';
+ DWARFFormValue::dumpAddress(OS, AddressSize, Address);
+ OS << ", ";
+ DWARFFormValue::dumpAddress(OS, AddressSize, getEndAddress());
+ OS << ')';
+}
+
+void DWARFDebugArangeSet::clear() {
+ Offset = -1ULL;
+ std::memset(&HeaderData, 0, sizeof(Header));
+ ArangeDescriptors.clear();
+}
+
+Error DWARFDebugArangeSet::extract(DWARFDataExtractor data,
+ uint64_t *offset_ptr,
+ function_ref<void(Error)> WarningHandler) {
+ assert(data.isValidOffset(*offset_ptr));
+ ArangeDescriptors.clear();
+ Offset = *offset_ptr;
+
+ // 7.21 Address Range Table (extract)
+ // Each set of entries in the table of address ranges contained in
+ // the .debug_aranges section begins with a header containing:
+ // 1. unit_length (initial length)
+ // A 4-byte (32-bit DWARF) or 12-byte (64-bit DWARF) length containing
+ // the length of the set of entries for this compilation unit,
+ // not including the length field itself.
+ // 2. version (uhalf)
+ // The value in this field is 2.
+ // 3. debug_info_offset (section offset)
+ // A 4-byte (32-bit DWARF) or 8-byte (64-bit DWARF) offset into the
+ // .debug_info section of the compilation unit header.
+ // 4. address_size (ubyte)
+ // 5. segment_selector_size (ubyte)
+ // This header is followed by a series of tuples. Each tuple consists of
+ // a segment, an address and a length. The segment selector size is given by
+ // the segment_selector_size field of the header; the address and length
+ // size are each given by the address_size field of the header. Each set of
+ // tuples is terminated by a 0 for the segment, a 0 for the address and 0
+ // for the length. If the segment_selector_size field in the header is zero,
+ // the segment selectors are omitted from all tuples, including
+ // the terminating tuple.
+
+ Error Err = Error::success();
+ std::tie(HeaderData.Length, HeaderData.Format) =
+ data.getInitialLength(offset_ptr, &Err);
+ HeaderData.Version = data.getU16(offset_ptr, &Err);
+ HeaderData.CuOffset = data.getUnsigned(
+ offset_ptr, dwarf::getDwarfOffsetByteSize(HeaderData.Format), &Err);
+ HeaderData.AddrSize = data.getU8(offset_ptr, &Err);
+ HeaderData.SegSize = data.getU8(offset_ptr, &Err);
+ if (Err) {
+ return createStringError(errc::invalid_argument,
+ "parsing address ranges table at offset 0x%" PRIx64
+ ": %s",
+ Offset, toString(std::move(Err)).c_str());
+ }
+
+ // Perform basic validation of the header fields.
+ uint64_t full_length =
+ dwarf::getUnitLengthFieldByteSize(HeaderData.Format) + HeaderData.Length;
+ if (!data.isValidOffsetForDataOfSize(Offset, full_length))
+ return createStringError(errc::invalid_argument,
+ "the length of address range table at offset "
+ "0x%" PRIx64 " exceeds section size",
+ Offset);
+ if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
+ HeaderData.AddrSize, errc::invalid_argument,
+ "address range table at offset 0x%" PRIx64, Offset))
+ return SizeErr;
+ if (HeaderData.SegSize != 0)
+ return createStringError(errc::not_supported,
+ "non-zero segment selector size in address range "
+ "table at offset 0x%" PRIx64 " is not supported",
+ Offset);
+
+ // The first tuple following the header in each set begins at an offset that
+ // is a multiple of the size of a single tuple (that is, twice the size of
+ // an address because we do not support non-zero segment selector sizes).
+ // Therefore, the full length should also be a multiple of the tuple size.
+ const uint32_t tuple_size = HeaderData.AddrSize * 2;
+ if (full_length % tuple_size != 0)
+ return createStringError(
+ errc::invalid_argument,
+ "address range table at offset 0x%" PRIx64
+ " has length that is not a multiple of the tuple size",
+ Offset);
+
+ // The header is padded, if necessary, to the appropriate boundary.
+ const uint32_t header_size = *offset_ptr - Offset;
+ uint32_t first_tuple_offset = 0;
+ while (first_tuple_offset < header_size)
+ first_tuple_offset += tuple_size;
+
+ // There should be space for at least one tuple.
+ if (full_length <= first_tuple_offset)
+ return createStringError(
+ errc::invalid_argument,
+ "address range table at offset 0x%" PRIx64
+ " has an insufficient length to contain any entries",
+ Offset);
+
+ *offset_ptr = Offset + first_tuple_offset;
+
+ Descriptor arangeDescriptor;
+
+ static_assert(sizeof(arangeDescriptor.Address) ==
+ sizeof(arangeDescriptor.Length),
+ "Different datatypes for addresses and sizes!");
+ assert(sizeof(arangeDescriptor.Address) >= HeaderData.AddrSize);
+
+ uint64_t end_offset = Offset + full_length;
+ while (*offset_ptr < end_offset) {
+ uint64_t EntryOffset = *offset_ptr;
+ arangeDescriptor.Address = data.getUnsigned(offset_ptr, HeaderData.AddrSize);
+ arangeDescriptor.Length = data.getUnsigned(offset_ptr, HeaderData.AddrSize);
+
+ // Each set of tuples is terminated by a 0 for the address and 0
+ // for the length.
+ if (arangeDescriptor.Length == 0 && arangeDescriptor.Address == 0) {
+ if (*offset_ptr == end_offset)
+ return ErrorSuccess();
+ WarningHandler(createStringError(
+ errc::invalid_argument,
+ "address range table at offset 0x%" PRIx64
+ " has a premature terminator entry at offset 0x%" PRIx64,
+ Offset, EntryOffset));
+ }
+
+ ArangeDescriptors.push_back(arangeDescriptor);
+ }
+
+ return createStringError(errc::invalid_argument,
+ "address range table at offset 0x%" PRIx64
+ " is not terminated by null entry",
+ Offset);
+}
+
+void DWARFDebugArangeSet::dump(raw_ostream &OS) const {
+ int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(HeaderData.Format);
+ OS << "Address Range Header: "
+ << format("length = 0x%0*" PRIx64 ", ", OffsetDumpWidth, HeaderData.Length)
+ << "format = " << dwarf::FormatString(HeaderData.Format) << ", "
+ << format("version = 0x%4.4x, ", HeaderData.Version)
+ << format("cu_offset = 0x%0*" PRIx64 ", ", OffsetDumpWidth,
+ HeaderData.CuOffset)
+ << format("addr_size = 0x%2.2x, ", HeaderData.AddrSize)
+ << format("seg_size = 0x%2.2x\n", HeaderData.SegSize);
+
+ for (const auto &Desc : ArangeDescriptors) {
+ Desc.dump(OS, HeaderData.AddrSize);
+ OS << '\n';
+ }
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
new file mode 100644
index 0000000000..1a1b8ea097
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugAranges.cpp
@@ -0,0 +1,127 @@
+//===- DWARFDebugAranges.cpp ----------------------------------------------===//
+//
+// 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/DWARF/DWARFDebugAranges.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugArangeSet.h"
+#include "llvm/Support/DataExtractor.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <set>
+
+using namespace llvm;
+
+void DWARFDebugAranges::extract(
+ DWARFDataExtractor DebugArangesData,
+ function_ref<void(Error)> RecoverableErrorHandler) {
+ if (!DebugArangesData.isValidOffset(0))
+ return;
+ uint64_t Offset = 0;
+ DWARFDebugArangeSet Set;
+
+ while (DebugArangesData.isValidOffset(Offset)) {
+ if (Error E =
+ Set.extract(DebugArangesData, &Offset, RecoverableErrorHandler)) {
+ RecoverableErrorHandler(std::move(E));
+ return;
+ }
+ uint64_t CUOffset = Set.getCompileUnitDIEOffset();
+ for (const auto &Desc : Set.descriptors()) {
+ uint64_t LowPC = Desc.Address;
+ uint64_t HighPC = Desc.getEndAddress();
+ appendRange(CUOffset, LowPC, HighPC);
+ }
+ ParsedCUOffsets.insert(CUOffset);
+ }
+}
+
+void DWARFDebugAranges::generate(DWARFContext *CTX) {
+ clear();
+ if (!CTX)
+ return;
+
+ // Extract aranges from .debug_aranges section.
+ DWARFDataExtractor ArangesData(CTX->getDWARFObj().getArangesSection(),
+ CTX->isLittleEndian(), 0);
+ extract(ArangesData, CTX->getRecoverableErrorHandler());
+
+ // Generate aranges from DIEs: even if .debug_aranges section is present,
+ // it may describe only a small subset of compilation units, so we need to
+ // manually build aranges for the rest of them.
+ for (const auto &CU : CTX->compile_units()) {
+ uint64_t CUOffset = CU->getOffset();
+ if (ParsedCUOffsets.insert(CUOffset).second) {
+ Expected<DWARFAddressRangesVector> CURanges = CU->collectAddressRanges();
+ if (!CURanges)
+ CTX->getRecoverableErrorHandler()(CURanges.takeError());
+ else
+ for (const auto &R : *CURanges)
+ appendRange(CUOffset, R.LowPC, R.HighPC);
+ }
+ }
+
+ construct();
+}
+
+void DWARFDebugAranges::clear() {
+ Endpoints.clear();
+ Aranges.clear();
+ ParsedCUOffsets.clear();
+}
+
+void DWARFDebugAranges::appendRange(uint64_t CUOffset, uint64_t LowPC,
+ uint64_t HighPC) {
+ if (LowPC >= HighPC)
+ return;
+ Endpoints.emplace_back(LowPC, CUOffset, true);
+ Endpoints.emplace_back(HighPC, CUOffset, false);
+}
+
+void DWARFDebugAranges::construct() {
+ std::multiset<uint64_t> ValidCUs; // Maintain the set of CUs describing
+ // a current address range.
+ llvm::sort(Endpoints);
+ uint64_t PrevAddress = -1ULL;
+ for (const auto &E : Endpoints) {
+ if (PrevAddress < E.Address && !ValidCUs.empty()) {
+ // If the address range between two endpoints is described by some
+ // CU, first try to extend the last range in Aranges. If we can't
+ // do it, start a new range.
+ if (!Aranges.empty() && Aranges.back().HighPC() == PrevAddress &&
+ ValidCUs.find(Aranges.back().CUOffset) != ValidCUs.end()) {
+ Aranges.back().setHighPC(E.Address);
+ } else {
+ Aranges.emplace_back(PrevAddress, E.Address, *ValidCUs.begin());
+ }
+ }
+ // Update the set of valid CUs.
+ if (E.IsRangeStart) {
+ ValidCUs.insert(E.CUOffset);
+ } else {
+ auto CUPos = ValidCUs.find(E.CUOffset);
+ assert(CUPos != ValidCUs.end());
+ ValidCUs.erase(CUPos);
+ }
+ PrevAddress = E.Address;
+ }
+ assert(ValidCUs.empty());
+
+ // Endpoints are not needed now.
+ Endpoints.clear();
+ Endpoints.shrink_to_fit();
+}
+
+uint64_t DWARFDebugAranges::findAddress(uint64_t Address) const {
+ RangeCollIterator It =
+ partition_point(Aranges, [=](Range R) { return R.HighPC() <= Address; });
+ if (It != Aranges.end() && It->LowPC <= Address)
+ return It->CUOffset;
+ return -1ULL;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
new file mode 100644
index 0000000000..92a461dbd9
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugFrame.cpp
@@ -0,0 +1,1251 @@
+//===- DWARFDebugFrame.h - Parsing of .debug_frame ------------------------===//
+//
+// 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/DWARF/DWARFDebugFrame.h"
+#include "llvm/ADT/DenseMap.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cinttypes>
+#include <cstdint>
+
+using namespace llvm;
+using namespace dwarf;
+
+static void printRegister(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
+ unsigned RegNum) {
+ if (MRI) {
+ if (Optional<unsigned> LLVMRegNum = MRI->getLLVMRegNum(RegNum, IsEH)) {
+ if (const char *RegName = MRI->getName(*LLVMRegNum)) {
+ OS << RegName;
+ return;
+ }
+ }
+ }
+ OS << "reg" << RegNum;
+}
+
+UnwindLocation UnwindLocation::createUnspecified() { return {Unspecified}; }
+
+UnwindLocation UnwindLocation::createUndefined() { return {Undefined}; }
+
+UnwindLocation UnwindLocation::createSame() { return {Same}; }
+
+UnwindLocation UnwindLocation::createIsConstant(int32_t Value) {
+ return {Constant, InvalidRegisterNumber, Value, None, false};
+}
+
+UnwindLocation UnwindLocation::createIsCFAPlusOffset(int32_t Offset) {
+ return {CFAPlusOffset, InvalidRegisterNumber, Offset, None, false};
+}
+
+UnwindLocation UnwindLocation::createAtCFAPlusOffset(int32_t Offset) {
+ return {CFAPlusOffset, InvalidRegisterNumber, Offset, None, true};
+}
+
+UnwindLocation
+UnwindLocation::createIsRegisterPlusOffset(uint32_t RegNum, int32_t Offset,
+ Optional<uint32_t> AddrSpace) {
+ return {RegPlusOffset, RegNum, Offset, AddrSpace, false};
+}
+
+UnwindLocation
+UnwindLocation::createAtRegisterPlusOffset(uint32_t RegNum, int32_t Offset,
+ Optional<uint32_t> AddrSpace) {
+ return {RegPlusOffset, RegNum, Offset, AddrSpace, true};
+}
+
+UnwindLocation UnwindLocation::createIsDWARFExpression(DWARFExpression Expr) {
+ return {Expr, false};
+}
+
+UnwindLocation UnwindLocation::createAtDWARFExpression(DWARFExpression Expr) {
+ return {Expr, true};
+}
+
+void UnwindLocation::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+ bool IsEH) const {
+ if (Dereference)
+ OS << '[';
+ switch (Kind) {
+ case Unspecified:
+ OS << "unspecified";
+ break;
+ case Undefined:
+ OS << "undefined";
+ break;
+ case Same:
+ OS << "same";
+ break;
+ case CFAPlusOffset:
+ OS << "CFA";
+ if (Offset == 0)
+ break;
+ if (Offset > 0)
+ OS << "+";
+ OS << Offset;
+ break;
+ case RegPlusOffset:
+ printRegister(OS, MRI, IsEH, RegNum);
+ if (Offset == 0 && !AddrSpace)
+ break;
+ if (Offset >= 0)
+ OS << "+";
+ OS << Offset;
+ if (AddrSpace)
+ OS << " in addrspace" << *AddrSpace;
+ break;
+ case DWARFExpr:
+ Expr->print(OS, DIDumpOptions(), MRI, nullptr, IsEH);
+ break;
+ case Constant:
+ OS << Offset;
+ break;
+ }
+ if (Dereference)
+ OS << ']';
+}
+
+raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS,
+ const UnwindLocation &UL) {
+ UL.dump(OS, nullptr, false);
+ return OS;
+}
+
+bool UnwindLocation::operator==(const UnwindLocation &RHS) const {
+ if (Kind != RHS.Kind)
+ return false;
+ switch (Kind) {
+ case Unspecified:
+ case Undefined:
+ case Same:
+ return true;
+ case CFAPlusOffset:
+ return Offset == RHS.Offset && Dereference == RHS.Dereference;
+ case RegPlusOffset:
+ return RegNum == RHS.RegNum && Offset == RHS.Offset &&
+ Dereference == RHS.Dereference;
+ case DWARFExpr:
+ return *Expr == *RHS.Expr && Dereference == RHS.Dereference;
+ case Constant:
+ return Offset == RHS.Offset;
+ }
+ return false;
+}
+
+void RegisterLocations::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+ bool IsEH) const {
+ bool First = true;
+ for (const auto &RegLocPair : Locations) {
+ if (First)
+ First = false;
+ else
+ OS << ", ";
+ printRegister(OS, MRI, IsEH, RegLocPair.first);
+ OS << '=';
+ RegLocPair.second.dump(OS, MRI, IsEH);
+ }
+}
+
+raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS,
+ const RegisterLocations &RL) {
+ RL.dump(OS, nullptr, false);
+ return OS;
+}
+
+void UnwindRow::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
+ unsigned IndentLevel) const {
+ OS.indent(2 * IndentLevel);
+ if (hasAddress())
+ OS << format("0x%" PRIx64 ": ", *Address);
+ OS << "CFA=";
+ CFAValue.dump(OS, MRI, IsEH);
+ if (RegLocs.hasLocations()) {
+ OS << ": ";
+ RegLocs.dump(OS, MRI, IsEH);
+ }
+ OS << "\n";
+}
+
+raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, const UnwindRow &Row) {
+ Row.dump(OS, nullptr, false, 0);
+ return OS;
+}
+
+void UnwindTable::dump(raw_ostream &OS, const MCRegisterInfo *MRI, bool IsEH,
+ unsigned IndentLevel) const {
+ for (const UnwindRow &Row : Rows)
+ Row.dump(OS, MRI, IsEH, IndentLevel);
+}
+
+raw_ostream &llvm::dwarf::operator<<(raw_ostream &OS, const UnwindTable &Rows) {
+ Rows.dump(OS, nullptr, false, 0);
+ return OS;
+}
+
+Expected<UnwindTable> UnwindTable::create(const FDE *Fde) {
+ const CIE *Cie = Fde->getLinkedCIE();
+ if (Cie == nullptr)
+ return createStringError(errc::invalid_argument,
+ "unable to get CIE for FDE at offset 0x%" PRIx64,
+ Fde->getOffset());
+
+ // Rows will be empty if there are no CFI instructions.
+ if (Cie->cfis().empty() && Fde->cfis().empty())
+ return UnwindTable();
+
+ UnwindTable UT;
+ UnwindRow Row;
+ Row.setAddress(Fde->getInitialLocation());
+ UT.EndAddress = Fde->getInitialLocation() + Fde->getAddressRange();
+ if (Error CieError = UT.parseRows(Cie->cfis(), Row, nullptr))
+ return std::move(CieError);
+ // We need to save the initial locations of registers from the CIE parsing
+ // in case we run into DW_CFA_restore or DW_CFA_restore_extended opcodes.
+ const RegisterLocations InitialLocs = Row.getRegisterLocations();
+ if (Error FdeError = UT.parseRows(Fde->cfis(), Row, &InitialLocs))
+ return std::move(FdeError);
+ // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty.
+ // Do not add that to the unwind table.
+ if (Row.getRegisterLocations().hasLocations() ||
+ Row.getCFAValue().getLocation() != UnwindLocation::Unspecified)
+ UT.Rows.push_back(Row);
+ return UT;
+}
+
+Expected<UnwindTable> UnwindTable::create(const CIE *Cie) {
+ // Rows will be empty if there are no CFI instructions.
+ if (Cie->cfis().empty())
+ return UnwindTable();
+
+ UnwindTable UT;
+ UnwindRow Row;
+ if (Error CieError = UT.parseRows(Cie->cfis(), Row, nullptr))
+ return std::move(CieError);
+ // May be all the CFI instructions were DW_CFA_nop amd Row becomes empty.
+ // Do not add that to the unwind table.
+ if (Row.getRegisterLocations().hasLocations() ||
+ Row.getCFAValue().getLocation() != UnwindLocation::Unspecified)
+ UT.Rows.push_back(Row);
+ return UT;
+}
+
+// See DWARF standard v3, section 7.23
+const uint8_t DWARF_CFI_PRIMARY_OPCODE_MASK = 0xc0;
+const uint8_t DWARF_CFI_PRIMARY_OPERAND_MASK = 0x3f;
+
+Error CFIProgram::parse(DWARFDataExtractor Data, uint64_t *Offset,
+ uint64_t EndOffset) {
+ DataExtractor::Cursor C(*Offset);
+ while (C && C.tell() < EndOffset) {
+ uint8_t Opcode = Data.getRelocatedValue(C, 1);
+ if (!C)
+ break;
+
+ // Some instructions have a primary opcode encoded in the top bits.
+ if (uint8_t Primary = Opcode & DWARF_CFI_PRIMARY_OPCODE_MASK) {
+ // If it's a primary opcode, the first operand is encoded in the bottom
+ // bits of the opcode itself.
+ uint64_t Op1 = Opcode & DWARF_CFI_PRIMARY_OPERAND_MASK;
+ switch (Primary) {
+ case DW_CFA_advance_loc:
+ case DW_CFA_restore:
+ addInstruction(Primary, Op1);
+ break;
+ case DW_CFA_offset:
+ addInstruction(Primary, Op1, Data.getULEB128(C));
+ break;
+ default:
+ llvm_unreachable("invalid primary CFI opcode");
+ }
+ continue;
+ }
+
+ // Extended opcode - its value is Opcode itself.
+ switch (Opcode) {
+ default:
+ return createStringError(errc::illegal_byte_sequence,
+ "invalid extended CFI opcode 0x%" PRIx8, Opcode);
+ case DW_CFA_nop:
+ case DW_CFA_remember_state:
+ case DW_CFA_restore_state:
+ case DW_CFA_GNU_window_save:
+ // No operands
+ addInstruction(Opcode);
+ break;
+ case DW_CFA_set_loc:
+ // Operands: Address
+ addInstruction(Opcode, Data.getRelocatedAddress(C));
+ break;
+ case DW_CFA_advance_loc1:
+ // Operands: 1-byte delta
+ addInstruction(Opcode, Data.getRelocatedValue(C, 1));
+ break;
+ case DW_CFA_advance_loc2:
+ // Operands: 2-byte delta
+ addInstruction(Opcode, Data.getRelocatedValue(C, 2));
+ break;
+ case DW_CFA_advance_loc4:
+ // Operands: 4-byte delta
+ addInstruction(Opcode, Data.getRelocatedValue(C, 4));
+ break;
+ case DW_CFA_restore_extended:
+ case DW_CFA_undefined:
+ case DW_CFA_same_value:
+ case DW_CFA_def_cfa_register:
+ case DW_CFA_def_cfa_offset:
+ case DW_CFA_GNU_args_size:
+ // Operands: ULEB128
+ addInstruction(Opcode, Data.getULEB128(C));
+ break;
+ case DW_CFA_def_cfa_offset_sf:
+ // Operands: SLEB128
+ addInstruction(Opcode, Data.getSLEB128(C));
+ break;
+ case DW_CFA_LLVM_def_aspace_cfa:
+ case DW_CFA_LLVM_def_aspace_cfa_sf: {
+ auto RegNum = Data.getULEB128(C);
+ auto CfaOffset = Opcode == DW_CFA_LLVM_def_aspace_cfa
+ ? Data.getULEB128(C)
+ : Data.getSLEB128(C);
+ auto AddressSpace = Data.getULEB128(C);
+ addInstruction(Opcode, RegNum, CfaOffset, AddressSpace);
+ break;
+ }
+ case DW_CFA_offset_extended:
+ case DW_CFA_register:
+ case DW_CFA_def_cfa:
+ case DW_CFA_val_offset: {
+ // Operands: ULEB128, ULEB128
+ // Note: We can not embed getULEB128 directly into function
+ // argument list. getULEB128 changes Offset and order of evaluation
+ // for arguments is unspecified.
+ uint64_t op1 = Data.getULEB128(C);
+ uint64_t op2 = Data.getULEB128(C);
+ addInstruction(Opcode, op1, op2);
+ break;
+ }
+ case DW_CFA_offset_extended_sf:
+ case DW_CFA_def_cfa_sf:
+ case DW_CFA_val_offset_sf: {
+ // Operands: ULEB128, SLEB128
+ // Note: see comment for the previous case
+ uint64_t op1 = Data.getULEB128(C);
+ uint64_t op2 = (uint64_t)Data.getSLEB128(C);
+ addInstruction(Opcode, op1, op2);
+ break;
+ }
+ case DW_CFA_def_cfa_expression: {
+ uint64_t ExprLength = Data.getULEB128(C);
+ addInstruction(Opcode, 0);
+ StringRef Expression = Data.getBytes(C, ExprLength);
+
+ DataExtractor Extractor(Expression, Data.isLittleEndian(),
+ Data.getAddressSize());
+ // Note. We do not pass the DWARF format to DWARFExpression, because
+ // DW_OP_call_ref, the only operation which depends on the format, is
+ // prohibited in call frame instructions, see sec. 6.4.2 in DWARFv5.
+ Instructions.back().Expression =
+ DWARFExpression(Extractor, Data.getAddressSize());
+ break;
+ }
+ case DW_CFA_expression:
+ case DW_CFA_val_expression: {
+ uint64_t RegNum = Data.getULEB128(C);
+ addInstruction(Opcode, RegNum, 0);
+
+ uint64_t BlockLength = Data.getULEB128(C);
+ StringRef Expression = Data.getBytes(C, BlockLength);
+ DataExtractor Extractor(Expression, Data.isLittleEndian(),
+ Data.getAddressSize());
+ // Note. We do not pass the DWARF format to DWARFExpression, because
+ // DW_OP_call_ref, the only operation which depends on the format, is
+ // prohibited in call frame instructions, see sec. 6.4.2 in DWARFv5.
+ Instructions.back().Expression =
+ DWARFExpression(Extractor, Data.getAddressSize());
+ break;
+ }
+ }
+ }
+
+ *Offset = C.tell();
+ return C.takeError();
+}
+
+StringRef CFIProgram::callFrameString(unsigned Opcode) const {
+ return dwarf::CallFrameString(Opcode, Arch);
+}
+
+const char *CFIProgram::operandTypeString(CFIProgram::OperandType OT) {
+#define ENUM_TO_CSTR(e) \
+ case e: \
+ return #e;
+ switch (OT) {
+ ENUM_TO_CSTR(OT_Unset);
+ ENUM_TO_CSTR(OT_None);
+ ENUM_TO_CSTR(OT_Address);
+ ENUM_TO_CSTR(OT_Offset);
+ ENUM_TO_CSTR(OT_FactoredCodeOffset);
+ ENUM_TO_CSTR(OT_SignedFactDataOffset);
+ ENUM_TO_CSTR(OT_UnsignedFactDataOffset);
+ ENUM_TO_CSTR(OT_Register);
+ ENUM_TO_CSTR(OT_AddressSpace);
+ ENUM_TO_CSTR(OT_Expression);
+ }
+ return "<unknown CFIProgram::OperandType>";
+}
+
+llvm::Expected<uint64_t>
+CFIProgram::Instruction::getOperandAsUnsigned(const CFIProgram &CFIP,
+ uint32_t OperandIdx) const {
+ if (OperandIdx >= MaxOperands)
+ return createStringError(errc::invalid_argument,
+ "operand index %" PRIu32 " is not valid",
+ OperandIdx);
+ OperandType Type = CFIP.getOperandTypes()[Opcode][OperandIdx];
+ uint64_t Operand = Ops[OperandIdx];
+ switch (Type) {
+ case OT_Unset:
+ case OT_None:
+ case OT_Expression:
+ return createStringError(errc::invalid_argument,
+ "op[%" PRIu32 "] has type %s which has no value",
+ OperandIdx, CFIProgram::operandTypeString(Type));
+
+ case OT_Offset:
+ case OT_SignedFactDataOffset:
+ case OT_UnsignedFactDataOffset:
+ return createStringError(
+ errc::invalid_argument,
+ "op[%" PRIu32 "] has OperandType OT_Offset which produces a signed "
+ "result, call getOperandAsSigned instead",
+ OperandIdx);
+
+ case OT_Address:
+ case OT_Register:
+ case OT_AddressSpace:
+ return Operand;
+
+ case OT_FactoredCodeOffset: {
+ const uint64_t CodeAlignmentFactor = CFIP.codeAlign();
+ if (CodeAlignmentFactor == 0)
+ return createStringError(
+ errc::invalid_argument,
+ "op[%" PRIu32 "] has type OT_FactoredCodeOffset but code alignment "
+ "is zero",
+ OperandIdx);
+ return Operand * CodeAlignmentFactor;
+ }
+ }
+ llvm_unreachable("invalid operand type");
+}
+
+llvm::Expected<int64_t>
+CFIProgram::Instruction::getOperandAsSigned(const CFIProgram &CFIP,
+ uint32_t OperandIdx) const {
+ if (OperandIdx >= MaxOperands)
+ return createStringError(errc::invalid_argument,
+ "operand index %" PRIu32 " is not valid",
+ OperandIdx);
+ OperandType Type = CFIP.getOperandTypes()[Opcode][OperandIdx];
+ uint64_t Operand = Ops[OperandIdx];
+ switch (Type) {
+ case OT_Unset:
+ case OT_None:
+ case OT_Expression:
+ return createStringError(errc::invalid_argument,
+ "op[%" PRIu32 "] has type %s which has no value",
+ OperandIdx, CFIProgram::operandTypeString(Type));
+
+ case OT_Address:
+ case OT_Register:
+ case OT_AddressSpace:
+ return createStringError(
+ errc::invalid_argument,
+ "op[%" PRIu32 "] has OperandType %s which produces an unsigned result, "
+ "call getOperandAsUnsigned instead",
+ OperandIdx, CFIProgram::operandTypeString(Type));
+
+ case OT_Offset:
+ return (int64_t)Operand;
+
+ case OT_FactoredCodeOffset:
+ case OT_SignedFactDataOffset: {
+ const int64_t DataAlignmentFactor = CFIP.dataAlign();
+ if (DataAlignmentFactor == 0)
+ return createStringError(errc::invalid_argument,
+ "op[%" PRIu32 "] has type %s but data "
+ "alignment is zero",
+ OperandIdx, CFIProgram::operandTypeString(Type));
+ return int64_t(Operand) * DataAlignmentFactor;
+ }
+
+ case OT_UnsignedFactDataOffset: {
+ const int64_t DataAlignmentFactor = CFIP.dataAlign();
+ if (DataAlignmentFactor == 0)
+ return createStringError(errc::invalid_argument,
+ "op[%" PRIu32
+ "] has type OT_UnsignedFactDataOffset but data "
+ "alignment is zero",
+ OperandIdx);
+ return Operand * DataAlignmentFactor;
+ }
+ }
+ llvm_unreachable("invalid operand type");
+}
+
+Error UnwindTable::parseRows(const CFIProgram &CFIP, UnwindRow &Row,
+ const RegisterLocations *InitialLocs) {
+ std::vector<RegisterLocations> RegisterStates;
+ for (const CFIProgram::Instruction &Inst : CFIP) {
+ switch (Inst.Opcode) {
+ case dwarf::DW_CFA_set_loc: {
+ // The DW_CFA_set_loc instruction takes a single operand that
+ // represents a target address. The required action is to create a new
+ // table row using the specified address as the location. All other
+ // values in the new row are initially identical to the current row.
+ // The new location value is always greater than the current one. If
+ // the segment_size field of this FDE's CIE is non- zero, the initial
+ // location is preceded by a segment selector of the given length
+ llvm::Expected<uint64_t> NewAddress = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!NewAddress)
+ return NewAddress.takeError();
+ if (*NewAddress <= Row.getAddress())
+ return createStringError(
+ errc::invalid_argument,
+ "%s with adrress 0x%" PRIx64 " which must be greater than the "
+ "current row address 0x%" PRIx64,
+ CFIP.callFrameString(Inst.Opcode).str().c_str(), *NewAddress,
+ Row.getAddress());
+ Rows.push_back(Row);
+ Row.setAddress(*NewAddress);
+ break;
+ }
+
+ case dwarf::DW_CFA_advance_loc:
+ case dwarf::DW_CFA_advance_loc1:
+ case dwarf::DW_CFA_advance_loc2:
+ case dwarf::DW_CFA_advance_loc4: {
+ // The DW_CFA_advance instruction takes a single operand that
+ // represents a constant delta. The required action is to create a new
+ // table row with a location value that is computed by taking the
+ // current entry’s location value and adding the value of delta *
+ // code_alignment_factor. All other values in the new row are initially
+ // identical to the current row.
+ Rows.push_back(Row);
+ llvm::Expected<uint64_t> Offset = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!Offset)
+ return Offset.takeError();
+ Row.slideAddress(*Offset);
+ break;
+ }
+
+ case dwarf::DW_CFA_restore:
+ case dwarf::DW_CFA_restore_extended: {
+ // The DW_CFA_restore instruction takes a single operand (encoded with
+ // the opcode) that represents a register number. The required action
+ // is to change the rule for the indicated register to the rule
+ // assigned it by the initial_instructions in the CIE.
+ if (InitialLocs == nullptr)
+ return createStringError(
+ errc::invalid_argument, "%s encountered while parsing a CIE",
+ CFIP.callFrameString(Inst.Opcode).str().c_str());
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ if (Optional<UnwindLocation> O =
+ InitialLocs->getRegisterLocation(*RegNum))
+ Row.getRegisterLocations().setRegisterLocation(*RegNum, *O);
+ else
+ Row.getRegisterLocations().removeRegisterLocation(*RegNum);
+ break;
+ }
+
+ case dwarf::DW_CFA_offset:
+ case dwarf::DW_CFA_offset_extended:
+ case dwarf::DW_CFA_offset_extended_sf: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
+ if (!Offset)
+ return Offset.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createAtCFAPlusOffset(*Offset));
+ break;
+ }
+
+ case dwarf::DW_CFA_nop:
+ break;
+
+ case dwarf::DW_CFA_remember_state:
+ RegisterStates.push_back(Row.getRegisterLocations());
+ break;
+
+ case dwarf::DW_CFA_restore_state:
+ if (RegisterStates.empty())
+ return createStringError(errc::invalid_argument,
+ "DW_CFA_restore_state without a matching "
+ "previous DW_CFA_remember_state");
+ Row.getRegisterLocations() = RegisterStates.back();
+ RegisterStates.pop_back();
+ break;
+
+ case dwarf::DW_CFA_GNU_window_save:
+ switch (CFIP.triple()) {
+ case Triple::aarch64:
+ case Triple::aarch64_be:
+ case Triple::aarch64_32: {
+ // DW_CFA_GNU_window_save is used for different things on different
+ // architectures. For aarch64 it is known as
+ // DW_CFA_AARCH64_negate_ra_state. The action is to toggle the
+ // value of the return address state between 1 and 0. If there is
+ // no rule for the AARCH64_DWARF_PAUTH_RA_STATE register, then it
+ // should be initially set to 1.
+ constexpr uint32_t AArch64DWARFPAuthRaState = 34;
+ auto LRLoc = Row.getRegisterLocations().getRegisterLocation(
+ AArch64DWARFPAuthRaState);
+ if (LRLoc) {
+ if (LRLoc->getLocation() == UnwindLocation::Constant) {
+ // Toggle the constant value from 0 to 1 or 1 to 0.
+ LRLoc->setConstant(LRLoc->getConstant() ^ 1);
+ } else {
+ return createStringError(
+ errc::invalid_argument,
+ "%s encountered when existing rule for this register is not "
+ "a constant",
+ CFIP.callFrameString(Inst.Opcode).str().c_str());
+ }
+ } else {
+ Row.getRegisterLocations().setRegisterLocation(
+ AArch64DWARFPAuthRaState, UnwindLocation::createIsConstant(1));
+ }
+ break;
+ }
+
+ case Triple::sparc:
+ case Triple::sparcv9:
+ case Triple::sparcel:
+ for (uint32_t RegNum = 16; RegNum < 32; ++RegNum) {
+ Row.getRegisterLocations().setRegisterLocation(
+ RegNum, UnwindLocation::createAtCFAPlusOffset((RegNum - 16) * 8));
+ }
+ break;
+
+ default: {
+ return createStringError(
+ errc::not_supported,
+ "DW_CFA opcode %#x is not supported for architecture %s",
+ Inst.Opcode, Triple::getArchTypeName(CFIP.triple()).str().c_str());
+
+ break;
+ }
+ }
+ break;
+
+ case dwarf::DW_CFA_undefined: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createUndefined());
+ break;
+ }
+
+ case dwarf::DW_CFA_same_value: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createSame());
+ break;
+ }
+
+ case dwarf::DW_CFA_GNU_args_size:
+ break;
+
+ case dwarf::DW_CFA_register: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ llvm::Expected<uint64_t> NewRegNum = Inst.getOperandAsUnsigned(CFIP, 1);
+ if (!NewRegNum)
+ return NewRegNum.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createIsRegisterPlusOffset(*NewRegNum, 0));
+ break;
+ }
+
+ case dwarf::DW_CFA_val_offset:
+ case dwarf::DW_CFA_val_offset_sf: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
+ if (!Offset)
+ return Offset.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createIsCFAPlusOffset(*Offset));
+ break;
+ }
+
+ case dwarf::DW_CFA_expression: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createAtDWARFExpression(*Inst.Expression));
+ break;
+ }
+
+ case dwarf::DW_CFA_val_expression: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ Row.getRegisterLocations().setRegisterLocation(
+ *RegNum, UnwindLocation::createIsDWARFExpression(*Inst.Expression));
+ break;
+ }
+
+ case dwarf::DW_CFA_def_cfa_register: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ if (Row.getCFAValue().getLocation() != UnwindLocation::RegPlusOffset)
+ Row.getCFAValue() =
+ UnwindLocation::createIsRegisterPlusOffset(*RegNum, 0);
+ else
+ Row.getCFAValue().setRegister(*RegNum);
+ break;
+ }
+
+ case dwarf::DW_CFA_def_cfa_offset:
+ case dwarf::DW_CFA_def_cfa_offset_sf: {
+ llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 0);
+ if (!Offset)
+ return Offset.takeError();
+ if (Row.getCFAValue().getLocation() != UnwindLocation::RegPlusOffset) {
+ return createStringError(
+ errc::invalid_argument,
+ "%s found when CFA rule was not RegPlusOffset",
+ CFIP.callFrameString(Inst.Opcode).str().c_str());
+ }
+ Row.getCFAValue().setOffset(*Offset);
+ break;
+ }
+
+ case dwarf::DW_CFA_def_cfa:
+ case dwarf::DW_CFA_def_cfa_sf: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
+ if (!Offset)
+ return Offset.takeError();
+ Row.getCFAValue() =
+ UnwindLocation::createIsRegisterPlusOffset(*RegNum, *Offset);
+ break;
+ }
+
+ case dwarf::DW_CFA_LLVM_def_aspace_cfa:
+ case dwarf::DW_CFA_LLVM_def_aspace_cfa_sf: {
+ llvm::Expected<uint64_t> RegNum = Inst.getOperandAsUnsigned(CFIP, 0);
+ if (!RegNum)
+ return RegNum.takeError();
+ llvm::Expected<int64_t> Offset = Inst.getOperandAsSigned(CFIP, 1);
+ if (!Offset)
+ return Offset.takeError();
+ llvm::Expected<uint32_t> CFAAddrSpace =
+ Inst.getOperandAsUnsigned(CFIP, 2);
+ if (!CFAAddrSpace)
+ return CFAAddrSpace.takeError();
+ Row.getCFAValue() = UnwindLocation::createIsRegisterPlusOffset(
+ *RegNum, *Offset, *CFAAddrSpace);
+ break;
+ }
+
+ case dwarf::DW_CFA_def_cfa_expression:
+ Row.getCFAValue() =
+ UnwindLocation::createIsDWARFExpression(*Inst.Expression);
+ break;
+ }
+ }
+ return Error::success();
+}
+
+ArrayRef<CFIProgram::OperandType[CFIProgram::MaxOperands]>
+CFIProgram::getOperandTypes() {
+ static OperandType OpTypes[DW_CFA_restore + 1][MaxOperands];
+ static bool Initialized = false;
+ if (Initialized) {
+ return ArrayRef<OperandType[MaxOperands]>(&OpTypes[0], DW_CFA_restore + 1);
+ }
+ Initialized = true;
+
+#define DECLARE_OP3(OP, OPTYPE0, OPTYPE1, OPTYPE2) \
+ do { \
+ OpTypes[OP][0] = OPTYPE0; \
+ OpTypes[OP][1] = OPTYPE1; \
+ OpTypes[OP][2] = OPTYPE2; \
+ } while (false)
+#define DECLARE_OP2(OP, OPTYPE0, OPTYPE1) \
+ DECLARE_OP3(OP, OPTYPE0, OPTYPE1, OT_None)
+#define DECLARE_OP1(OP, OPTYPE0) DECLARE_OP2(OP, OPTYPE0, OT_None)
+#define DECLARE_OP0(OP) DECLARE_OP1(OP, OT_None)
+
+ DECLARE_OP1(DW_CFA_set_loc, OT_Address);
+ DECLARE_OP1(DW_CFA_advance_loc, OT_FactoredCodeOffset);
+ DECLARE_OP1(DW_CFA_advance_loc1, OT_FactoredCodeOffset);
+ DECLARE_OP1(DW_CFA_advance_loc2, OT_FactoredCodeOffset);
+ DECLARE_OP1(DW_CFA_advance_loc4, OT_FactoredCodeOffset);
+ DECLARE_OP1(DW_CFA_MIPS_advance_loc8, OT_FactoredCodeOffset);
+ DECLARE_OP2(DW_CFA_def_cfa, OT_Register, OT_Offset);
+ DECLARE_OP2(DW_CFA_def_cfa_sf, OT_Register, OT_SignedFactDataOffset);
+ DECLARE_OP1(DW_CFA_def_cfa_register, OT_Register);
+ DECLARE_OP3(DW_CFA_LLVM_def_aspace_cfa, OT_Register, OT_Offset,
+ OT_AddressSpace);
+ DECLARE_OP3(DW_CFA_LLVM_def_aspace_cfa_sf, OT_Register,
+ OT_SignedFactDataOffset, OT_AddressSpace);
+ DECLARE_OP1(DW_CFA_def_cfa_offset, OT_Offset);
+ DECLARE_OP1(DW_CFA_def_cfa_offset_sf, OT_SignedFactDataOffset);
+ DECLARE_OP1(DW_CFA_def_cfa_expression, OT_Expression);
+ DECLARE_OP1(DW_CFA_undefined, OT_Register);
+ DECLARE_OP1(DW_CFA_same_value, OT_Register);
+ DECLARE_OP2(DW_CFA_offset, OT_Register, OT_UnsignedFactDataOffset);
+ DECLARE_OP2(DW_CFA_offset_extended, OT_Register, OT_UnsignedFactDataOffset);
+ DECLARE_OP2(DW_CFA_offset_extended_sf, OT_Register, OT_SignedFactDataOffset);
+ DECLARE_OP2(DW_CFA_val_offset, OT_Register, OT_UnsignedFactDataOffset);
+ DECLARE_OP2(DW_CFA_val_offset_sf, OT_Register, OT_SignedFactDataOffset);
+ DECLARE_OP2(DW_CFA_register, OT_Register, OT_Register);
+ DECLARE_OP2(DW_CFA_expression, OT_Register, OT_Expression);
+ DECLARE_OP2(DW_CFA_val_expression, OT_Register, OT_Expression);
+ DECLARE_OP1(DW_CFA_restore, OT_Register);
+ DECLARE_OP1(DW_CFA_restore_extended, OT_Register);
+ DECLARE_OP0(DW_CFA_remember_state);
+ DECLARE_OP0(DW_CFA_restore_state);
+ DECLARE_OP0(DW_CFA_GNU_window_save);
+ DECLARE_OP1(DW_CFA_GNU_args_size, OT_Offset);
+ DECLARE_OP0(DW_CFA_nop);
+
+#undef DECLARE_OP0
+#undef DECLARE_OP1
+#undef DECLARE_OP2
+
+ return ArrayRef<OperandType[MaxOperands]>(&OpTypes[0], DW_CFA_restore + 1);
+}
+
+/// Print \p Opcode's operand number \p OperandIdx which has value \p Operand.
+void CFIProgram::printOperand(raw_ostream &OS, DIDumpOptions DumpOpts,
+ const MCRegisterInfo *MRI, bool IsEH,
+ const Instruction &Instr, unsigned OperandIdx,
+ uint64_t Operand) const {
+ assert(OperandIdx < MaxOperands);
+ uint8_t Opcode = Instr.Opcode;
+ OperandType Type = getOperandTypes()[Opcode][OperandIdx];
+
+ switch (Type) {
+ case OT_Unset: {
+ OS << " Unsupported " << (OperandIdx ? "second" : "first") << " operand to";
+ auto OpcodeName = callFrameString(Opcode);
+ if (!OpcodeName.empty())
+ OS << " " << OpcodeName;
+ else
+ OS << format(" Opcode %x", Opcode);
+ break;
+ }
+ case OT_None:
+ break;
+ case OT_Address:
+ OS << format(" %" PRIx64, Operand);
+ break;
+ case OT_Offset:
+ // The offsets are all encoded in a unsigned form, but in practice
+ // consumers use them signed. It's most certainly legacy due to
+ // the lack of signed variants in the first Dwarf standards.
+ OS << format(" %+" PRId64, int64_t(Operand));
+ break;
+ case OT_FactoredCodeOffset: // Always Unsigned
+ if (CodeAlignmentFactor)
+ OS << format(" %" PRId64, Operand * CodeAlignmentFactor);
+ else
+ OS << format(" %" PRId64 "*code_alignment_factor" , Operand);
+ break;
+ case OT_SignedFactDataOffset:
+ if (DataAlignmentFactor)
+ OS << format(" %" PRId64, int64_t(Operand) * DataAlignmentFactor);
+ else
+ OS << format(" %" PRId64 "*data_alignment_factor" , int64_t(Operand));
+ break;
+ case OT_UnsignedFactDataOffset:
+ if (DataAlignmentFactor)
+ OS << format(" %" PRId64, Operand * DataAlignmentFactor);
+ else
+ OS << format(" %" PRId64 "*data_alignment_factor" , Operand);
+ break;
+ case OT_Register:
+ OS << ' ';
+ printRegister(OS, MRI, IsEH, Operand);
+ break;
+ case OT_AddressSpace:
+ OS << format(" in addrspace%" PRId64, Operand);
+ break;
+ case OT_Expression:
+ assert(Instr.Expression && "missing DWARFExpression object");
+ OS << " ";
+ Instr.Expression->print(OS, DumpOpts, MRI, nullptr, IsEH);
+ break;
+ }
+}
+
+void CFIProgram::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
+ const MCRegisterInfo *MRI, bool IsEH,
+ unsigned IndentLevel) const {
+ for (const auto &Instr : Instructions) {
+ uint8_t Opcode = Instr.Opcode;
+ OS.indent(2 * IndentLevel);
+ OS << callFrameString(Opcode) << ":";
+ for (unsigned i = 0; i < Instr.Ops.size(); ++i)
+ printOperand(OS, DumpOpts, MRI, IsEH, Instr, i, Instr.Ops[i]);
+ OS << '\n';
+ }
+}
+
+// Returns the CIE identifier to be used by the requested format.
+// CIE ids for .debug_frame sections are defined in Section 7.24 of DWARFv5.
+// For CIE ID in .eh_frame sections see
+// https://refspecs.linuxfoundation.org/LSB_5.0.0/LSB-Core-generic/LSB-Core-generic/ehframechpt.html
+constexpr uint64_t getCIEId(bool IsDWARF64, bool IsEH) {
+ if (IsEH)
+ return 0;
+ if (IsDWARF64)
+ return DW64_CIE_ID;
+ return DW_CIE_ID;
+}
+
+void CIE::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
+ const MCRegisterInfo *MRI, bool IsEH) const {
+ // A CIE with a zero length is a terminator entry in the .eh_frame section.
+ if (IsEH && Length == 0) {
+ OS << format("%08" PRIx64, Offset) << " ZERO terminator\n";
+ return;
+ }
+
+ OS << format("%08" PRIx64, Offset)
+ << format(" %0*" PRIx64, IsDWARF64 ? 16 : 8, Length)
+ << format(" %0*" PRIx64, IsDWARF64 && !IsEH ? 16 : 8,
+ getCIEId(IsDWARF64, IsEH))
+ << " CIE\n"
+ << " Format: " << FormatString(IsDWARF64) << "\n";
+ if (IsEH && Version != 1)
+ OS << "WARNING: unsupported CIE version\n";
+ OS << format(" Version: %d\n", Version)
+ << " Augmentation: \"" << Augmentation << "\"\n";
+ if (Version >= 4) {
+ OS << format(" Address size: %u\n", (uint32_t)AddressSize);
+ OS << format(" Segment desc size: %u\n",
+ (uint32_t)SegmentDescriptorSize);
+ }
+ OS << format(" Code alignment factor: %u\n", (uint32_t)CodeAlignmentFactor);
+ OS << format(" Data alignment factor: %d\n", (int32_t)DataAlignmentFactor);
+ OS << format(" Return address column: %d\n", (int32_t)ReturnAddressRegister);
+ if (Personality)
+ OS << format(" Personality Address: %016" PRIx64 "\n", *Personality);
+ if (!AugmentationData.empty()) {
+ OS << " Augmentation data: ";
+ for (uint8_t Byte : AugmentationData)
+ OS << ' ' << hexdigit(Byte >> 4) << hexdigit(Byte & 0xf);
+ OS << "\n";
+ }
+ OS << "\n";
+ CFIs.dump(OS, DumpOpts, MRI, IsEH);
+ OS << "\n";
+
+ if (Expected<UnwindTable> RowsOrErr = UnwindTable::create(this))
+ RowsOrErr->dump(OS, MRI, IsEH, 1);
+ else {
+ DumpOpts.RecoverableErrorHandler(joinErrors(
+ createStringError(errc::invalid_argument,
+ "decoding the CIE opcodes into rows failed"),
+ RowsOrErr.takeError()));
+ }
+ OS << "\n";
+}
+
+void FDE::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
+ const MCRegisterInfo *MRI, bool IsEH) const {
+ OS << format("%08" PRIx64, Offset)
+ << format(" %0*" PRIx64, IsDWARF64 ? 16 : 8, Length)
+ << format(" %0*" PRIx64, IsDWARF64 && !IsEH ? 16 : 8, CIEPointer)
+ << " FDE cie=";
+ if (LinkedCIE)
+ OS << format("%08" PRIx64, LinkedCIE->getOffset());
+ else
+ OS << "<invalid offset>";
+ OS << format(" pc=%08" PRIx64 "...%08" PRIx64 "\n", InitialLocation,
+ InitialLocation + AddressRange);
+ OS << " Format: " << FormatString(IsDWARF64) << "\n";
+ if (LSDAAddress)
+ OS << format(" LSDA Address: %016" PRIx64 "\n", *LSDAAddress);
+ CFIs.dump(OS, DumpOpts, MRI, IsEH);
+ OS << "\n";
+
+ if (Expected<UnwindTable> RowsOrErr = UnwindTable::create(this))
+ RowsOrErr->dump(OS, MRI, IsEH, 1);
+ else {
+ DumpOpts.RecoverableErrorHandler(joinErrors(
+ createStringError(errc::invalid_argument,
+ "decoding the FDE opcodes into rows failed"),
+ RowsOrErr.takeError()));
+ }
+ OS << "\n";
+}
+
+DWARFDebugFrame::DWARFDebugFrame(Triple::ArchType Arch,
+ bool IsEH, uint64_t EHFrameAddress)
+ : Arch(Arch), IsEH(IsEH), EHFrameAddress(EHFrameAddress) {}
+
+DWARFDebugFrame::~DWARFDebugFrame() = default;
+
+static void LLVM_ATTRIBUTE_UNUSED dumpDataAux(DataExtractor Data,
+ uint64_t Offset, int Length) {
+ errs() << "DUMP: ";
+ for (int i = 0; i < Length; ++i) {
+ uint8_t c = Data.getU8(&Offset);
+ errs().write_hex(c); errs() << " ";
+ }
+ errs() << "\n";
+}
+
+Error DWARFDebugFrame::parse(DWARFDataExtractor Data) {
+ uint64_t Offset = 0;
+ DenseMap<uint64_t, CIE *> CIEs;
+
+ while (Data.isValidOffset(Offset)) {
+ uint64_t StartOffset = Offset;
+
+ uint64_t Length;
+ DwarfFormat Format;
+ std::tie(Length, Format) = Data.getInitialLength(&Offset);
+ bool IsDWARF64 = Format == DWARF64;
+
+ // If the Length is 0, then this CIE is a terminator. We add it because some
+ // dumper tools might need it to print something special for such entries
+ // (e.g. llvm-objdump --dwarf=frames prints "ZERO terminator").
+ if (Length == 0) {
+ auto Cie = std::make_unique<CIE>(
+ IsDWARF64, StartOffset, 0, 0, SmallString<8>(), 0, 0, 0, 0, 0,
+ SmallString<8>(), 0, 0, None, None, Arch);
+ CIEs[StartOffset] = Cie.get();
+ Entries.push_back(std::move(Cie));
+ break;
+ }
+
+ // At this point, Offset points to the next field after Length.
+ // Length is the structure size excluding itself. Compute an offset one
+ // past the end of the structure (needed to know how many instructions to
+ // read).
+ uint64_t StartStructureOffset = Offset;
+ uint64_t EndStructureOffset = Offset + Length;
+
+ // The Id field's size depends on the DWARF format
+ Error Err = Error::success();
+ uint64_t Id = Data.getRelocatedValue((IsDWARF64 && !IsEH) ? 8 : 4, &Offset,
+ /*SectionIndex=*/nullptr, &Err);
+ if (Err)
+ return Err;
+
+ if (Id == getCIEId(IsDWARF64, IsEH)) {
+ uint8_t Version = Data.getU8(&Offset);
+ const char *Augmentation = Data.getCStr(&Offset);
+ StringRef AugmentationString(Augmentation ? Augmentation : "");
+ uint8_t AddressSize = Version < 4 ? Data.getAddressSize() :
+ Data.getU8(&Offset);
+ Data.setAddressSize(AddressSize);
+ uint8_t SegmentDescriptorSize = Version < 4 ? 0 : Data.getU8(&Offset);
+ uint64_t CodeAlignmentFactor = Data.getULEB128(&Offset);
+ int64_t DataAlignmentFactor = Data.getSLEB128(&Offset);
+ uint64_t ReturnAddressRegister =
+ Version == 1 ? Data.getU8(&Offset) : Data.getULEB128(&Offset);
+
+ // Parse the augmentation data for EH CIEs
+ StringRef AugmentationData("");
+ uint32_t FDEPointerEncoding = DW_EH_PE_absptr;
+ uint32_t LSDAPointerEncoding = DW_EH_PE_omit;
+ Optional<uint64_t> Personality;
+ Optional<uint32_t> PersonalityEncoding;
+ if (IsEH) {
+ Optional<uint64_t> AugmentationLength;
+ uint64_t StartAugmentationOffset;
+ uint64_t EndAugmentationOffset;
+
+ // Walk the augmentation string to get all the augmentation data.
+ for (unsigned i = 0, e = AugmentationString.size(); i != e; ++i) {
+ switch (AugmentationString[i]) {
+ default:
+ return createStringError(
+ errc::invalid_argument,
+ "unknown augmentation character in entry at 0x%" PRIx64,
+ StartOffset);
+ case 'L':
+ LSDAPointerEncoding = Data.getU8(&Offset);
+ break;
+ case 'P': {
+ if (Personality)
+ return createStringError(
+ errc::invalid_argument,
+ "duplicate personality in entry at 0x%" PRIx64, StartOffset);
+ PersonalityEncoding = Data.getU8(&Offset);
+ Personality = Data.getEncodedPointer(
+ &Offset, *PersonalityEncoding,
+ EHFrameAddress ? EHFrameAddress + Offset : 0);
+ break;
+ }
+ case 'R':
+ FDEPointerEncoding = Data.getU8(&Offset);
+ break;
+ case 'S':
+ // Current frame is a signal trampoline.
+ break;
+ case 'z':
+ if (i)
+ return createStringError(
+ errc::invalid_argument,
+ "'z' must be the first character at 0x%" PRIx64, StartOffset);
+ // Parse the augmentation length first. We only parse it if
+ // the string contains a 'z'.
+ AugmentationLength = Data.getULEB128(&Offset);
+ StartAugmentationOffset = Offset;
+ EndAugmentationOffset = Offset + *AugmentationLength;
+ break;
+ case 'B':
+ // B-Key is used for signing functions associated with this
+ // augmentation string
+ break;
+ }
+ }
+
+ if (AugmentationLength.hasValue()) {
+ if (Offset != EndAugmentationOffset)
+ return createStringError(errc::invalid_argument,
+ "parsing augmentation data at 0x%" PRIx64
+ " failed",
+ StartOffset);
+ AugmentationData = Data.getData().slice(StartAugmentationOffset,
+ EndAugmentationOffset);
+ }
+ }
+
+ auto Cie = std::make_unique<CIE>(
+ IsDWARF64, StartOffset, Length, Version, AugmentationString,
+ AddressSize, SegmentDescriptorSize, CodeAlignmentFactor,
+ DataAlignmentFactor, ReturnAddressRegister, AugmentationData,
+ FDEPointerEncoding, LSDAPointerEncoding, Personality,
+ PersonalityEncoding, Arch);
+ CIEs[StartOffset] = Cie.get();
+ Entries.emplace_back(std::move(Cie));
+ } else {
+ // FDE
+ uint64_t CIEPointer = Id;
+ uint64_t InitialLocation = 0;
+ uint64_t AddressRange = 0;
+ Optional<uint64_t> LSDAAddress;
+ CIE *Cie = CIEs[IsEH ? (StartStructureOffset - CIEPointer) : CIEPointer];
+
+ if (IsEH) {
+ // The address size is encoded in the CIE we reference.
+ if (!Cie)
+ return createStringError(errc::invalid_argument,
+ "parsing FDE data at 0x%" PRIx64
+ " failed due to missing CIE",
+ StartOffset);
+ if (auto Val =
+ Data.getEncodedPointer(&Offset, Cie->getFDEPointerEncoding(),
+ EHFrameAddress + Offset)) {
+ InitialLocation = *Val;
+ }
+ if (auto Val = Data.getEncodedPointer(
+ &Offset, Cie->getFDEPointerEncoding(), 0)) {
+ AddressRange = *Val;
+ }
+
+ StringRef AugmentationString = Cie->getAugmentationString();
+ if (!AugmentationString.empty()) {
+ // Parse the augmentation length and data for this FDE.
+ uint64_t AugmentationLength = Data.getULEB128(&Offset);
+
+ uint64_t EndAugmentationOffset = Offset + AugmentationLength;
+
+ // Decode the LSDA if the CIE augmentation string said we should.
+ if (Cie->getLSDAPointerEncoding() != DW_EH_PE_omit) {
+ LSDAAddress = Data.getEncodedPointer(
+ &Offset, Cie->getLSDAPointerEncoding(),
+ EHFrameAddress ? Offset + EHFrameAddress : 0);
+ }
+
+ if (Offset != EndAugmentationOffset)
+ return createStringError(errc::invalid_argument,
+ "parsing augmentation data at 0x%" PRIx64
+ " failed",
+ StartOffset);
+ }
+ } else {
+ InitialLocation = Data.getRelocatedAddress(&Offset);
+ AddressRange = Data.getRelocatedAddress(&Offset);
+ }
+
+ Entries.emplace_back(new FDE(IsDWARF64, StartOffset, Length, CIEPointer,
+ InitialLocation, AddressRange, Cie,
+ LSDAAddress, Arch));
+ }
+
+ if (Error E =
+ Entries.back()->cfis().parse(Data, &Offset, EndStructureOffset))
+ return E;
+
+ if (Offset != EndStructureOffset)
+ return createStringError(
+ errc::invalid_argument,
+ "parsing entry instructions at 0x%" PRIx64 " failed", StartOffset);
+ }
+
+ return Error::success();
+}
+
+FrameEntry *DWARFDebugFrame::getEntryAtOffset(uint64_t Offset) const {
+ auto It = partition_point(Entries, [=](const std::unique_ptr<FrameEntry> &E) {
+ return E->getOffset() < Offset;
+ });
+ if (It != Entries.end() && (*It)->getOffset() == Offset)
+ return It->get();
+ return nullptr;
+}
+
+void DWARFDebugFrame::dump(raw_ostream &OS, DIDumpOptions DumpOpts,
+ const MCRegisterInfo *MRI,
+ Optional<uint64_t> Offset) const {
+ if (Offset) {
+ if (auto *Entry = getEntryAtOffset(*Offset))
+ Entry->dump(OS, DumpOpts, MRI, IsEH);
+ return;
+ }
+
+ OS << "\n";
+ for (const auto &Entry : Entries)
+ Entry->dump(OS, DumpOpts, MRI, IsEH);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
new file mode 100644
index 0000000000..385bde51e2
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugInfoEntry.cpp
@@ -0,0 +1,94 @@
+//===- DWARFDebugInfoEntry.cpp --------------------------------------------===//
+//
+// 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/DWARF/DWARFDebugInfoEntry.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/DataExtractor.h"
+#include <cstddef>
+#include <cstdint>
+
+using namespace llvm;
+using namespace dwarf;
+
+bool DWARFDebugInfoEntry::extractFast(const DWARFUnit &U, uint64_t *OffsetPtr,
+ const DWARFDataExtractor &DebugInfoData,
+ uint64_t UEndOffset, uint32_t ParentIdx) {
+ Offset = *OffsetPtr;
+ this->ParentIdx = ParentIdx;
+ if (Offset >= UEndOffset) {
+ U.getContext().getWarningHandler()(
+ createStringError(errc::invalid_argument,
+ "DWARF unit from offset 0x%8.8" PRIx64 " incl. "
+ "to offset 0x%8.8" PRIx64 " excl. "
+ "tries to read DIEs at offset 0x%8.8" PRIx64,
+ U.getOffset(), U.getNextUnitOffset(), *OffsetPtr));
+ return false;
+ }
+ assert(DebugInfoData.isValidOffset(UEndOffset - 1));
+ uint64_t AbbrCode = DebugInfoData.getULEB128(OffsetPtr);
+ if (0 == AbbrCode) {
+ // NULL debug tag entry.
+ AbbrevDecl = nullptr;
+ return true;
+ }
+ const auto *AbbrevSet = U.getAbbreviations();
+ if (!AbbrevSet) {
+ U.getContext().getWarningHandler()(
+ createStringError(errc::invalid_argument,
+ "DWARF unit at offset 0x%8.8" PRIx64 " "
+ "contains invalid abbreviation set offset 0x%" PRIx64,
+ U.getOffset(), U.getAbbreviationsOffset()));
+ // Restore the original offset.
+ *OffsetPtr = Offset;
+ return false;
+ }
+ AbbrevDecl = AbbrevSet->getAbbreviationDeclaration(AbbrCode);
+ if (!AbbrevDecl) {
+ U.getContext().getWarningHandler()(
+ createStringError(errc::invalid_argument,
+ "DWARF unit at offset 0x%8.8" PRIx64 " "
+ "contains invalid abbreviation %" PRIu64 " at "
+ "offset 0x%8.8" PRIx64 ", valid abbreviations are %s",
+ U.getOffset(), AbbrCode, *OffsetPtr,
+ AbbrevSet->getCodeRange().c_str()));
+ // Restore the original offset.
+ *OffsetPtr = Offset;
+ return false;
+ }
+ // See if all attributes in this DIE have fixed byte sizes. If so, we can
+ // just add this size to the offset to skip to the next DIE.
+ if (Optional<size_t> FixedSize = AbbrevDecl->getFixedAttributesByteSize(U)) {
+ *OffsetPtr += *FixedSize;
+ return true;
+ }
+
+ // Skip all data in the .debug_info for the attributes
+ for (const auto &AttrSpec : AbbrevDecl->attributes()) {
+ // Check if this attribute has a fixed byte size.
+ if (auto FixedSize = AttrSpec.getByteSize(U)) {
+ // Attribute byte size if fixed, just add the size to the offset.
+ *OffsetPtr += *FixedSize;
+ } else if (!DWARFFormValue::skipValue(AttrSpec.Form, DebugInfoData,
+ OffsetPtr, U.getFormParams())) {
+ // We failed to skip this attribute's value, restore the original offset
+ // and return the failure status.
+ U.getContext().getWarningHandler()(createStringError(
+ errc::invalid_argument,
+ "DWARF unit at offset 0x%8.8" PRIx64 " "
+ "contains invalid FORM_* 0x%" PRIx16 " at offset 0x%8.8" PRIx64,
+ U.getOffset(), AttrSpec.Form, *OffsetPtr));
+ *OffsetPtr = Offset;
+ return false;
+ }
+ }
+ return true;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugLine.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
new file mode 100644
index 0000000000..f36d3f8725
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugLine.cpp
@@ -0,0 +1,1496 @@
+//===- DWARFDebugLine.cpp -------------------------------------------------===//
+//
+// 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/DWARF/DWARFDebugLine.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cinttypes>
+#include <cstdint>
+#include <cstdio>
+#include <utility>
+
+using namespace llvm;
+using namespace dwarf;
+
+using FileLineInfoKind = DILineInfoSpecifier::FileLineInfoKind;
+
+namespace {
+
+struct ContentDescriptor {
+ dwarf::LineNumberEntryFormat Type;
+ dwarf::Form Form;
+};
+
+using ContentDescriptors = SmallVector<ContentDescriptor, 4>;
+
+} // end anonymous namespace
+
+static bool versionIsSupported(uint16_t Version) {
+ return Version >= 2 && Version <= 5;
+}
+
+void DWARFDebugLine::ContentTypeTracker::trackContentType(
+ dwarf::LineNumberEntryFormat ContentType) {
+ switch (ContentType) {
+ case dwarf::DW_LNCT_timestamp:
+ HasModTime = true;
+ break;
+ case dwarf::DW_LNCT_size:
+ HasLength = true;
+ break;
+ case dwarf::DW_LNCT_MD5:
+ HasMD5 = true;
+ break;
+ case dwarf::DW_LNCT_LLVM_source:
+ HasSource = true;
+ break;
+ default:
+ // We only care about values we consider optional, and new values may be
+ // added in the vendor extension range, so we do not match exhaustively.
+ break;
+ }
+}
+
+DWARFDebugLine::Prologue::Prologue() { clear(); }
+
+bool DWARFDebugLine::Prologue::hasFileAtIndex(uint64_t FileIndex) const {
+ uint16_t DwarfVersion = getVersion();
+ assert(DwarfVersion != 0 &&
+ "line table prologue has no dwarf version information");
+ if (DwarfVersion >= 5)
+ return FileIndex < FileNames.size();
+ return FileIndex != 0 && FileIndex <= FileNames.size();
+}
+
+Optional<uint64_t> DWARFDebugLine::Prologue::getLastValidFileIndex() const {
+ if (FileNames.empty())
+ return None;
+ uint16_t DwarfVersion = getVersion();
+ assert(DwarfVersion != 0 &&
+ "line table prologue has no dwarf version information");
+ // In DWARF v5 the file names are 0-indexed.
+ if (DwarfVersion >= 5)
+ return FileNames.size() - 1;
+ return FileNames.size();
+}
+
+const llvm::DWARFDebugLine::FileNameEntry &
+DWARFDebugLine::Prologue::getFileNameEntry(uint64_t Index) const {
+ uint16_t DwarfVersion = getVersion();
+ assert(DwarfVersion != 0 &&
+ "line table prologue has no dwarf version information");
+ // In DWARF v5 the file names are 0-indexed.
+ if (DwarfVersion >= 5)
+ return FileNames[Index];
+ return FileNames[Index - 1];
+}
+
+void DWARFDebugLine::Prologue::clear() {
+ TotalLength = PrologueLength = 0;
+ SegSelectorSize = 0;
+ MinInstLength = MaxOpsPerInst = DefaultIsStmt = LineBase = LineRange = 0;
+ OpcodeBase = 0;
+ FormParams = dwarf::FormParams({0, 0, DWARF32});
+ ContentTypes = ContentTypeTracker();
+ StandardOpcodeLengths.clear();
+ IncludeDirectories.clear();
+ FileNames.clear();
+}
+
+void DWARFDebugLine::Prologue::dump(raw_ostream &OS,
+ DIDumpOptions DumpOptions) const {
+ if (!totalLengthIsValid())
+ return;
+ int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(FormParams.Format);
+ OS << "Line table prologue:\n"
+ << format(" total_length: 0x%0*" PRIx64 "\n", OffsetDumpWidth,
+ TotalLength)
+ << " format: " << dwarf::FormatString(FormParams.Format) << "\n"
+ << format(" version: %u\n", getVersion());
+ if (!versionIsSupported(getVersion()))
+ return;
+ if (getVersion() >= 5)
+ OS << format(" address_size: %u\n", getAddressSize())
+ << format(" seg_select_size: %u\n", SegSelectorSize);
+ OS << format(" prologue_length: 0x%0*" PRIx64 "\n", OffsetDumpWidth,
+ PrologueLength)
+ << format(" min_inst_length: %u\n", MinInstLength)
+ << format(getVersion() >= 4 ? "max_ops_per_inst: %u\n" : "", MaxOpsPerInst)
+ << format(" default_is_stmt: %u\n", DefaultIsStmt)
+ << format(" line_base: %i\n", LineBase)
+ << format(" line_range: %u\n", LineRange)
+ << format(" opcode_base: %u\n", OpcodeBase);
+
+ for (uint32_t I = 0; I != StandardOpcodeLengths.size(); ++I)
+ OS << formatv("standard_opcode_lengths[{0}] = {1}\n",
+ static_cast<dwarf::LineNumberOps>(I + 1),
+ StandardOpcodeLengths[I]);
+
+ if (!IncludeDirectories.empty()) {
+ // DWARF v5 starts directory indexes at 0.
+ uint32_t DirBase = getVersion() >= 5 ? 0 : 1;
+ for (uint32_t I = 0; I != IncludeDirectories.size(); ++I) {
+ OS << format("include_directories[%3u] = ", I + DirBase);
+ IncludeDirectories[I].dump(OS, DumpOptions);
+ OS << '\n';
+ }
+ }
+
+ if (!FileNames.empty()) {
+ // DWARF v5 starts file indexes at 0.
+ uint32_t FileBase = getVersion() >= 5 ? 0 : 1;
+ for (uint32_t I = 0; I != FileNames.size(); ++I) {
+ const FileNameEntry &FileEntry = FileNames[I];
+ OS << format("file_names[%3u]:\n", I + FileBase);
+ OS << " name: ";
+ FileEntry.Name.dump(OS, DumpOptions);
+ OS << '\n'
+ << format(" dir_index: %" PRIu64 "\n", FileEntry.DirIdx);
+ if (ContentTypes.HasMD5)
+ OS << " md5_checksum: " << FileEntry.Checksum.digest() << '\n';
+ if (ContentTypes.HasModTime)
+ OS << format(" mod_time: 0x%8.8" PRIx64 "\n", FileEntry.ModTime);
+ if (ContentTypes.HasLength)
+ OS << format(" length: 0x%8.8" PRIx64 "\n", FileEntry.Length);
+ if (ContentTypes.HasSource) {
+ OS << " source: ";
+ FileEntry.Source.dump(OS, DumpOptions);
+ OS << '\n';
+ }
+ }
+ }
+}
+
+// Parse v2-v4 directory and file tables.
+static Error
+parseV2DirFileTables(const DWARFDataExtractor &DebugLineData,
+ uint64_t *OffsetPtr,
+ DWARFDebugLine::ContentTypeTracker &ContentTypes,
+ std::vector<DWARFFormValue> &IncludeDirectories,
+ std::vector<DWARFDebugLine::FileNameEntry> &FileNames) {
+ while (true) {
+ Error Err = Error::success();
+ StringRef S = DebugLineData.getCStrRef(OffsetPtr, &Err);
+ if (Err) {
+ consumeError(std::move(Err));
+ return createStringError(errc::invalid_argument,
+ "include directories table was not null "
+ "terminated before the end of the prologue");
+ }
+ if (S.empty())
+ break;
+ DWARFFormValue Dir =
+ DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, S.data());
+ IncludeDirectories.push_back(Dir);
+ }
+
+ ContentTypes.HasModTime = true;
+ ContentTypes.HasLength = true;
+
+ while (true) {
+ Error Err = Error::success();
+ StringRef Name = DebugLineData.getCStrRef(OffsetPtr, &Err);
+ if (!Err && Name.empty())
+ break;
+
+ DWARFDebugLine::FileNameEntry FileEntry;
+ FileEntry.Name =
+ DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, Name.data());
+ FileEntry.DirIdx = DebugLineData.getULEB128(OffsetPtr, &Err);
+ FileEntry.ModTime = DebugLineData.getULEB128(OffsetPtr, &Err);
+ FileEntry.Length = DebugLineData.getULEB128(OffsetPtr, &Err);
+
+ if (Err) {
+ consumeError(std::move(Err));
+ return createStringError(
+ errc::invalid_argument,
+ "file names table was not null terminated before "
+ "the end of the prologue");
+ }
+ FileNames.push_back(FileEntry);
+ }
+
+ return Error::success();
+}
+
+// Parse v5 directory/file entry content descriptions.
+// Returns the descriptors, or an error if we did not find a path or ran off
+// the end of the prologue.
+static llvm::Expected<ContentDescriptors>
+parseV5EntryFormat(const DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr,
+ DWARFDebugLine::ContentTypeTracker *ContentTypes) {
+ Error Err = Error::success();
+ ContentDescriptors Descriptors;
+ int FormatCount = DebugLineData.getU8(OffsetPtr, &Err);
+ bool HasPath = false;
+ for (int I = 0; I != FormatCount && !Err; ++I) {
+ ContentDescriptor Descriptor;
+ Descriptor.Type =
+ dwarf::LineNumberEntryFormat(DebugLineData.getULEB128(OffsetPtr, &Err));
+ Descriptor.Form = dwarf::Form(DebugLineData.getULEB128(OffsetPtr, &Err));
+ if (Descriptor.Type == dwarf::DW_LNCT_path)
+ HasPath = true;
+ if (ContentTypes)
+ ContentTypes->trackContentType(Descriptor.Type);
+ Descriptors.push_back(Descriptor);
+ }
+
+ if (Err)
+ return createStringError(errc::invalid_argument,
+ "failed to parse entry content descriptors: %s",
+ toString(std::move(Err)).c_str());
+
+ if (!HasPath)
+ return createStringError(errc::invalid_argument,
+ "failed to parse entry content descriptions"
+ " because no path was found");
+ return Descriptors;
+}
+
+static Error
+parseV5DirFileTables(const DWARFDataExtractor &DebugLineData,
+ uint64_t *OffsetPtr, const dwarf::FormParams &FormParams,
+ const DWARFContext &Ctx, const DWARFUnit *U,
+ DWARFDebugLine::ContentTypeTracker &ContentTypes,
+ std::vector<DWARFFormValue> &IncludeDirectories,
+ std::vector<DWARFDebugLine::FileNameEntry> &FileNames) {
+ // Get the directory entry description.
+ llvm::Expected<ContentDescriptors> DirDescriptors =
+ parseV5EntryFormat(DebugLineData, OffsetPtr, nullptr);
+ if (!DirDescriptors)
+ return DirDescriptors.takeError();
+
+ // Get the directory entries, according to the format described above.
+ uint64_t DirEntryCount = DebugLineData.getULEB128(OffsetPtr);
+ for (uint64_t I = 0; I != DirEntryCount; ++I) {
+ for (auto Descriptor : *DirDescriptors) {
+ DWARFFormValue Value(Descriptor.Form);
+ switch (Descriptor.Type) {
+ case DW_LNCT_path:
+ if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U))
+ return createStringError(errc::invalid_argument,
+ "failed to parse directory entry because "
+ "extracting the form value failed");
+ IncludeDirectories.push_back(Value);
+ break;
+ default:
+ if (!Value.skipValue(DebugLineData, OffsetPtr, FormParams))
+ return createStringError(errc::invalid_argument,
+ "failed to parse directory entry because "
+ "skipping the form value failed");
+ }
+ }
+ }
+
+ // Get the file entry description.
+ llvm::Expected<ContentDescriptors> FileDescriptors =
+ parseV5EntryFormat(DebugLineData, OffsetPtr, &ContentTypes);
+ if (!FileDescriptors)
+ return FileDescriptors.takeError();
+
+ // Get the file entries, according to the format described above.
+ uint64_t FileEntryCount = DebugLineData.getULEB128(OffsetPtr);
+ for (uint64_t I = 0; I != FileEntryCount; ++I) {
+ DWARFDebugLine::FileNameEntry FileEntry;
+ for (auto Descriptor : *FileDescriptors) {
+ DWARFFormValue Value(Descriptor.Form);
+ if (!Value.extractValue(DebugLineData, OffsetPtr, FormParams, &Ctx, U))
+ return createStringError(errc::invalid_argument,
+ "failed to parse file entry because "
+ "extracting the form value failed");
+ switch (Descriptor.Type) {
+ case DW_LNCT_path:
+ FileEntry.Name = Value;
+ break;
+ case DW_LNCT_LLVM_source:
+ FileEntry.Source = Value;
+ break;
+ case DW_LNCT_directory_index:
+ FileEntry.DirIdx = Value.getAsUnsignedConstant().getValue();
+ break;
+ case DW_LNCT_timestamp:
+ FileEntry.ModTime = Value.getAsUnsignedConstant().getValue();
+ break;
+ case DW_LNCT_size:
+ FileEntry.Length = Value.getAsUnsignedConstant().getValue();
+ break;
+ case DW_LNCT_MD5:
+ if (!Value.getAsBlock() || Value.getAsBlock().getValue().size() != 16)
+ return createStringError(
+ errc::invalid_argument,
+ "failed to parse file entry because the MD5 hash is invalid");
+ std::uninitialized_copy_n(Value.getAsBlock().getValue().begin(), 16,
+ FileEntry.Checksum.Bytes.begin());
+ break;
+ default:
+ break;
+ }
+ }
+ FileNames.push_back(FileEntry);
+ }
+ return Error::success();
+}
+
+uint64_t DWARFDebugLine::Prologue::getLength() const {
+ uint64_t Length = PrologueLength + sizeofTotalLength() +
+ sizeof(getVersion()) + sizeofPrologueLength();
+ if (getVersion() >= 5)
+ Length += 2; // Address + Segment selector sizes.
+ return Length;
+}
+
+Error DWARFDebugLine::Prologue::parse(
+ DWARFDataExtractor DebugLineData, uint64_t *OffsetPtr,
+ function_ref<void(Error)> RecoverableErrorHandler, const DWARFContext &Ctx,
+ const DWARFUnit *U) {
+ const uint64_t PrologueOffset = *OffsetPtr;
+
+ clear();
+ DataExtractor::Cursor Cursor(*OffsetPtr);
+ std::tie(TotalLength, FormParams.Format) =
+ DebugLineData.getInitialLength(Cursor);
+
+ DebugLineData =
+ DWARFDataExtractor(DebugLineData, Cursor.tell() + TotalLength);
+ FormParams.Version = DebugLineData.getU16(Cursor);
+ if (Cursor && !versionIsSupported(getVersion())) {
+ // Treat this error as unrecoverable - we cannot be sure what any of
+ // the data represents including the length field, so cannot skip it or make
+ // any reasonable assumptions.
+ *OffsetPtr = Cursor.tell();
+ return createStringError(
+ errc::not_supported,
+ "parsing line table prologue at offset 0x%8.8" PRIx64
+ ": unsupported version %" PRIu16,
+ PrologueOffset, getVersion());
+ }
+
+ if (getVersion() >= 5) {
+ FormParams.AddrSize = DebugLineData.getU8(Cursor);
+ assert((!Cursor || DebugLineData.getAddressSize() == 0 ||
+ DebugLineData.getAddressSize() == getAddressSize()) &&
+ "Line table header and data extractor disagree");
+ SegSelectorSize = DebugLineData.getU8(Cursor);
+ }
+
+ PrologueLength =
+ DebugLineData.getRelocatedValue(Cursor, sizeofPrologueLength());
+ const uint64_t EndPrologueOffset = PrologueLength + Cursor.tell();
+ DebugLineData = DWARFDataExtractor(DebugLineData, EndPrologueOffset);
+ MinInstLength = DebugLineData.getU8(Cursor);
+ if (getVersion() >= 4)
+ MaxOpsPerInst = DebugLineData.getU8(Cursor);
+ DefaultIsStmt = DebugLineData.getU8(Cursor);
+ LineBase = DebugLineData.getU8(Cursor);
+ LineRange = DebugLineData.getU8(Cursor);
+ OpcodeBase = DebugLineData.getU8(Cursor);
+
+ if (Cursor && OpcodeBase == 0) {
+ // If the opcode base is 0, we cannot read the standard opcode lengths (of
+ // which there are supposed to be one fewer than the opcode base). Assume
+ // there are no standard opcodes and continue parsing.
+ RecoverableErrorHandler(createStringError(
+ errc::invalid_argument,
+ "parsing line table prologue at offset 0x%8.8" PRIx64
+ " found opcode base of 0. Assuming no standard opcodes",
+ PrologueOffset));
+ } else if (Cursor) {
+ StandardOpcodeLengths.reserve(OpcodeBase - 1);
+ for (uint32_t I = 1; I < OpcodeBase; ++I) {
+ uint8_t OpLen = DebugLineData.getU8(Cursor);
+ StandardOpcodeLengths.push_back(OpLen);
+ }
+ }
+
+ *OffsetPtr = Cursor.tell();
+ // A corrupt file name or directory table does not prevent interpretation of
+ // the main line program, so check the cursor state now so that its errors can
+ // be handled separately.
+ if (!Cursor)
+ return createStringError(
+ errc::invalid_argument,
+ "parsing line table prologue at offset 0x%8.8" PRIx64 ": %s",
+ PrologueOffset, toString(Cursor.takeError()).c_str());
+
+ Error E =
+ getVersion() >= 5
+ ? parseV5DirFileTables(DebugLineData, OffsetPtr, FormParams, Ctx, U,
+ ContentTypes, IncludeDirectories, FileNames)
+ : parseV2DirFileTables(DebugLineData, OffsetPtr, ContentTypes,
+ IncludeDirectories, FileNames);
+ if (E) {
+ RecoverableErrorHandler(joinErrors(
+ createStringError(
+ errc::invalid_argument,
+ "parsing line table prologue at 0x%8.8" PRIx64
+ " found an invalid directory or file table description at"
+ " 0x%8.8" PRIx64,
+ PrologueOffset, *OffsetPtr),
+ std::move(E)));
+ return Error::success();
+ }
+
+ assert(*OffsetPtr <= EndPrologueOffset);
+ if (*OffsetPtr != EndPrologueOffset) {
+ RecoverableErrorHandler(createStringError(
+ errc::invalid_argument,
+ "unknown data in line table prologue at offset 0x%8.8" PRIx64
+ ": parsing ended (at offset 0x%8.8" PRIx64
+ ") before reaching the prologue end at offset 0x%8.8" PRIx64,
+ PrologueOffset, *OffsetPtr, EndPrologueOffset));
+ }
+ return Error::success();
+}
+
+DWARFDebugLine::Row::Row(bool DefaultIsStmt) { reset(DefaultIsStmt); }
+
+void DWARFDebugLine::Row::postAppend() {
+ Discriminator = 0;
+ BasicBlock = false;
+ PrologueEnd = false;
+ EpilogueBegin = false;
+}
+
+void DWARFDebugLine::Row::reset(bool DefaultIsStmt) {
+ Address.Address = 0;
+ Address.SectionIndex = object::SectionedAddress::UndefSection;
+ Line = 1;
+ Column = 0;
+ File = 1;
+ Isa = 0;
+ Discriminator = 0;
+ IsStmt = DefaultIsStmt;
+ BasicBlock = false;
+ EndSequence = false;
+ PrologueEnd = false;
+ EpilogueBegin = false;
+}
+
+void DWARFDebugLine::Row::dumpTableHeader(raw_ostream &OS, unsigned Indent) {
+ OS.indent(Indent)
+ << "Address Line Column File ISA Discriminator Flags\n";
+ OS.indent(Indent)
+ << "------------------ ------ ------ ------ --- ------------- "
+ "-------------\n";
+}
+
+void DWARFDebugLine::Row::dump(raw_ostream &OS) const {
+ OS << format("0x%16.16" PRIx64 " %6u %6u", Address.Address, Line, Column)
+ << format(" %6u %3u %13u ", File, Isa, Discriminator)
+ << (IsStmt ? " is_stmt" : "") << (BasicBlock ? " basic_block" : "")
+ << (PrologueEnd ? " prologue_end" : "")
+ << (EpilogueBegin ? " epilogue_begin" : "")
+ << (EndSequence ? " end_sequence" : "") << '\n';
+}
+
+DWARFDebugLine::Sequence::Sequence() { reset(); }
+
+void DWARFDebugLine::Sequence::reset() {
+ LowPC = 0;
+ HighPC = 0;
+ SectionIndex = object::SectionedAddress::UndefSection;
+ FirstRowIndex = 0;
+ LastRowIndex = 0;
+ Empty = true;
+}
+
+DWARFDebugLine::LineTable::LineTable() { clear(); }
+
+void DWARFDebugLine::LineTable::dump(raw_ostream &OS,
+ DIDumpOptions DumpOptions) const {
+ Prologue.dump(OS, DumpOptions);
+
+ if (!Rows.empty()) {
+ OS << '\n';
+ Row::dumpTableHeader(OS, 0);
+ for (const Row &R : Rows) {
+ R.dump(OS);
+ }
+ }
+
+ // Terminate the table with a final blank line to clearly delineate it from
+ // later dumps.
+ OS << '\n';
+}
+
+void DWARFDebugLine::LineTable::clear() {
+ Prologue.clear();
+ Rows.clear();
+ Sequences.clear();
+}
+
+DWARFDebugLine::ParsingState::ParsingState(
+ struct LineTable *LT, uint64_t TableOffset,
+ function_ref<void(Error)> ErrorHandler)
+ : LineTable(LT), LineTableOffset(TableOffset), ErrorHandler(ErrorHandler) {
+ resetRowAndSequence();
+}
+
+void DWARFDebugLine::ParsingState::resetRowAndSequence() {
+ Row.reset(LineTable->Prologue.DefaultIsStmt);
+ Sequence.reset();
+}
+
+void DWARFDebugLine::ParsingState::appendRowToMatrix() {
+ unsigned RowNumber = LineTable->Rows.size();
+ if (Sequence.Empty) {
+ // Record the beginning of instruction sequence.
+ Sequence.Empty = false;
+ Sequence.LowPC = Row.Address.Address;
+ Sequence.FirstRowIndex = RowNumber;
+ }
+ LineTable->appendRow(Row);
+ if (Row.EndSequence) {
+ // Record the end of instruction sequence.
+ Sequence.HighPC = Row.Address.Address;
+ Sequence.LastRowIndex = RowNumber + 1;
+ Sequence.SectionIndex = Row.Address.SectionIndex;
+ if (Sequence.isValid())
+ LineTable->appendSequence(Sequence);
+ Sequence.reset();
+ }
+ Row.postAppend();
+}
+
+const DWARFDebugLine::LineTable *
+DWARFDebugLine::getLineTable(uint64_t Offset) const {
+ LineTableConstIter Pos = LineTableMap.find(Offset);
+ if (Pos != LineTableMap.end())
+ return &Pos->second;
+ return nullptr;
+}
+
+Expected<const DWARFDebugLine::LineTable *> DWARFDebugLine::getOrParseLineTable(
+ DWARFDataExtractor &DebugLineData, uint64_t Offset, const DWARFContext &Ctx,
+ const DWARFUnit *U, function_ref<void(Error)> RecoverableErrorHandler) {
+ if (!DebugLineData.isValidOffset(Offset))
+ return createStringError(errc::invalid_argument, "offset 0x%8.8" PRIx64
+ " is not a valid debug line section offset",
+ Offset);
+
+ std::pair<LineTableIter, bool> Pos =
+ LineTableMap.insert(LineTableMapTy::value_type(Offset, LineTable()));
+ LineTable *LT = &Pos.first->second;
+ if (Pos.second) {
+ if (Error Err =
+ LT->parse(DebugLineData, &Offset, Ctx, U, RecoverableErrorHandler))
+ return std::move(Err);
+ return LT;
+ }
+ return LT;
+}
+
+static StringRef getOpcodeName(uint8_t Opcode, uint8_t OpcodeBase) {
+ assert(Opcode != 0);
+ if (Opcode < OpcodeBase)
+ return LNStandardString(Opcode);
+ return "special";
+}
+
+uint64_t DWARFDebugLine::ParsingState::advanceAddr(uint64_t OperationAdvance,
+ uint8_t Opcode,
+ uint64_t OpcodeOffset) {
+ StringRef OpcodeName = getOpcodeName(Opcode, LineTable->Prologue.OpcodeBase);
+ // For versions less than 4, the MaxOpsPerInst member is set to 0, as the
+ // maximum_operations_per_instruction field wasn't introduced until DWARFv4.
+ // Don't warn about bad values in this situation.
+ if (ReportAdvanceAddrProblem && LineTable->Prologue.getVersion() >= 4 &&
+ LineTable->Prologue.MaxOpsPerInst != 1)
+ ErrorHandler(createStringError(
+ errc::not_supported,
+ "line table program at offset 0x%8.8" PRIx64
+ " contains a %s opcode at offset 0x%8.8" PRIx64
+ ", but the prologue maximum_operations_per_instruction value is %" PRId8
+ ", which is unsupported. Assuming a value of 1 instead",
+ LineTableOffset, OpcodeName.data(), OpcodeOffset,
+ LineTable->Prologue.MaxOpsPerInst));
+ if (ReportAdvanceAddrProblem && LineTable->Prologue.MinInstLength == 0)
+ ErrorHandler(
+ createStringError(errc::invalid_argument,
+ "line table program at offset 0x%8.8" PRIx64
+ " contains a %s opcode at offset 0x%8.8" PRIx64
+ ", but the prologue minimum_instruction_length value "
+ "is 0, which prevents any address advancing",
+ LineTableOffset, OpcodeName.data(), OpcodeOffset));
+ ReportAdvanceAddrProblem = false;
+ uint64_t AddrOffset = OperationAdvance * LineTable->Prologue.MinInstLength;
+ Row.Address.Address += AddrOffset;
+ return AddrOffset;
+}
+
+DWARFDebugLine::ParsingState::AddrAndAdjustedOpcode
+DWARFDebugLine::ParsingState::advanceAddrForOpcode(uint8_t Opcode,
+ uint64_t OpcodeOffset) {
+ assert(Opcode == DW_LNS_const_add_pc ||
+ Opcode >= LineTable->Prologue.OpcodeBase);
+ if (ReportBadLineRange && LineTable->Prologue.LineRange == 0) {
+ StringRef OpcodeName =
+ getOpcodeName(Opcode, LineTable->Prologue.OpcodeBase);
+ ErrorHandler(
+ createStringError(errc::not_supported,
+ "line table program at offset 0x%8.8" PRIx64
+ " contains a %s opcode at offset 0x%8.8" PRIx64
+ ", but the prologue line_range value is 0. The "
+ "address and line will not be adjusted",
+ LineTableOffset, OpcodeName.data(), OpcodeOffset));
+ ReportBadLineRange = false;
+ }
+
+ uint8_t OpcodeValue = Opcode;
+ if (Opcode == DW_LNS_const_add_pc)
+ OpcodeValue = 255;
+ uint8_t AdjustedOpcode = OpcodeValue - LineTable->Prologue.OpcodeBase;
+ uint64_t OperationAdvance =
+ LineTable->Prologue.LineRange != 0
+ ? AdjustedOpcode / LineTable->Prologue.LineRange
+ : 0;
+ uint64_t AddrOffset = advanceAddr(OperationAdvance, Opcode, OpcodeOffset);
+ return {AddrOffset, AdjustedOpcode};
+}
+
+DWARFDebugLine::ParsingState::AddrAndLineDelta
+DWARFDebugLine::ParsingState::handleSpecialOpcode(uint8_t Opcode,
+ uint64_t OpcodeOffset) {
+ // A special opcode value is chosen based on the amount that needs
+ // to be added to the line and address registers. The maximum line
+ // increment for a special opcode is the value of the line_base
+ // field in the header, plus the value of the line_range field,
+ // minus 1 (line base + line range - 1). If the desired line
+ // increment is greater than the maximum line increment, a standard
+ // opcode must be used instead of a special opcode. The "address
+ // advance" is calculated by dividing the desired address increment
+ // by the minimum_instruction_length field from the header. The
+ // special opcode is then calculated using the following formula:
+ //
+ // opcode = (desired line increment - line_base) +
+ // (line_range * address advance) + opcode_base
+ //
+ // If the resulting opcode is greater than 255, a standard opcode
+ // must be used instead.
+ //
+ // To decode a special opcode, subtract the opcode_base from the
+ // opcode itself to give the adjusted opcode. The amount to
+ // increment the address register is the result of the adjusted
+ // opcode divided by the line_range multiplied by the
+ // minimum_instruction_length field from the header. That is:
+ //
+ // address increment = (adjusted opcode / line_range) *
+ // minimum_instruction_length
+ //
+ // The amount to increment the line register is the line_base plus
+ // the result of the adjusted opcode modulo the line_range. That is:
+ //
+ // line increment = line_base + (adjusted opcode % line_range)
+
+ DWARFDebugLine::ParsingState::AddrAndAdjustedOpcode AddrAdvanceResult =
+ advanceAddrForOpcode(Opcode, OpcodeOffset);
+ int32_t LineOffset = 0;
+ if (LineTable->Prologue.LineRange != 0)
+ LineOffset =
+ LineTable->Prologue.LineBase +
+ (AddrAdvanceResult.AdjustedOpcode % LineTable->Prologue.LineRange);
+ Row.Line += LineOffset;
+ return {AddrAdvanceResult.AddrDelta, LineOffset};
+}
+
+/// Parse a ULEB128 using the specified \p Cursor. \returns the parsed value on
+/// success, or None if \p Cursor is in a failing state.
+template <typename T>
+static Optional<T> parseULEB128(DWARFDataExtractor &Data,
+ DataExtractor::Cursor &Cursor) {
+ T Value = Data.getULEB128(Cursor);
+ if (Cursor)
+ return Value;
+ return None;
+}
+
+Error DWARFDebugLine::LineTable::parse(
+ DWARFDataExtractor &DebugLineData, uint64_t *OffsetPtr,
+ const DWARFContext &Ctx, const DWARFUnit *U,
+ function_ref<void(Error)> RecoverableErrorHandler, raw_ostream *OS,
+ bool Verbose) {
+ assert((OS || !Verbose) && "cannot have verbose output without stream");
+ const uint64_t DebugLineOffset = *OffsetPtr;
+
+ clear();
+
+ Error PrologueErr =
+ Prologue.parse(DebugLineData, OffsetPtr, RecoverableErrorHandler, Ctx, U);
+
+ if (OS) {
+ DIDumpOptions DumpOptions;
+ DumpOptions.Verbose = Verbose;
+ Prologue.dump(*OS, DumpOptions);
+ }
+
+ if (PrologueErr) {
+ // Ensure there is a blank line after the prologue to clearly delineate it
+ // from later dumps.
+ if (OS)
+ *OS << "\n";
+ return PrologueErr;
+ }
+
+ uint64_t ProgramLength = Prologue.TotalLength + Prologue.sizeofTotalLength();
+ if (!DebugLineData.isValidOffsetForDataOfSize(DebugLineOffset,
+ ProgramLength)) {
+ assert(DebugLineData.size() > DebugLineOffset &&
+ "prologue parsing should handle invalid offset");
+ uint64_t BytesRemaining = DebugLineData.size() - DebugLineOffset;
+ RecoverableErrorHandler(
+ createStringError(errc::invalid_argument,
+ "line table program with offset 0x%8.8" PRIx64
+ " has length 0x%8.8" PRIx64 " but only 0x%8.8" PRIx64
+ " bytes are available",
+ DebugLineOffset, ProgramLength, BytesRemaining));
+ // Continue by capping the length at the number of remaining bytes.
+ ProgramLength = BytesRemaining;
+ }
+
+ // Create a DataExtractor which can only see the data up to the end of the
+ // table, to prevent reading past the end.
+ const uint64_t EndOffset = DebugLineOffset + ProgramLength;
+ DWARFDataExtractor TableData(DebugLineData, EndOffset);
+
+ // See if we should tell the data extractor the address size.
+ if (TableData.getAddressSize() == 0)
+ TableData.setAddressSize(Prologue.getAddressSize());
+ else
+ assert(Prologue.getAddressSize() == 0 ||
+ Prologue.getAddressSize() == TableData.getAddressSize());
+
+ ParsingState State(this, DebugLineOffset, RecoverableErrorHandler);
+
+ *OffsetPtr = DebugLineOffset + Prologue.getLength();
+ if (OS && *OffsetPtr < EndOffset) {
+ *OS << '\n';
+ Row::dumpTableHeader(*OS, /*Indent=*/Verbose ? 12 : 0);
+ }
+ bool TombstonedAddress = false;
+ auto EmitRow = [&] {
+ if (!TombstonedAddress) {
+ if (Verbose) {
+ *OS << "\n";
+ OS->indent(12);
+ }
+ if (OS)
+ State.Row.dump(*OS);
+ State.appendRowToMatrix();
+ }
+ };
+ while (*OffsetPtr < EndOffset) {
+ DataExtractor::Cursor Cursor(*OffsetPtr);
+
+ if (Verbose)
+ *OS << format("0x%08.08" PRIx64 ": ", *OffsetPtr);
+
+ uint64_t OpcodeOffset = *OffsetPtr;
+ uint8_t Opcode = TableData.getU8(Cursor);
+ size_t RowCount = Rows.size();
+
+ if (Cursor && Verbose)
+ *OS << format("%02.02" PRIx8 " ", Opcode);
+
+ if (Opcode == 0) {
+ // Extended Opcodes always start with a zero opcode followed by
+ // a uleb128 length so you can skip ones you don't know about
+ uint64_t Len = TableData.getULEB128(Cursor);
+ uint64_t ExtOffset = Cursor.tell();
+
+ // Tolerate zero-length; assume length is correct and soldier on.
+ if (Len == 0) {
+ if (Cursor && Verbose)
+ *OS << "Badly formed extended line op (length 0)\n";
+ if (!Cursor) {
+ if (Verbose)
+ *OS << "\n";
+ RecoverableErrorHandler(Cursor.takeError());
+ }
+ *OffsetPtr = Cursor.tell();
+ continue;
+ }
+
+ uint8_t SubOpcode = TableData.getU8(Cursor);
+ // OperandOffset will be the same as ExtOffset, if it was not possible to
+ // read the SubOpcode.
+ uint64_t OperandOffset = Cursor.tell();
+ if (Verbose)
+ *OS << LNExtendedString(SubOpcode);
+ switch (SubOpcode) {
+ case DW_LNE_end_sequence:
+ // Set the end_sequence register of the state machine to true and
+ // append a row to the matrix using the current values of the
+ // state-machine registers. Then reset the registers to the initial
+ // values specified above. Every statement program sequence must end
+ // with a DW_LNE_end_sequence instruction which creates a row whose
+ // address is that of the byte after the last target machine instruction
+ // of the sequence.
+ State.Row.EndSequence = true;
+ // No need to test the Cursor is valid here, since it must be to get
+ // into this code path - if it were invalid, the default case would be
+ // followed.
+ EmitRow();
+ State.resetRowAndSequence();
+ break;
+
+ case DW_LNE_set_address:
+ // Takes a single relocatable address as an operand. The size of the
+ // operand is the size appropriate to hold an address on the target
+ // machine. Set the address register to the value given by the
+ // relocatable address. All of the other statement program opcodes
+ // that affect the address register add a delta to it. This instruction
+ // stores a relocatable value into it instead.
+ //
+ // Make sure the extractor knows the address size. If not, infer it
+ // from the size of the operand.
+ {
+ uint8_t ExtractorAddressSize = TableData.getAddressSize();
+ uint64_t OpcodeAddressSize = Len - 1;
+ if (ExtractorAddressSize != OpcodeAddressSize &&
+ ExtractorAddressSize != 0)
+ RecoverableErrorHandler(createStringError(
+ errc::invalid_argument,
+ "mismatching address size at offset 0x%8.8" PRIx64
+ " expected 0x%2.2" PRIx8 " found 0x%2.2" PRIx64,
+ ExtOffset, ExtractorAddressSize, Len - 1));
+
+ // Assume that the line table is correct and temporarily override the
+ // address size. If the size is unsupported, give up trying to read
+ // the address and continue to the next opcode.
+ if (OpcodeAddressSize != 1 && OpcodeAddressSize != 2 &&
+ OpcodeAddressSize != 4 && OpcodeAddressSize != 8) {
+ RecoverableErrorHandler(createStringError(
+ errc::invalid_argument,
+ "address size 0x%2.2" PRIx64
+ " of DW_LNE_set_address opcode at offset 0x%8.8" PRIx64
+ " is unsupported",
+ OpcodeAddressSize, ExtOffset));
+ TableData.skip(Cursor, OpcodeAddressSize);
+ } else {
+ TableData.setAddressSize(OpcodeAddressSize);
+ State.Row.Address.Address = TableData.getRelocatedAddress(
+ Cursor, &State.Row.Address.SectionIndex);
+
+ uint64_t Tombstone =
+ dwarf::computeTombstoneAddress(OpcodeAddressSize);
+ TombstonedAddress = State.Row.Address.Address == Tombstone;
+
+ // Restore the address size if the extractor already had it.
+ if (ExtractorAddressSize != 0)
+ TableData.setAddressSize(ExtractorAddressSize);
+ }
+
+ if (Cursor && Verbose) {
+ *OS << " (";
+ DWARFFormValue::dumpAddress(*OS, OpcodeAddressSize, State.Row.Address.Address);
+ *OS << ')';
+ }
+ }
+ break;
+
+ case DW_LNE_define_file:
+ // Takes 4 arguments. The first is a null terminated string containing
+ // a source file name. The second is an unsigned LEB128 number
+ // representing the directory index of the directory in which the file
+ // was found. The third is an unsigned LEB128 number representing the
+ // time of last modification of the file. The fourth is an unsigned
+ // LEB128 number representing the length in bytes of the file. The time
+ // and length fields may contain LEB128(0) if the information is not
+ // available.
+ //
+ // The directory index represents an entry in the include_directories
+ // section of the statement program prologue. The index is LEB128(0)
+ // if the file was found in the current directory of the compilation,
+ // LEB128(1) if it was found in the first directory in the
+ // include_directories section, and so on. The directory index is
+ // ignored for file names that represent full path names.
+ //
+ // The files are numbered, starting at 1, in the order in which they
+ // appear; the names in the prologue come before names defined by
+ // the DW_LNE_define_file instruction. These numbers are used in the
+ // the file register of the state machine.
+ {
+ FileNameEntry FileEntry;
+ const char *Name = TableData.getCStr(Cursor);
+ FileEntry.Name =
+ DWARFFormValue::createFromPValue(dwarf::DW_FORM_string, Name);
+ FileEntry.DirIdx = TableData.getULEB128(Cursor);
+ FileEntry.ModTime = TableData.getULEB128(Cursor);
+ FileEntry.Length = TableData.getULEB128(Cursor);
+ Prologue.FileNames.push_back(FileEntry);
+ if (Cursor && Verbose)
+ *OS << " (" << Name << ", dir=" << FileEntry.DirIdx << ", mod_time="
+ << format("(0x%16.16" PRIx64 ")", FileEntry.ModTime)
+ << ", length=" << FileEntry.Length << ")";
+ }
+ break;
+
+ case DW_LNE_set_discriminator:
+ State.Row.Discriminator = TableData.getULEB128(Cursor);
+ if (Cursor && Verbose)
+ *OS << " (" << State.Row.Discriminator << ")";
+ break;
+
+ default:
+ if (Cursor && Verbose)
+ *OS << format("Unrecognized extended op 0x%02.02" PRIx8, SubOpcode)
+ << format(" length %" PRIx64, Len);
+ // Len doesn't include the zero opcode byte or the length itself, but
+ // it does include the sub_opcode, so we have to adjust for that.
+ TableData.skip(Cursor, Len - 1);
+ break;
+ }
+ // Make sure the length as recorded in the table and the standard length
+ // for the opcode match. If they don't, continue from the end as claimed
+ // by the table. Similarly, continue from the claimed end in the event of
+ // a parsing error.
+ uint64_t End = ExtOffset + Len;
+ if (Cursor && Cursor.tell() != End)
+ RecoverableErrorHandler(createStringError(
+ errc::illegal_byte_sequence,
+ "unexpected line op length at offset 0x%8.8" PRIx64
+ " expected 0x%2.2" PRIx64 " found 0x%2.2" PRIx64,
+ ExtOffset, Len, Cursor.tell() - ExtOffset));
+ if (!Cursor && Verbose) {
+ DWARFDataExtractor::Cursor ByteCursor(OperandOffset);
+ uint8_t Byte = TableData.getU8(ByteCursor);
+ if (ByteCursor) {
+ *OS << " (<parsing error>";
+ do {
+ *OS << format(" %2.2" PRIx8, Byte);
+ Byte = TableData.getU8(ByteCursor);
+ } while (ByteCursor);
+ *OS << ")";
+ }
+
+ // The only parse failure in this case should be if the end was reached.
+ // In that case, throw away the error, as the main Cursor's error will
+ // be sufficient.
+ consumeError(ByteCursor.takeError());
+ }
+ *OffsetPtr = End;
+ } else if (Opcode < Prologue.OpcodeBase) {
+ if (Verbose)
+ *OS << LNStandardString(Opcode);
+ switch (Opcode) {
+ // Standard Opcodes
+ case DW_LNS_copy:
+ // Takes no arguments. Append a row to the matrix using the
+ // current values of the state-machine registers.
+ EmitRow();
+ break;
+
+ case DW_LNS_advance_pc:
+ // Takes a single unsigned LEB128 operand, multiplies it by the
+ // min_inst_length field of the prologue, and adds the
+ // result to the address register of the state machine.
+ if (Optional<uint64_t> Operand =
+ parseULEB128<uint64_t>(TableData, Cursor)) {
+ uint64_t AddrOffset =
+ State.advanceAddr(*Operand, Opcode, OpcodeOffset);
+ if (Verbose)
+ *OS << " (" << AddrOffset << ")";
+ }
+ break;
+
+ case DW_LNS_advance_line:
+ // Takes a single signed LEB128 operand and adds that value to
+ // the line register of the state machine.
+ {
+ int64_t LineDelta = TableData.getSLEB128(Cursor);
+ if (Cursor) {
+ State.Row.Line += LineDelta;
+ if (Verbose)
+ *OS << " (" << State.Row.Line << ")";
+ }
+ }
+ break;
+
+ case DW_LNS_set_file:
+ // Takes a single unsigned LEB128 operand and stores it in the file
+ // register of the state machine.
+ if (Optional<uint16_t> File =
+ parseULEB128<uint16_t>(TableData, Cursor)) {
+ State.Row.File = *File;
+ if (Verbose)
+ *OS << " (" << State.Row.File << ")";
+ }
+ break;
+
+ case DW_LNS_set_column:
+ // Takes a single unsigned LEB128 operand and stores it in the
+ // column register of the state machine.
+ if (Optional<uint16_t> Column =
+ parseULEB128<uint16_t>(TableData, Cursor)) {
+ State.Row.Column = *Column;
+ if (Verbose)
+ *OS << " (" << State.Row.Column << ")";
+ }
+ break;
+
+ case DW_LNS_negate_stmt:
+ // Takes no arguments. Set the is_stmt register of the state
+ // machine to the logical negation of its current value.
+ State.Row.IsStmt = !State.Row.IsStmt;
+ break;
+
+ case DW_LNS_set_basic_block:
+ // Takes no arguments. Set the basic_block register of the
+ // state machine to true
+ State.Row.BasicBlock = true;
+ break;
+
+ case DW_LNS_const_add_pc:
+ // Takes no arguments. Add to the address register of the state
+ // machine the address increment value corresponding to special
+ // opcode 255. The motivation for DW_LNS_const_add_pc is this:
+ // when the statement program needs to advance the address by a
+ // small amount, it can use a single special opcode, which occupies
+ // a single byte. When it needs to advance the address by up to
+ // twice the range of the last special opcode, it can use
+ // DW_LNS_const_add_pc followed by a special opcode, for a total
+ // of two bytes. Only if it needs to advance the address by more
+ // than twice that range will it need to use both DW_LNS_advance_pc
+ // and a special opcode, requiring three or more bytes.
+ {
+ uint64_t AddrOffset =
+ State.advanceAddrForOpcode(Opcode, OpcodeOffset).AddrDelta;
+ if (Verbose)
+ *OS << format(" (0x%16.16" PRIx64 ")", AddrOffset);
+ }
+ break;
+
+ case DW_LNS_fixed_advance_pc:
+ // Takes a single uhalf operand. Add to the address register of
+ // the state machine the value of the (unencoded) operand. This
+ // is the only extended opcode that takes an argument that is not
+ // a variable length number. The motivation for DW_LNS_fixed_advance_pc
+ // is this: existing assemblers cannot emit DW_LNS_advance_pc or
+ // special opcodes because they cannot encode LEB128 numbers or
+ // judge when the computation of a special opcode overflows and
+ // requires the use of DW_LNS_advance_pc. Such assemblers, however,
+ // can use DW_LNS_fixed_advance_pc instead, sacrificing compression.
+ {
+ uint16_t PCOffset =
+ TableData.getRelocatedValue(Cursor, 2);
+ if (Cursor) {
+ State.Row.Address.Address += PCOffset;
+ if (Verbose)
+ *OS << format(" (0x%4.4" PRIx16 ")", PCOffset);
+ }
+ }
+ break;
+
+ case DW_LNS_set_prologue_end:
+ // Takes no arguments. Set the prologue_end register of the
+ // state machine to true
+ State.Row.PrologueEnd = true;
+ break;
+
+ case DW_LNS_set_epilogue_begin:
+ // Takes no arguments. Set the basic_block register of the
+ // state machine to true
+ State.Row.EpilogueBegin = true;
+ break;
+
+ case DW_LNS_set_isa:
+ // Takes a single unsigned LEB128 operand and stores it in the
+ // ISA register of the state machine.
+ if (Optional<uint8_t> Isa = parseULEB128<uint8_t>(TableData, Cursor)) {
+ State.Row.Isa = *Isa;
+ if (Verbose)
+ *OS << " (" << (uint64_t)State.Row.Isa << ")";
+ }
+ break;
+
+ default:
+ // Handle any unknown standard opcodes here. We know the lengths
+ // of such opcodes because they are specified in the prologue
+ // as a multiple of LEB128 operands for each opcode.
+ {
+ assert(Opcode - 1U < Prologue.StandardOpcodeLengths.size());
+ if (Verbose)
+ *OS << "Unrecognized standard opcode";
+ uint8_t OpcodeLength = Prologue.StandardOpcodeLengths[Opcode - 1];
+ std::vector<uint64_t> Operands;
+ for (uint8_t I = 0; I < OpcodeLength; ++I) {
+ if (Optional<uint64_t> Value =
+ parseULEB128<uint64_t>(TableData, Cursor))
+ Operands.push_back(*Value);
+ else
+ break;
+ }
+ if (Verbose && !Operands.empty()) {
+ *OS << " (operands: ";
+ bool First = true;
+ for (uint64_t Value : Operands) {
+ if (!First)
+ *OS << ", ";
+ First = false;
+ *OS << format("0x%16.16" PRIx64, Value);
+ }
+ if (Verbose)
+ *OS << ')';
+ }
+ }
+ break;
+ }
+
+ *OffsetPtr = Cursor.tell();
+ } else {
+ // Special Opcodes.
+ ParsingState::AddrAndLineDelta Delta =
+ State.handleSpecialOpcode(Opcode, OpcodeOffset);
+
+ if (Verbose)
+ *OS << "address += " << Delta.Address << ", line += " << Delta.Line;
+ EmitRow();
+ *OffsetPtr = Cursor.tell();
+ }
+
+ // When a row is added to the matrix, it is also dumped, which includes a
+ // new line already, so don't add an extra one.
+ if (Verbose && Rows.size() == RowCount)
+ *OS << "\n";
+
+ // Most parse failures other than when parsing extended opcodes are due to
+ // failures to read ULEBs. Bail out of parsing, since we don't know where to
+ // continue reading from as there is no stated length for such byte
+ // sequences. Print the final trailing new line if needed before doing so.
+ if (!Cursor && Opcode != 0) {
+ if (Verbose)
+ *OS << "\n";
+ return Cursor.takeError();
+ }
+
+ if (!Cursor)
+ RecoverableErrorHandler(Cursor.takeError());
+ }
+
+ if (!State.Sequence.Empty)
+ RecoverableErrorHandler(createStringError(
+ errc::illegal_byte_sequence,
+ "last sequence in debug line table at offset 0x%8.8" PRIx64
+ " is not terminated",
+ DebugLineOffset));
+
+ // Sort all sequences so that address lookup will work faster.
+ if (!Sequences.empty()) {
+ llvm::sort(Sequences, Sequence::orderByHighPC);
+ // Note: actually, instruction address ranges of sequences should not
+ // overlap (in shared objects and executables). If they do, the address
+ // lookup would still work, though, but result would be ambiguous.
+ // We don't report warning in this case. For example,
+ // sometimes .so compiled from multiple object files contains a few
+ // rudimentary sequences for address ranges [0x0, 0xsomething).
+ }
+
+ // Terminate the table with a final blank line to clearly delineate it from
+ // later dumps.
+ if (OS)
+ *OS << "\n";
+
+ return Error::success();
+}
+
+uint32_t DWARFDebugLine::LineTable::findRowInSeq(
+ const DWARFDebugLine::Sequence &Seq,
+ object::SectionedAddress Address) const {
+ if (!Seq.containsPC(Address))
+ return UnknownRowIndex;
+ assert(Seq.SectionIndex == Address.SectionIndex);
+ // In some cases, e.g. first instruction in a function, the compiler generates
+ // two entries, both with the same address. We want the last one.
+ //
+ // In general we want a non-empty range: the last row whose address is less
+ // than or equal to Address. This can be computed as upper_bound - 1.
+ DWARFDebugLine::Row Row;
+ Row.Address = Address;
+ RowIter FirstRow = Rows.begin() + Seq.FirstRowIndex;
+ RowIter LastRow = Rows.begin() + Seq.LastRowIndex;
+ assert(FirstRow->Address.Address <= Row.Address.Address &&
+ Row.Address.Address < LastRow[-1].Address.Address);
+ RowIter RowPos = std::upper_bound(FirstRow + 1, LastRow - 1, Row,
+ DWARFDebugLine::Row::orderByAddress) -
+ 1;
+ assert(Seq.SectionIndex == RowPos->Address.SectionIndex);
+ return RowPos - Rows.begin();
+}
+
+uint32_t DWARFDebugLine::LineTable::lookupAddress(
+ object::SectionedAddress Address) const {
+
+ // Search for relocatable addresses
+ uint32_t Result = lookupAddressImpl(Address);
+
+ if (Result != UnknownRowIndex ||
+ Address.SectionIndex == object::SectionedAddress::UndefSection)
+ return Result;
+
+ // Search for absolute addresses
+ Address.SectionIndex = object::SectionedAddress::UndefSection;
+ return lookupAddressImpl(Address);
+}
+
+uint32_t DWARFDebugLine::LineTable::lookupAddressImpl(
+ object::SectionedAddress Address) const {
+ // First, find an instruction sequence containing the given address.
+ DWARFDebugLine::Sequence Sequence;
+ Sequence.SectionIndex = Address.SectionIndex;
+ Sequence.HighPC = Address.Address;
+ SequenceIter It = llvm::upper_bound(Sequences, Sequence,
+ DWARFDebugLine::Sequence::orderByHighPC);
+ if (It == Sequences.end() || It->SectionIndex != Address.SectionIndex)
+ return UnknownRowIndex;
+ return findRowInSeq(*It, Address);
+}
+
+bool DWARFDebugLine::LineTable::lookupAddressRange(
+ object::SectionedAddress Address, uint64_t Size,
+ std::vector<uint32_t> &Result) const {
+
+ // Search for relocatable addresses
+ if (lookupAddressRangeImpl(Address, Size, Result))
+ return true;
+
+ if (Address.SectionIndex == object::SectionedAddress::UndefSection)
+ return false;
+
+ // Search for absolute addresses
+ Address.SectionIndex = object::SectionedAddress::UndefSection;
+ return lookupAddressRangeImpl(Address, Size, Result);
+}
+
+bool DWARFDebugLine::LineTable::lookupAddressRangeImpl(
+ object::SectionedAddress Address, uint64_t Size,
+ std::vector<uint32_t> &Result) const {
+ if (Sequences.empty())
+ return false;
+ uint64_t EndAddr = Address.Address + Size;
+ // First, find an instruction sequence containing the given address.
+ DWARFDebugLine::Sequence Sequence;
+ Sequence.SectionIndex = Address.SectionIndex;
+ Sequence.HighPC = Address.Address;
+ SequenceIter LastSeq = Sequences.end();
+ SequenceIter SeqPos = llvm::upper_bound(
+ Sequences, Sequence, DWARFDebugLine::Sequence::orderByHighPC);
+ if (SeqPos == LastSeq || !SeqPos->containsPC(Address))
+ return false;
+
+ SequenceIter StartPos = SeqPos;
+
+ // Add the rows from the first sequence to the vector, starting with the
+ // index we just calculated
+
+ while (SeqPos != LastSeq && SeqPos->LowPC < EndAddr) {
+ const DWARFDebugLine::Sequence &CurSeq = *SeqPos;
+ // For the first sequence, we need to find which row in the sequence is the
+ // first in our range.
+ uint32_t FirstRowIndex = CurSeq.FirstRowIndex;
+ if (SeqPos == StartPos)
+ FirstRowIndex = findRowInSeq(CurSeq, Address);
+
+ // Figure out the last row in the range.
+ uint32_t LastRowIndex =
+ findRowInSeq(CurSeq, {EndAddr - 1, Address.SectionIndex});
+ if (LastRowIndex == UnknownRowIndex)
+ LastRowIndex = CurSeq.LastRowIndex - 1;
+
+ assert(FirstRowIndex != UnknownRowIndex);
+ assert(LastRowIndex != UnknownRowIndex);
+
+ for (uint32_t I = FirstRowIndex; I <= LastRowIndex; ++I) {
+ Result.push_back(I);
+ }
+
+ ++SeqPos;
+ }
+
+ return true;
+}
+
+Optional<StringRef> DWARFDebugLine::LineTable::getSourceByIndex(uint64_t FileIndex,
+ FileLineInfoKind Kind) const {
+ if (Kind == FileLineInfoKind::None || !Prologue.hasFileAtIndex(FileIndex))
+ return None;
+ const FileNameEntry &Entry = Prologue.getFileNameEntry(FileIndex);
+ if (auto E = dwarf::toString(Entry.Source))
+ return StringRef(*E);
+ return None;
+}
+
+static bool isPathAbsoluteOnWindowsOrPosix(const Twine &Path) {
+ // Debug info can contain paths from any OS, not necessarily
+ // an OS we're currently running on. Moreover different compilation units can
+ // be compiled on different operating systems and linked together later.
+ return sys::path::is_absolute(Path, sys::path::Style::posix) ||
+ sys::path::is_absolute(Path, sys::path::Style::windows);
+}
+
+bool DWARFDebugLine::Prologue::getFileNameByIndex(
+ uint64_t FileIndex, StringRef CompDir, FileLineInfoKind Kind,
+ std::string &Result, sys::path::Style Style) const {
+ if (Kind == FileLineInfoKind::None || !hasFileAtIndex(FileIndex))
+ return false;
+ const FileNameEntry &Entry = getFileNameEntry(FileIndex);
+ auto E = dwarf::toString(Entry.Name);
+ if (!E)
+ return false;
+ StringRef FileName = *E;
+ if (Kind == FileLineInfoKind::RawValue ||
+ isPathAbsoluteOnWindowsOrPosix(FileName)) {
+ Result = std::string(FileName);
+ return true;
+ }
+ if (Kind == FileLineInfoKind::BaseNameOnly) {
+ Result = std::string(llvm::sys::path::filename(FileName));
+ return true;
+ }
+
+ SmallString<16> FilePath;
+ StringRef IncludeDir;
+ // Be defensive about the contents of Entry.
+ if (getVersion() >= 5) {
+ // DirIdx 0 is the compilation directory, so don't include it for
+ // relative names.
+ if ((Entry.DirIdx != 0 || Kind != FileLineInfoKind::RelativeFilePath) &&
+ Entry.DirIdx < IncludeDirectories.size())
+ IncludeDir = dwarf::toStringRef(IncludeDirectories[Entry.DirIdx]);
+ } else {
+ if (0 < Entry.DirIdx && Entry.DirIdx <= IncludeDirectories.size())
+ IncludeDir = dwarf::toStringRef(IncludeDirectories[Entry.DirIdx - 1]);
+ }
+
+ // For absolute paths only, include the compilation directory of compile unit.
+ // We know that FileName is not absolute, the only way to have an absolute
+ // path at this point would be if IncludeDir is absolute.
+ if (Kind == FileLineInfoKind::AbsoluteFilePath && !CompDir.empty() &&
+ !isPathAbsoluteOnWindowsOrPosix(IncludeDir))
+ sys::path::append(FilePath, Style, CompDir);
+
+ assert((Kind == FileLineInfoKind::AbsoluteFilePath ||
+ Kind == FileLineInfoKind::RelativeFilePath) &&
+ "invalid FileLineInfo Kind");
+
+ // sys::path::append skips empty strings.
+ sys::path::append(FilePath, Style, IncludeDir, FileName);
+ Result = std::string(FilePath.str());
+ return true;
+}
+
+bool DWARFDebugLine::LineTable::getFileLineInfoForAddress(
+ object::SectionedAddress Address, const char *CompDir,
+ FileLineInfoKind Kind, DILineInfo &Result) const {
+ // Get the index of row we're looking for in the line table.
+ uint32_t RowIndex = lookupAddress(Address);
+ if (RowIndex == -1U)
+ return false;
+ // Take file number and line/column from the row.
+ const auto &Row = Rows[RowIndex];
+ if (!getFileNameByIndex(Row.File, CompDir, Kind, Result.FileName))
+ return false;
+ Result.Line = Row.Line;
+ Result.Column = Row.Column;
+ Result.Discriminator = Row.Discriminator;
+ Result.Source = getSourceByIndex(Row.File, Kind);
+ return true;
+}
+
+// We want to supply the Unit associated with a .debug_line[.dwo] table when
+// we dump it, if possible, but still dump the table even if there isn't a Unit.
+// Therefore, collect up handles on all the Units that point into the
+// line-table section.
+static DWARFDebugLine::SectionParser::LineToUnitMap
+buildLineToUnitMap(DWARFUnitVector::iterator_range Units) {
+ DWARFDebugLine::SectionParser::LineToUnitMap LineToUnit;
+ for (const auto &U : Units)
+ if (auto CUDIE = U->getUnitDIE())
+ if (auto StmtOffset = toSectionOffset(CUDIE.find(DW_AT_stmt_list)))
+ LineToUnit.insert(std::make_pair(*StmtOffset, &*U));
+ return LineToUnit;
+}
+
+DWARFDebugLine::SectionParser::SectionParser(
+ DWARFDataExtractor &Data, const DWARFContext &C,
+ DWARFUnitVector::iterator_range Units)
+ : DebugLineData(Data), Context(C) {
+ LineToUnit = buildLineToUnitMap(Units);
+ if (!DebugLineData.isValidOffset(Offset))
+ Done = true;
+}
+
+bool DWARFDebugLine::Prologue::totalLengthIsValid() const {
+ return TotalLength != 0u;
+}
+
+DWARFDebugLine::LineTable DWARFDebugLine::SectionParser::parseNext(
+ function_ref<void(Error)> RecoverableErrorHandler,
+ function_ref<void(Error)> UnrecoverableErrorHandler, raw_ostream *OS,
+ bool Verbose) {
+ assert(DebugLineData.isValidOffset(Offset) &&
+ "parsing should have terminated");
+ DWARFUnit *U = prepareToParse(Offset);
+ uint64_t OldOffset = Offset;
+ LineTable LT;
+ if (Error Err = LT.parse(DebugLineData, &Offset, Context, U,
+ RecoverableErrorHandler, OS, Verbose))
+ UnrecoverableErrorHandler(std::move(Err));
+ moveToNextTable(OldOffset, LT.Prologue);
+ return LT;
+}
+
+void DWARFDebugLine::SectionParser::skip(
+ function_ref<void(Error)> RecoverableErrorHandler,
+ function_ref<void(Error)> UnrecoverableErrorHandler) {
+ assert(DebugLineData.isValidOffset(Offset) &&
+ "parsing should have terminated");
+ DWARFUnit *U = prepareToParse(Offset);
+ uint64_t OldOffset = Offset;
+ LineTable LT;
+ if (Error Err = LT.Prologue.parse(DebugLineData, &Offset,
+ RecoverableErrorHandler, Context, U))
+ UnrecoverableErrorHandler(std::move(Err));
+ moveToNextTable(OldOffset, LT.Prologue);
+}
+
+DWARFUnit *DWARFDebugLine::SectionParser::prepareToParse(uint64_t Offset) {
+ DWARFUnit *U = nullptr;
+ auto It = LineToUnit.find(Offset);
+ if (It != LineToUnit.end())
+ U = It->second;
+ DebugLineData.setAddressSize(U ? U->getAddressByteSize() : 0);
+ return U;
+}
+
+void DWARFDebugLine::SectionParser::moveToNextTable(uint64_t OldOffset,
+ const Prologue &P) {
+ // If the length field is not valid, we don't know where the next table is, so
+ // cannot continue to parse. Mark the parser as done, and leave the Offset
+ // value as it currently is. This will be the end of the bad length field.
+ if (!P.totalLengthIsValid()) {
+ Done = true;
+ return;
+ }
+
+ Offset = OldOffset + P.TotalLength + P.sizeofTotalLength();
+ if (!DebugLineData.isValidOffset(Offset)) {
+ Done = true;
+ }
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
new file mode 100644
index 0000000000..f39c7871d6
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugLoc.cpp
@@ -0,0 +1,411 @@
+//===- DWARFDebugLoc.cpp --------------------------------------------------===//
+//
+// 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/DWARF/DWARFDebugLoc.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
+#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/Compiler.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cinttypes>
+#include <cstdint>
+
+using namespace llvm;
+using object::SectionedAddress;
+
+namespace {
+class DWARFLocationInterpreter {
+ Optional<object::SectionedAddress> Base;
+ std::function<Optional<object::SectionedAddress>(uint32_t)> LookupAddr;
+
+public:
+ DWARFLocationInterpreter(
+ Optional<object::SectionedAddress> Base,
+ std::function<Optional<object::SectionedAddress>(uint32_t)> LookupAddr)
+ : Base(Base), LookupAddr(std::move(LookupAddr)) {}
+
+ Expected<Optional<DWARFLocationExpression>>
+ Interpret(const DWARFLocationEntry &E);
+};
+} // namespace
+
+static Error createResolverError(uint32_t Index, unsigned Kind) {
+ return make_error<ResolverError>(Index, (dwarf::LoclistEntries)Kind);
+}
+
+Expected<Optional<DWARFLocationExpression>>
+DWARFLocationInterpreter::Interpret(const DWARFLocationEntry &E) {
+ switch (E.Kind) {
+ case dwarf::DW_LLE_end_of_list:
+ return None;
+ case dwarf::DW_LLE_base_addressx: {
+ Base = LookupAddr(E.Value0);
+ if (!Base)
+ return createResolverError(E.Value0, E.Kind);
+ return None;
+ }
+ case dwarf::DW_LLE_startx_endx: {
+ Optional<SectionedAddress> LowPC = LookupAddr(E.Value0);
+ if (!LowPC)
+ return createResolverError(E.Value0, E.Kind);
+ Optional<SectionedAddress> HighPC = LookupAddr(E.Value1);
+ if (!HighPC)
+ return createResolverError(E.Value1, E.Kind);
+ return DWARFLocationExpression{
+ DWARFAddressRange{LowPC->Address, HighPC->Address, LowPC->SectionIndex},
+ E.Loc};
+ }
+ case dwarf::DW_LLE_startx_length: {
+ Optional<SectionedAddress> LowPC = LookupAddr(E.Value0);
+ if (!LowPC)
+ return createResolverError(E.Value0, E.Kind);
+ return DWARFLocationExpression{DWARFAddressRange{LowPC->Address,
+ LowPC->Address + E.Value1,
+ LowPC->SectionIndex},
+ E.Loc};
+ }
+ case dwarf::DW_LLE_offset_pair: {
+ if (!Base) {
+ return createStringError(inconvertibleErrorCode(),
+ "Unable to resolve location list offset pair: "
+ "Base address not defined");
+ }
+ DWARFAddressRange Range{Base->Address + E.Value0, Base->Address + E.Value1,
+ Base->SectionIndex};
+ if (Range.SectionIndex == SectionedAddress::UndefSection)
+ Range.SectionIndex = E.SectionIndex;
+ return DWARFLocationExpression{Range, E.Loc};
+ }
+ case dwarf::DW_LLE_default_location:
+ return DWARFLocationExpression{None, E.Loc};
+ case dwarf::DW_LLE_base_address:
+ Base = SectionedAddress{E.Value0, E.SectionIndex};
+ return None;
+ case dwarf::DW_LLE_start_end:
+ return DWARFLocationExpression{
+ DWARFAddressRange{E.Value0, E.Value1, E.SectionIndex}, E.Loc};
+ case dwarf::DW_LLE_start_length:
+ return DWARFLocationExpression{
+ DWARFAddressRange{E.Value0, E.Value0 + E.Value1, E.SectionIndex},
+ E.Loc};
+ default:
+ llvm_unreachable("unreachable locations list kind");
+ }
+}
+
+static void dumpExpression(raw_ostream &OS, DIDumpOptions DumpOpts,
+ ArrayRef<uint8_t> Data, bool IsLittleEndian,
+ unsigned AddressSize, const MCRegisterInfo *MRI,
+ DWARFUnit *U) {
+ DWARFDataExtractor Extractor(Data, IsLittleEndian, AddressSize);
+ // Note. We do not pass any format to DWARFExpression, even if the
+ // corresponding unit is known. For now, there is only one operation,
+ // DW_OP_call_ref, which depends on the format; it is rarely used, and
+ // is unexpected in location tables.
+ DWARFExpression(Extractor, AddressSize).print(OS, DumpOpts, MRI, U);
+}
+
+bool DWARFLocationTable::dumpLocationList(uint64_t *Offset, raw_ostream &OS,
+ Optional<SectionedAddress> BaseAddr,
+ const MCRegisterInfo *MRI,
+ const DWARFObject &Obj, DWARFUnit *U,
+ DIDumpOptions DumpOpts,
+ unsigned Indent) const {
+ DWARFLocationInterpreter Interp(
+ BaseAddr, [U](uint32_t Index) -> Optional<SectionedAddress> {
+ if (U)
+ return U->getAddrOffsetSectionItem(Index);
+ return None;
+ });
+ OS << format("0x%8.8" PRIx64 ": ", *Offset);
+ Error E = visitLocationList(Offset, [&](const DWARFLocationEntry &E) {
+ Expected<Optional<DWARFLocationExpression>> Loc = Interp.Interpret(E);
+ if (!Loc || DumpOpts.DisplayRawContents)
+ dumpRawEntry(E, OS, Indent, DumpOpts, Obj);
+ if (Loc && *Loc) {
+ OS << "\n";
+ OS.indent(Indent);
+ if (DumpOpts.DisplayRawContents)
+ OS << " => ";
+
+ DIDumpOptions RangeDumpOpts(DumpOpts);
+ RangeDumpOpts.DisplayRawContents = false;
+ if (Loc.get()->Range)
+ Loc.get()->Range->dump(OS, Data.getAddressSize(), RangeDumpOpts, &Obj);
+ else
+ OS << "<default>";
+ }
+ if (!Loc)
+ consumeError(Loc.takeError());
+
+ if (E.Kind != dwarf::DW_LLE_base_address &&
+ E.Kind != dwarf::DW_LLE_base_addressx &&
+ E.Kind != dwarf::DW_LLE_end_of_list) {
+ OS << ": ";
+ dumpExpression(OS, DumpOpts, E.Loc, Data.isLittleEndian(),
+ Data.getAddressSize(), MRI, U);
+ }
+ return true;
+ });
+ if (E) {
+ DumpOpts.RecoverableErrorHandler(std::move(E));
+ return false;
+ }
+ return true;
+}
+
+Error DWARFLocationTable::visitAbsoluteLocationList(
+ uint64_t Offset, Optional<SectionedAddress> BaseAddr,
+ std::function<Optional<SectionedAddress>(uint32_t)> LookupAddr,
+ function_ref<bool(Expected<DWARFLocationExpression>)> Callback) const {
+ DWARFLocationInterpreter Interp(BaseAddr, std::move(LookupAddr));
+ return visitLocationList(&Offset, [&](const DWARFLocationEntry &E) {
+ Expected<Optional<DWARFLocationExpression>> Loc = Interp.Interpret(E);
+ if (!Loc)
+ return Callback(Loc.takeError());
+ if (*Loc)
+ return Callback(**Loc);
+ return true;
+ });
+}
+
+void DWARFDebugLoc::dump(raw_ostream &OS, const MCRegisterInfo *MRI,
+ const DWARFObject &Obj, DIDumpOptions DumpOpts,
+ Optional<uint64_t> DumpOffset) const {
+ auto BaseAddr = None;
+ unsigned Indent = 12;
+ if (DumpOffset) {
+ dumpLocationList(&*DumpOffset, OS, BaseAddr, MRI, Obj, nullptr, DumpOpts,
+ Indent);
+ } else {
+ uint64_t Offset = 0;
+ StringRef Separator;
+ bool CanContinue = true;
+ while (CanContinue && Data.isValidOffset(Offset)) {
+ OS << Separator;
+ Separator = "\n";
+
+ CanContinue = dumpLocationList(&Offset, OS, BaseAddr, MRI, Obj, nullptr,
+ DumpOpts, Indent);
+ OS << '\n';
+ }
+ }
+}
+
+Error DWARFDebugLoc::visitLocationList(
+ uint64_t *Offset,
+ function_ref<bool(const DWARFLocationEntry &)> Callback) const {
+ DataExtractor::Cursor C(*Offset);
+ while (true) {
+ uint64_t SectionIndex;
+ uint64_t Value0 = Data.getRelocatedAddress(C);
+ uint64_t Value1 = Data.getRelocatedAddress(C, &SectionIndex);
+
+ DWARFLocationEntry E;
+
+ // The end of any given location list is marked by an end of list entry,
+ // which consists of a 0 for the beginning address offset and a 0 for the
+ // ending address offset. A beginning offset of 0xff...f marks the base
+ // address selection entry.
+ if (Value0 == 0 && Value1 == 0) {
+ E.Kind = dwarf::DW_LLE_end_of_list;
+ } else if (Value0 == (Data.getAddressSize() == 4 ? -1U : -1ULL)) {
+ E.Kind = dwarf::DW_LLE_base_address;
+ E.Value0 = Value1;
+ E.SectionIndex = SectionIndex;
+ } else {
+ E.Kind = dwarf::DW_LLE_offset_pair;
+ E.Value0 = Value0;
+ E.Value1 = Value1;
+ E.SectionIndex = SectionIndex;
+ unsigned Bytes = Data.getU16(C);
+ // A single location description describing the location of the object...
+ Data.getU8(C, E.Loc, Bytes);
+ }
+
+ if (!C)
+ return C.takeError();
+ if (!Callback(E) || E.Kind == dwarf::DW_LLE_end_of_list)
+ break;
+ }
+ *Offset = C.tell();
+ return Error::success();
+}
+
+void DWARFDebugLoc::dumpRawEntry(const DWARFLocationEntry &Entry,
+ raw_ostream &OS, unsigned Indent,
+ DIDumpOptions DumpOpts,
+ const DWARFObject &Obj) const {
+ uint64_t Value0, Value1;
+ switch (Entry.Kind) {
+ case dwarf::DW_LLE_base_address:
+ Value0 = Data.getAddressSize() == 4 ? -1U : -1ULL;
+ Value1 = Entry.Value0;
+ break;
+ case dwarf::DW_LLE_offset_pair:
+ Value0 = Entry.Value0;
+ Value1 = Entry.Value1;
+ break;
+ case dwarf::DW_LLE_end_of_list:
+ return;
+ default:
+ llvm_unreachable("Not possible in DWARF4!");
+ }
+ OS << '\n';
+ OS.indent(Indent);
+ OS << '(' << format_hex(Value0, 2 + Data.getAddressSize() * 2) << ", "
+ << format_hex(Value1, 2 + Data.getAddressSize() * 2) << ')';
+ DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, Entry.SectionIndex);
+}
+
+Error DWARFDebugLoclists::visitLocationList(
+ uint64_t *Offset, function_ref<bool(const DWARFLocationEntry &)> F) const {
+
+ DataExtractor::Cursor C(*Offset);
+ bool Continue = true;
+ while (Continue) {
+ DWARFLocationEntry E;
+ E.Kind = Data.getU8(C);
+ switch (E.Kind) {
+ case dwarf::DW_LLE_end_of_list:
+ break;
+ case dwarf::DW_LLE_base_addressx:
+ E.Value0 = Data.getULEB128(C);
+ break;
+ case dwarf::DW_LLE_startx_endx:
+ E.Value0 = Data.getULEB128(C);
+ E.Value1 = Data.getULEB128(C);
+ break;
+ case dwarf::DW_LLE_startx_length:
+ E.Value0 = Data.getULEB128(C);
+ // Pre-DWARF 5 has different interpretation of the length field. We have
+ // to support both pre- and standartized styles for the compatibility.
+ if (Version < 5)
+ E.Value1 = Data.getU32(C);
+ else
+ E.Value1 = Data.getULEB128(C);
+ break;
+ case dwarf::DW_LLE_offset_pair:
+ E.Value0 = Data.getULEB128(C);
+ E.Value1 = Data.getULEB128(C);
+ E.SectionIndex = SectionedAddress::UndefSection;
+ break;
+ case dwarf::DW_LLE_default_location:
+ break;
+ case dwarf::DW_LLE_base_address:
+ E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex);
+ break;
+ case dwarf::DW_LLE_start_end:
+ E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex);
+ E.Value1 = Data.getRelocatedAddress(C);
+ break;
+ case dwarf::DW_LLE_start_length:
+ E.Value0 = Data.getRelocatedAddress(C, &E.SectionIndex);
+ E.Value1 = Data.getULEB128(C);
+ break;
+ default:
+ cantFail(C.takeError());
+ return createStringError(errc::illegal_byte_sequence,
+ "LLE of kind %x not supported", (int)E.Kind);
+ }
+
+ if (E.Kind != dwarf::DW_LLE_base_address &&
+ E.Kind != dwarf::DW_LLE_base_addressx &&
+ E.Kind != dwarf::DW_LLE_end_of_list) {
+ unsigned Bytes = Version >= 5 ? Data.getULEB128(C) : Data.getU16(C);
+ // A single location description describing the location of the object...
+ Data.getU8(C, E.Loc, Bytes);
+ }
+
+ if (!C)
+ return C.takeError();
+ Continue = F(E) && E.Kind != dwarf::DW_LLE_end_of_list;
+ }
+ *Offset = C.tell();
+ return Error::success();
+}
+
+void DWARFDebugLoclists::dumpRawEntry(const DWARFLocationEntry &Entry,
+ raw_ostream &OS, unsigned Indent,
+ DIDumpOptions DumpOpts,
+ const DWARFObject &Obj) const {
+ size_t MaxEncodingStringLength = 0;
+#define HANDLE_DW_LLE(ID, NAME) \
+ MaxEncodingStringLength = std::max(MaxEncodingStringLength, \
+ dwarf::LocListEncodingString(ID).size());
+#include "llvm/BinaryFormat/Dwarf.def"
+
+ OS << "\n";
+ OS.indent(Indent);
+ StringRef EncodingString = dwarf::LocListEncodingString(Entry.Kind);
+ // Unsupported encodings should have been reported during parsing.
+ assert(!EncodingString.empty() && "Unknown loclist entry encoding");
+ OS << format("%-*s(", MaxEncodingStringLength, EncodingString.data());
+ unsigned FieldSize = 2 + 2 * Data.getAddressSize();
+ switch (Entry.Kind) {
+ case dwarf::DW_LLE_end_of_list:
+ case dwarf::DW_LLE_default_location:
+ break;
+ case dwarf::DW_LLE_startx_endx:
+ case dwarf::DW_LLE_startx_length:
+ case dwarf::DW_LLE_offset_pair:
+ case dwarf::DW_LLE_start_end:
+ case dwarf::DW_LLE_start_length:
+ OS << format_hex(Entry.Value0, FieldSize) << ", "
+ << format_hex(Entry.Value1, FieldSize);
+ break;
+ case dwarf::DW_LLE_base_addressx:
+ case dwarf::DW_LLE_base_address:
+ OS << format_hex(Entry.Value0, FieldSize);
+ break;
+ }
+ OS << ')';
+ switch (Entry.Kind) {
+ case dwarf::DW_LLE_base_address:
+ case dwarf::DW_LLE_start_end:
+ case dwarf::DW_LLE_start_length:
+ DWARFFormValue::dumpAddressSection(Obj, OS, DumpOpts, Entry.SectionIndex);
+ break;
+ default:
+ break;
+ }
+}
+
+void DWARFDebugLoclists::dumpRange(uint64_t StartOffset, uint64_t Size,
+ raw_ostream &OS, const MCRegisterInfo *MRI,
+ const DWARFObject &Obj,
+ DIDumpOptions DumpOpts) {
+ if (!Data.isValidOffsetForDataOfSize(StartOffset, Size)) {
+ OS << "Invalid dump range\n";
+ return;
+ }
+ uint64_t Offset = StartOffset;
+ StringRef Separator;
+ bool CanContinue = true;
+ while (CanContinue && Offset < StartOffset + Size) {
+ OS << Separator;
+ Separator = "\n";
+
+ CanContinue = dumpLocationList(&Offset, OS, /*BaseAddr=*/None, MRI, Obj,
+ nullptr, DumpOpts, /*Indent=*/12);
+ OS << '\n';
+ }
+}
+
+void llvm::ResolverError::log(raw_ostream &OS) const {
+ OS << format("unable to resolve indirect address %u for: %s", Index,
+ dwarf::LocListEncodingString(Kind).data());
+}
+
+char llvm::ResolverError::ID;
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp
new file mode 100644
index 0000000000..7a81d7ff06
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugMacro.cpp
@@ -0,0 +1,243 @@
+//===- DWARFDebugMacro.cpp ------------------------------------------------===//
+//
+// 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/DWARF/DWARFDebugMacro.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+
+using namespace llvm;
+using namespace dwarf;
+
+DwarfFormat DWARFDebugMacro::MacroHeader::getDwarfFormat() const {
+ return Flags & MACRO_OFFSET_SIZE ? DWARF64 : DWARF32;
+}
+
+uint8_t DWARFDebugMacro::MacroHeader::getOffsetByteSize() const {
+ return getDwarfOffsetByteSize(getDwarfFormat());
+}
+
+void DWARFDebugMacro::MacroHeader::dumpMacroHeader(raw_ostream &OS) const {
+ // FIXME: Add support for dumping opcode_operands_table
+ OS << format("macro header: version = 0x%04" PRIx16, Version)
+ << format(", flags = 0x%02" PRIx8, Flags)
+ << ", format = " << FormatString(getDwarfFormat());
+ if (Flags & MACRO_DEBUG_LINE_OFFSET)
+ OS << format(", debug_line_offset = 0x%0*" PRIx64, 2 * getOffsetByteSize(),
+ DebugLineOffset);
+ OS << "\n";
+}
+
+void DWARFDebugMacro::dump(raw_ostream &OS) const {
+ unsigned IndLevel = 0;
+ for (const auto &Macros : MacroLists) {
+ OS << format("0x%08" PRIx64 ":\n", Macros.Offset);
+ if (Macros.IsDebugMacro)
+ Macros.Header.dumpMacroHeader(OS);
+ for (const Entry &E : Macros.Macros) {
+ // There should not be DW_MACINFO_end_file when IndLevel is Zero. However,
+ // this check handles the case of corrupted ".debug_macinfo" section.
+ if (IndLevel > 0)
+ IndLevel -= (E.Type == DW_MACINFO_end_file);
+ // Print indentation.
+ for (unsigned I = 0; I < IndLevel; I++)
+ OS << " ";
+ IndLevel += (E.Type == DW_MACINFO_start_file);
+ // Based on which version we are handling choose appropriate macro forms.
+ if (Macros.IsDebugMacro)
+ WithColor(OS, HighlightColor::Macro).get()
+ << (Macros.Header.Version < 5 ? GnuMacroString(E.Type)
+ : MacroString(E.Type));
+ else
+ WithColor(OS, HighlightColor::Macro).get() << MacinfoString(E.Type);
+ switch (E.Type) {
+ default:
+ // Got a corrupted ".debug_macinfo/.debug_macro" section (invalid
+ // macinfo type).
+ break;
+ // debug_macro and debug_macinfo share some common encodings.
+ // DW_MACRO_define == DW_MACINFO_define
+ // DW_MACRO_undef == DW_MACINFO_undef
+ // DW_MACRO_start_file == DW_MACINFO_start_file
+ // DW_MACRO_end_file == DW_MACINFO_end_file
+ // For readability/uniformity we are using DW_MACRO_*.
+ //
+ // The GNU .debug_macro extension's entries have the same encoding
+ // as DWARF 5's DW_MACRO_* entries, so we only use the latter here.
+ case DW_MACRO_define:
+ case DW_MACRO_undef:
+ case DW_MACRO_define_strp:
+ case DW_MACRO_undef_strp:
+ case DW_MACRO_define_strx:
+ case DW_MACRO_undef_strx:
+ OS << " - lineno: " << E.Line;
+ OS << " macro: " << E.MacroStr;
+ break;
+ case DW_MACRO_start_file:
+ OS << " - lineno: " << E.Line;
+ OS << " filenum: " << E.File;
+ break;
+ case DW_MACRO_import:
+ OS << format(" - import offset: 0x%0*" PRIx64,
+ 2 * Macros.Header.getOffsetByteSize(), E.ImportOffset);
+ break;
+ case DW_MACRO_end_file:
+ break;
+ case DW_MACINFO_vendor_ext:
+ OS << " - constant: " << E.ExtConstant;
+ OS << " string: " << E.ExtStr;
+ break;
+ }
+ OS << "\n";
+ }
+ }
+}
+
+Error DWARFDebugMacro::parseImpl(
+ Optional<DWARFUnitVector::compile_unit_range> Units,
+ Optional<DataExtractor> StringExtractor, DWARFDataExtractor Data,
+ bool IsMacro) {
+ uint64_t Offset = 0;
+ MacroList *M = nullptr;
+ using MacroToUnitsMap = DenseMap<uint64_t, DWARFUnit *>;
+ MacroToUnitsMap MacroToUnits;
+ if (IsMacro && Data.isValidOffset(Offset)) {
+ // Keep a mapping from Macro contribution to CUs, this will
+ // be needed while retrieving macro from DW_MACRO_define_strx form.
+ for (const auto &U : Units.getValue())
+ if (auto CUDIE = U->getUnitDIE())
+ // Skip units which does not contibutes to macro section.
+ if (auto MacroOffset = toSectionOffset(CUDIE.find(DW_AT_macros)))
+ MacroToUnits.try_emplace(*MacroOffset, U.get());
+ }
+ while (Data.isValidOffset(Offset)) {
+ if (!M) {
+ MacroLists.emplace_back();
+ M = &MacroLists.back();
+ M->Offset = Offset;
+ M->IsDebugMacro = IsMacro;
+ if (IsMacro) {
+ auto Err = M->Header.parseMacroHeader(Data, &Offset);
+ if (Err)
+ return Err;
+ }
+ }
+ // A macro list entry consists of:
+ M->Macros.emplace_back();
+ Entry &E = M->Macros.back();
+ // 1. Macinfo type
+ E.Type = Data.getULEB128(&Offset);
+
+ if (E.Type == 0) {
+ // Reached end of a ".debug_macinfo/debug_macro" section contribution.
+ M = nullptr;
+ continue;
+ }
+
+ switch (E.Type) {
+ default:
+ // Got a corrupted ".debug_macinfo" section (invalid macinfo type).
+ // Push the corrupted entry to the list and halt parsing.
+ E.Type = DW_MACINFO_invalid;
+ return Error::success();
+ // debug_macro and debug_macinfo share some common encodings.
+ // DW_MACRO_define == DW_MACINFO_define
+ // DW_MACRO_undef == DW_MACINFO_undef
+ // DW_MACRO_start_file == DW_MACINFO_start_file
+ // DW_MACRO_end_file == DW_MACINFO_end_file
+ // For readibility/uniformity we are using DW_MACRO_*.
+ case DW_MACRO_define:
+ case DW_MACRO_undef:
+ // 2. Source line
+ E.Line = Data.getULEB128(&Offset);
+ // 3. Macro string
+ E.MacroStr = Data.getCStr(&Offset);
+ break;
+ case DW_MACRO_define_strp:
+ case DW_MACRO_undef_strp: {
+ if (!IsMacro) {
+ // DW_MACRO_define_strp is a new form introduced in DWARFv5, it is
+ // not supported in debug_macinfo[.dwo] sections. Assume it as an
+ // invalid entry, push it and halt parsing.
+ E.Type = DW_MACINFO_invalid;
+ return Error::success();
+ }
+ uint64_t StrOffset = 0;
+ // 2. Source line
+ E.Line = Data.getULEB128(&Offset);
+ // 3. Macro string
+ StrOffset =
+ Data.getRelocatedValue(M->Header.getOffsetByteSize(), &Offset);
+ assert(StringExtractor && "String Extractor not found");
+ E.MacroStr = StringExtractor->getCStr(&StrOffset);
+ break;
+ }
+ case DW_MACRO_define_strx:
+ case DW_MACRO_undef_strx: {
+ if (!IsMacro) {
+ // DW_MACRO_define_strx is a new form introduced in DWARFv5, it is
+ // not supported in debug_macinfo[.dwo] sections. Assume it as an
+ // invalid entry, push it and halt parsing.
+ E.Type = DW_MACINFO_invalid;
+ return Error::success();
+ }
+ E.Line = Data.getULEB128(&Offset);
+ auto MacroContributionOffset = MacroToUnits.find(M->Offset);
+ if (MacroContributionOffset == MacroToUnits.end())
+ return createStringError(errc::invalid_argument,
+ "Macro contribution of the unit not found");
+ Expected<uint64_t> StrOffset =
+ MacroContributionOffset->second->getStringOffsetSectionItem(
+ Data.getULEB128(&Offset));
+ if (!StrOffset)
+ return StrOffset.takeError();
+ E.MacroStr =
+ MacroContributionOffset->second->getStringExtractor().getCStr(
+ &*StrOffset);
+ break;
+ }
+ case DW_MACRO_start_file:
+ // 2. Source line
+ E.Line = Data.getULEB128(&Offset);
+ // 3. Source file id
+ E.File = Data.getULEB128(&Offset);
+ break;
+ case DW_MACRO_end_file:
+ break;
+ case DW_MACRO_import:
+ E.ImportOffset =
+ Data.getRelocatedValue(M->Header.getOffsetByteSize(), &Offset);
+ break;
+ case DW_MACINFO_vendor_ext:
+ // 2. Vendor extension constant
+ E.ExtConstant = Data.getULEB128(&Offset);
+ // 3. Vendor extension string
+ E.ExtStr = Data.getCStr(&Offset);
+ break;
+ }
+ }
+ return Error::success();
+}
+
+Error DWARFDebugMacro::MacroHeader::parseMacroHeader(DWARFDataExtractor Data,
+ uint64_t *Offset) {
+ Version = Data.getU16(Offset);
+ uint8_t FlagData = Data.getU8(Offset);
+
+ // FIXME: Add support for parsing opcode_operands_table
+ if (FlagData & MACRO_OPCODE_OPERANDS_TABLE)
+ return createStringError(errc::not_supported,
+ "opcode_operands_table is not supported");
+ Flags = FlagData;
+ if (Flags & MACRO_DEBUG_LINE_OFFSET)
+ DebugLineOffset = Data.getUnsigned(Offset, getOffsetByteSize());
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp
new file mode 100644
index 0000000000..5031acdb54
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp
@@ -0,0 +1,118 @@
+//===- DWARFDebugPubTable.cpp ---------------------------------------------===//
+//
+// 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/DWARF/DWARFDebugPubTable.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+
+using namespace llvm;
+using namespace dwarf;
+
+void DWARFDebugPubTable::extract(
+ DWARFDataExtractor Data, bool GnuStyle,
+ function_ref<void(Error)> RecoverableErrorHandler) {
+ this->GnuStyle = GnuStyle;
+ Sets.clear();
+ uint64_t Offset = 0;
+ while (Data.isValidOffset(Offset)) {
+ uint64_t SetOffset = Offset;
+ Sets.push_back({});
+ Set &NewSet = Sets.back();
+
+ DataExtractor::Cursor C(Offset);
+ std::tie(NewSet.Length, NewSet.Format) = Data.getInitialLength(C);
+ if (!C) {
+ // Drop the newly added set because it does not contain anything useful
+ // to dump.
+ Sets.pop_back();
+ RecoverableErrorHandler(createStringError(
+ errc::invalid_argument,
+ "name lookup table at offset 0x%" PRIx64 " parsing failed: %s",
+ SetOffset, toString(C.takeError()).c_str()));
+ return;
+ }
+
+ Offset = C.tell() + NewSet.Length;
+ DWARFDataExtractor SetData(Data, Offset);
+ const unsigned OffsetSize = dwarf::getDwarfOffsetByteSize(NewSet.Format);
+
+ NewSet.Version = SetData.getU16(C);
+ NewSet.Offset = SetData.getRelocatedValue(C, OffsetSize);
+ NewSet.Size = SetData.getUnsigned(C, OffsetSize);
+
+ if (!C) {
+ // Preserve the newly added set because at least some fields of the header
+ // are read and can be dumped.
+ RecoverableErrorHandler(
+ createStringError(errc::invalid_argument,
+ "name lookup table at offset 0x%" PRIx64
+ " does not have a complete header: %s",
+ SetOffset, toString(C.takeError()).c_str()));
+ continue;
+ }
+
+ while (C) {
+ uint64_t DieRef = SetData.getUnsigned(C, OffsetSize);
+ if (DieRef == 0)
+ break;
+ uint8_t IndexEntryValue = GnuStyle ? SetData.getU8(C) : 0;
+ StringRef Name = SetData.getCStrRef(C);
+ if (C)
+ NewSet.Entries.push_back(
+ {DieRef, PubIndexEntryDescriptor(IndexEntryValue), Name});
+ }
+
+ if (!C) {
+ RecoverableErrorHandler(createStringError(
+ errc::invalid_argument,
+ "name lookup table at offset 0x%" PRIx64 " parsing failed: %s",
+ SetOffset, toString(C.takeError()).c_str()));
+ continue;
+ }
+ if (C.tell() != Offset)
+ RecoverableErrorHandler(createStringError(
+ errc::invalid_argument,
+ "name lookup table at offset 0x%" PRIx64
+ " has a terminator at offset 0x%" PRIx64
+ " before the expected end at 0x%" PRIx64,
+ SetOffset, C.tell() - OffsetSize, Offset - OffsetSize));
+ }
+}
+
+void DWARFDebugPubTable::dump(raw_ostream &OS) const {
+ for (const Set &S : Sets) {
+ int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(S.Format);
+ OS << "length = " << format("0x%0*" PRIx64, OffsetDumpWidth, S.Length);
+ OS << ", format = " << dwarf::FormatString(S.Format);
+ OS << ", version = " << format("0x%04x", S.Version);
+ OS << ", unit_offset = "
+ << format("0x%0*" PRIx64, OffsetDumpWidth, S.Offset);
+ OS << ", unit_size = " << format("0x%0*" PRIx64, OffsetDumpWidth, S.Size)
+ << '\n';
+ OS << (GnuStyle ? "Offset Linkage Kind Name\n"
+ : "Offset Name\n");
+
+ for (const Entry &E : S.Entries) {
+ OS << format("0x%0*" PRIx64 " ", OffsetDumpWidth, E.SecOffset);
+ if (GnuStyle) {
+ StringRef EntryLinkage =
+ GDBIndexEntryLinkageString(E.Descriptor.Linkage);
+ StringRef EntryKind = dwarf::GDBIndexEntryKindString(E.Descriptor.Kind);
+ OS << format("%-8s", EntryLinkage.data()) << ' '
+ << format("%-8s", EntryKind.data()) << ' ';
+ }
+ OS << '\"' << E.Name << "\"\n";
+ }
+ }
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
new file mode 100644
index 0000000000..cad3dcab8a
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugRangeList.cpp
@@ -0,0 +1,119 @@
+//===- DWARFDebugRangesList.cpp -------------------------------------------===//
+//
+// 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/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cinttypes>
+#include <cstdint>
+
+using namespace llvm;
+
+bool DWARFDebugRangeList::RangeListEntry::isBaseAddressSelectionEntry(
+ uint8_t AddressSize) const {
+ assert(DWARFContext::isAddressSizeSupported(AddressSize));
+ return StartAddress == dwarf::computeTombstoneAddress(AddressSize);
+}
+
+void DWARFDebugRangeList::clear() {
+ Offset = -1ULL;
+ AddressSize = 0;
+ Entries.clear();
+}
+
+Error DWARFDebugRangeList::extract(const DWARFDataExtractor &data,
+ uint64_t *offset_ptr) {
+ clear();
+ if (!data.isValidOffset(*offset_ptr))
+ return createStringError(errc::invalid_argument,
+ "invalid range list offset 0x%" PRIx64, *offset_ptr);
+
+ AddressSize = data.getAddressSize();
+ if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
+ AddressSize, errc::invalid_argument,
+ "range list at offset 0x%" PRIx64, *offset_ptr))
+ return SizeErr;
+ Offset = *offset_ptr;
+ while (true) {
+ RangeListEntry Entry;
+ Entry.SectionIndex = -1ULL;
+
+ uint64_t prev_offset = *offset_ptr;
+ Entry.StartAddress = data.getRelocatedAddress(offset_ptr);
+ Entry.EndAddress =
+ data.getRelocatedAddress(offset_ptr, &Entry.SectionIndex);
+
+ // Check that both values were extracted correctly.
+ if (*offset_ptr != prev_offset + 2 * AddressSize) {
+ clear();
+ return createStringError(errc::invalid_argument,
+ "invalid range list entry at offset 0x%" PRIx64,
+ prev_offset);
+ }
+ if (Entry.isEndOfListEntry())
+ break;
+ Entries.push_back(Entry);
+ }
+ return Error::success();
+}
+
+void DWARFDebugRangeList::dump(raw_ostream &OS) const {
+ const char *AddrFmt;
+ switch (AddressSize) {
+ case 2:
+ AddrFmt = "%08" PRIx64 " %04" PRIx64 " %04" PRIx64 "\n";
+ break;
+ case 4:
+ AddrFmt = "%08" PRIx64 " %08" PRIx64 " %08" PRIx64 "\n";
+ break;
+ case 8:
+ AddrFmt = "%08" PRIx64 " %016" PRIx64 " %016" PRIx64 "\n";
+ break;
+ default:
+ llvm_unreachable("unsupported address size");
+ }
+ for (const RangeListEntry &RLE : Entries)
+ OS << format(AddrFmt, Offset, RLE.StartAddress, RLE.EndAddress);
+ OS << format("%08" PRIx64 " <End of list>\n", Offset);
+}
+
+DWARFAddressRangesVector DWARFDebugRangeList::getAbsoluteRanges(
+ llvm::Optional<object::SectionedAddress> BaseAddr) const {
+ DWARFAddressRangesVector Res;
+ // debug_addr can't use the max integer tombstone because that's used for the
+ // base address specifier entry - so use max-1.
+ uint64_t Tombstone = dwarf::computeTombstoneAddress(AddressSize) - 1;
+ for (const RangeListEntry &RLE : Entries) {
+ if (RLE.isBaseAddressSelectionEntry(AddressSize)) {
+ BaseAddr = {RLE.EndAddress, RLE.SectionIndex};
+ continue;
+ }
+
+ DWARFAddressRange E;
+ E.LowPC = RLE.StartAddress;
+ if (E.LowPC == Tombstone)
+ continue;
+ E.HighPC = RLE.EndAddress;
+ E.SectionIndex = RLE.SectionIndex;
+ // Base address of a range list entry is determined by the closest preceding
+ // base address selection entry in the same range list. It defaults to the
+ // base address of the compilation unit if there is no such entry.
+ if (BaseAddr) {
+ if (BaseAddr->Address == Tombstone)
+ continue;
+ E.LowPC += BaseAddr->Address;
+ E.HighPC += BaseAddr->Address;
+ if (E.SectionIndex == -1ULL)
+ E.SectionIndex = BaseAddr->SectionIndex;
+ }
+ Res.push_back(E);
+ }
+ return Res;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
new file mode 100644
index 0000000000..d12acca196
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDebugRnglists.cpp
@@ -0,0 +1,263 @@
+//===- DWARFDebugRnglists.cpp ---------------------------------------------===//
+//
+// 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/DWARF/DWARFDebugRnglists.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+Error RangeListEntry::extract(DWARFDataExtractor Data, uint64_t *OffsetPtr) {
+ Offset = *OffsetPtr;
+ SectionIndex = -1ULL;
+ // The caller should guarantee that we have at least 1 byte available, so
+ // we just assert instead of revalidate.
+ assert(*OffsetPtr < Data.size() &&
+ "not enough space to extract a rangelist encoding");
+ uint8_t Encoding = Data.getU8(OffsetPtr);
+
+ DataExtractor::Cursor C(*OffsetPtr);
+ switch (Encoding) {
+ case dwarf::DW_RLE_end_of_list:
+ Value0 = Value1 = 0;
+ break;
+ // TODO: Support other encodings.
+ case dwarf::DW_RLE_base_addressx: {
+ Value0 = Data.getULEB128(C);
+ break;
+ }
+ case dwarf::DW_RLE_startx_endx:
+ Value0 = Data.getULEB128(C);
+ Value1 = Data.getULEB128(C);
+ break;
+ case dwarf::DW_RLE_startx_length: {
+ Value0 = Data.getULEB128(C);
+ Value1 = Data.getULEB128(C);
+ break;
+ }
+ case dwarf::DW_RLE_offset_pair: {
+ Value0 = Data.getULEB128(C);
+ Value1 = Data.getULEB128(C);
+ break;
+ }
+ case dwarf::DW_RLE_base_address: {
+ Value0 = Data.getRelocatedAddress(C, &SectionIndex);
+ break;
+ }
+ case dwarf::DW_RLE_start_end: {
+ Value0 = Data.getRelocatedAddress(C, &SectionIndex);
+ Value1 = Data.getRelocatedAddress(C);
+ break;
+ }
+ case dwarf::DW_RLE_start_length: {
+ Value0 = Data.getRelocatedAddress(C, &SectionIndex);
+ Value1 = Data.getULEB128(C);
+ break;
+ }
+ default:
+ consumeError(C.takeError());
+ return createStringError(errc::not_supported,
+ "unknown rnglists encoding 0x%" PRIx32
+ " at offset 0x%" PRIx64,
+ uint32_t(Encoding), Offset);
+ }
+
+ if (!C) {
+ consumeError(C.takeError());
+ return createStringError(
+ errc::invalid_argument,
+ "read past end of table when reading %s encoding at offset 0x%" PRIx64,
+ dwarf::RLEString(Encoding).data(), Offset);
+ }
+
+ *OffsetPtr = C.tell();
+ EntryKind = Encoding;
+ return Error::success();
+}
+
+DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
+ llvm::Optional<object::SectionedAddress> BaseAddr, DWARFUnit &U) const {
+ return getAbsoluteRanges(
+ BaseAddr, U.getAddressByteSize(),
+ [&](uint32_t Index) { return U.getAddrOffsetSectionItem(Index); });
+}
+
+DWARFAddressRangesVector DWARFDebugRnglist::getAbsoluteRanges(
+ Optional<object::SectionedAddress> BaseAddr, uint8_t AddressByteSize,
+ function_ref<Optional<object::SectionedAddress>(uint32_t)>
+ LookupPooledAddress) const {
+ DWARFAddressRangesVector Res;
+ uint64_t Tombstone = dwarf::computeTombstoneAddress(AddressByteSize);
+ for (const RangeListEntry &RLE : Entries) {
+ if (RLE.EntryKind == dwarf::DW_RLE_end_of_list)
+ break;
+ if (RLE.EntryKind == dwarf::DW_RLE_base_addressx) {
+ BaseAddr = LookupPooledAddress(RLE.Value0);
+ if (!BaseAddr)
+ BaseAddr = {RLE.Value0, -1ULL};
+ continue;
+ }
+ if (RLE.EntryKind == dwarf::DW_RLE_base_address) {
+ BaseAddr = {RLE.Value0, RLE.SectionIndex};
+ continue;
+ }
+
+ DWARFAddressRange E;
+ E.SectionIndex = RLE.SectionIndex;
+ if (BaseAddr && E.SectionIndex == -1ULL)
+ E.SectionIndex = BaseAddr->SectionIndex;
+
+ switch (RLE.EntryKind) {
+ case dwarf::DW_RLE_offset_pair:
+ E.LowPC = RLE.Value0;
+ if (E.LowPC == Tombstone)
+ continue;
+ E.HighPC = RLE.Value1;
+ if (BaseAddr) {
+ if (BaseAddr->Address == Tombstone)
+ continue;
+ E.LowPC += BaseAddr->Address;
+ E.HighPC += BaseAddr->Address;
+ }
+ break;
+ case dwarf::DW_RLE_start_end:
+ E.LowPC = RLE.Value0;
+ E.HighPC = RLE.Value1;
+ break;
+ case dwarf::DW_RLE_start_length:
+ E.LowPC = RLE.Value0;
+ E.HighPC = E.LowPC + RLE.Value1;
+ break;
+ case dwarf::DW_RLE_startx_length: {
+ auto Start = LookupPooledAddress(RLE.Value0);
+ if (!Start)
+ Start = {0, -1ULL};
+ E.SectionIndex = Start->SectionIndex;
+ E.LowPC = Start->Address;
+ E.HighPC = E.LowPC + RLE.Value1;
+ break;
+ }
+ case dwarf::DW_RLE_startx_endx: {
+ auto Start = LookupPooledAddress(RLE.Value0);
+ if (!Start)
+ Start = {0, -1ULL};
+ auto End = LookupPooledAddress(RLE.Value1);
+ if (!End)
+ End = {0, -1ULL};
+ // FIXME: Some error handling if Start.SectionIndex != End.SectionIndex
+ E.SectionIndex = Start->SectionIndex;
+ E.LowPC = Start->Address;
+ E.HighPC = End->Address;
+ break;
+ }
+ default:
+ // Unsupported encodings should have been reported during extraction,
+ // so we should not run into any here.
+ llvm_unreachable("Unsupported range list encoding");
+ }
+ if (E.LowPC == Tombstone)
+ continue;
+ Res.push_back(E);
+ }
+ return Res;
+}
+
+void RangeListEntry::dump(
+ raw_ostream &OS, uint8_t AddrSize, uint8_t MaxEncodingStringLength,
+ uint64_t &CurrentBase, DIDumpOptions DumpOpts,
+ llvm::function_ref<Optional<object::SectionedAddress>(uint32_t)>
+ LookupPooledAddress) const {
+ auto PrintRawEntry = [](raw_ostream &OS, const RangeListEntry &Entry,
+ uint8_t AddrSize, DIDumpOptions DumpOpts) {
+ if (DumpOpts.Verbose) {
+ DumpOpts.DisplayRawContents = true;
+ DWARFAddressRange(Entry.Value0, Entry.Value1)
+ .dump(OS, AddrSize, DumpOpts);
+ OS << " => ";
+ }
+ };
+
+ if (DumpOpts.Verbose) {
+ // Print the section offset in verbose mode.
+ OS << format("0x%8.8" PRIx64 ":", Offset);
+ auto EncodingString = dwarf::RangeListEncodingString(EntryKind);
+ // Unsupported encodings should have been reported during parsing.
+ assert(!EncodingString.empty() && "Unknown range entry encoding");
+ OS << format(" [%s%*c", EncodingString.data(),
+ MaxEncodingStringLength - EncodingString.size() + 1, ']');
+ if (EntryKind != dwarf::DW_RLE_end_of_list)
+ OS << ": ";
+ }
+
+ uint64_t Tombstone = dwarf::computeTombstoneAddress(AddrSize);
+
+ switch (EntryKind) {
+ case dwarf::DW_RLE_end_of_list:
+ OS << (DumpOpts.Verbose ? "" : "<End of list>");
+ break;
+ case dwarf::DW_RLE_base_addressx: {
+ if (auto SA = LookupPooledAddress(Value0))
+ CurrentBase = SA->Address;
+ else
+ CurrentBase = Value0;
+ if (!DumpOpts.Verbose)
+ return;
+ DWARFFormValue::dumpAddress(OS << ' ', AddrSize, Value0);
+ break;
+ }
+ case dwarf::DW_RLE_base_address:
+ // In non-verbose mode we do not print anything for this entry.
+ CurrentBase = Value0;
+ if (!DumpOpts.Verbose)
+ return;
+ DWARFFormValue::dumpAddress(OS << ' ', AddrSize, Value0);
+ break;
+ case dwarf::DW_RLE_start_length:
+ PrintRawEntry(OS, *this, AddrSize, DumpOpts);
+ DWARFAddressRange(Value0, Value0 + Value1).dump(OS, AddrSize, DumpOpts);
+ break;
+ case dwarf::DW_RLE_offset_pair:
+ PrintRawEntry(OS, *this, AddrSize, DumpOpts);
+ if (CurrentBase != Tombstone)
+ DWARFAddressRange(Value0 + CurrentBase, Value1 + CurrentBase)
+ .dump(OS, AddrSize, DumpOpts);
+ else
+ OS << "dead code";
+ break;
+ case dwarf::DW_RLE_start_end:
+ DWARFAddressRange(Value0, Value1).dump(OS, AddrSize, DumpOpts);
+ break;
+ case dwarf::DW_RLE_startx_length: {
+ PrintRawEntry(OS, *this, AddrSize, DumpOpts);
+ uint64_t Start = 0;
+ if (auto SA = LookupPooledAddress(Value0))
+ Start = SA->Address;
+ DWARFAddressRange(Start, Start + Value1).dump(OS, AddrSize, DumpOpts);
+ break;
+ }
+ case dwarf::DW_RLE_startx_endx: {
+ PrintRawEntry(OS, *this, AddrSize, DumpOpts);
+ uint64_t Start = 0;
+ if (auto SA = LookupPooledAddress(Value0))
+ Start = SA->Address;
+ uint64_t End = 0;
+ if (auto SA = LookupPooledAddress(Value1))
+ End = SA->Address;
+ DWARFAddressRange(Start, End).dump(OS, AddrSize, DumpOpts);
+ break;
+ }
+ default:
+ llvm_unreachable("Unsupported range list encoding");
+ }
+ OS << "\n";
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDie.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDie.cpp
new file mode 100644
index 0000000000..ec7889a372
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFDie.cpp
@@ -0,0 +1,1285 @@
+//===- DWARFDie.cpp -------------------------------------------------------===//
+//
+// 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/DWARF/DWARFDie.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRangeList.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatAdapters.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/MathExtras.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cinttypes>
+#include <cstdint>
+#include <string>
+#include <utility>
+
+using namespace llvm;
+using namespace dwarf;
+using namespace object;
+
+static void dumpApplePropertyAttribute(raw_ostream &OS, uint64_t Val) {
+ OS << " (";
+ do {
+ uint64_t Shift = countTrailingZeros(Val);
+ assert(Shift < 64 && "undefined behavior");
+ uint64_t Bit = 1ULL << Shift;
+ auto PropName = ApplePropertyString(Bit);
+ if (!PropName.empty())
+ OS << PropName;
+ else
+ OS << format("DW_APPLE_PROPERTY_0x%" PRIx64, Bit);
+ if (!(Val ^= Bit))
+ break;
+ OS << ", ";
+ } while (true);
+ OS << ")";
+}
+
+static void dumpRanges(const DWARFObject &Obj, raw_ostream &OS,
+ const DWARFAddressRangesVector &Ranges,
+ unsigned AddressSize, unsigned Indent,
+ const DIDumpOptions &DumpOpts) {
+ if (!DumpOpts.ShowAddresses)
+ return;
+
+ for (const DWARFAddressRange &R : Ranges) {
+ OS << '\n';
+ OS.indent(Indent);
+ R.dump(OS, AddressSize, DumpOpts, &Obj);
+ }
+}
+
+static void dumpLocationList(raw_ostream &OS, const DWARFFormValue &FormValue,
+ DWARFUnit *U, unsigned Indent,
+ DIDumpOptions DumpOpts) {
+ assert(FormValue.isFormClass(DWARFFormValue::FC_SectionOffset) &&
+ "bad FORM for location list");
+ DWARFContext &Ctx = U->getContext();
+ const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
+ uint64_t Offset = *FormValue.getAsSectionOffset();
+
+ if (FormValue.getForm() == DW_FORM_loclistx) {
+ FormValue.dump(OS, DumpOpts);
+
+ if (auto LoclistOffset = U->getLoclistOffset(Offset))
+ Offset = *LoclistOffset;
+ else
+ return;
+ }
+ U->getLocationTable().dumpLocationList(&Offset, OS, U->getBaseAddress(), MRI,
+ Ctx.getDWARFObj(), U, DumpOpts,
+ Indent);
+}
+
+static void dumpLocationExpr(raw_ostream &OS, const DWARFFormValue &FormValue,
+ DWARFUnit *U, unsigned Indent,
+ DIDumpOptions DumpOpts) {
+ assert((FormValue.isFormClass(DWARFFormValue::FC_Block) ||
+ FormValue.isFormClass(DWARFFormValue::FC_Exprloc)) &&
+ "bad FORM for location expression");
+ DWARFContext &Ctx = U->getContext();
+ const MCRegisterInfo *MRI = Ctx.getRegisterInfo();
+ ArrayRef<uint8_t> Expr = *FormValue.getAsBlock();
+ DataExtractor Data(StringRef((const char *)Expr.data(), Expr.size()),
+ Ctx.isLittleEndian(), 0);
+ DWARFExpression(Data, U->getAddressByteSize(), U->getFormParams().Format)
+ .print(OS, DumpOpts, MRI, U);
+}
+
+static DWARFDie resolveReferencedType(DWARFDie D,
+ dwarf::Attribute Attr = DW_AT_type) {
+ return D.getAttributeValueAsReferencedDie(Attr).resolveTypeUnitReference();
+}
+static DWARFDie resolveReferencedType(DWARFDie D, DWARFFormValue F) {
+ return D.getAttributeValueAsReferencedDie(F).resolveTypeUnitReference();
+}
+
+namespace {
+
+// FIXME: We should have pretty printers per language. Currently we print
+// everything as if it was C++ and fall back to the TAG type name.
+struct DWARFTypePrinter {
+ raw_ostream &OS;
+ bool Word = true;
+ bool EndedWithTemplate = false;
+
+ DWARFTypePrinter(raw_ostream &OS) : OS(OS) {}
+
+ /// Dump the name encoded in the type tag.
+ void appendTypeTagName(dwarf::Tag T) {
+ StringRef TagStr = TagString(T);
+ static constexpr StringRef Prefix = "DW_TAG_";
+ static constexpr StringRef Suffix = "_type";
+ if (!TagStr.startswith(Prefix) || !TagStr.endswith(Suffix))
+ return;
+ OS << TagStr.substr(Prefix.size(),
+ TagStr.size() - (Prefix.size() + Suffix.size()))
+ << " ";
+ }
+
+ void appendArrayType(const DWARFDie &D) {
+ for (const DWARFDie &C : D.children()) {
+ if (C.getTag() != DW_TAG_subrange_type)
+ continue;
+ Optional<uint64_t> LB;
+ Optional<uint64_t> Count;
+ Optional<uint64_t> UB;
+ Optional<unsigned> DefaultLB;
+ if (Optional<DWARFFormValue> L = C.find(DW_AT_lower_bound))
+ LB = L->getAsUnsignedConstant();
+ if (Optional<DWARFFormValue> CountV = C.find(DW_AT_count))
+ Count = CountV->getAsUnsignedConstant();
+ if (Optional<DWARFFormValue> UpperV = C.find(DW_AT_upper_bound))
+ UB = UpperV->getAsUnsignedConstant();
+ if (Optional<DWARFFormValue> LV =
+ D.getDwarfUnit()->getUnitDIE().find(DW_AT_language))
+ if (Optional<uint64_t> LC = LV->getAsUnsignedConstant())
+ if ((DefaultLB =
+ LanguageLowerBound(static_cast<dwarf::SourceLanguage>(*LC))))
+ if (LB && *LB == *DefaultLB)
+ LB = None;
+ if (!LB && !Count && !UB)
+ OS << "[]";
+ else if (!LB && (Count || UB) && DefaultLB)
+ OS << '[' << (Count ? *Count : *UB - *DefaultLB + 1) << ']';
+ else {
+ OS << "[[";
+ if (LB)
+ OS << *LB;
+ else
+ OS << '?';
+ OS << ", ";
+ if (Count)
+ if (LB)
+ OS << *LB + *Count;
+ else
+ OS << "? + " << *Count;
+ else if (UB)
+ OS << *UB + 1;
+ else
+ OS << '?';
+ OS << ")]";
+ }
+ }
+ EndedWithTemplate = false;
+ }
+
+ DWARFDie skipQualifiers(DWARFDie D) {
+ while (D && (D.getTag() == DW_TAG_const_type ||
+ D.getTag() == DW_TAG_volatile_type))
+ D = resolveReferencedType(D);
+ return D;
+ }
+
+ bool needsParens(DWARFDie D) {
+ D = skipQualifiers(D);
+ return D && (D.getTag() == DW_TAG_subroutine_type || D.getTag() == DW_TAG_array_type);
+ }
+
+ void appendPointerLikeTypeBefore(DWARFDie D, DWARFDie Inner, StringRef Ptr) {
+ appendQualifiedNameBefore(Inner);
+ if (Word)
+ OS << ' ';
+ if (needsParens(Inner))
+ OS << '(';
+ OS << Ptr;
+ Word = false;
+ EndedWithTemplate = false;
+ }
+
+ DWARFDie
+ appendUnqualifiedNameBefore(DWARFDie D,
+ std::string *OriginalFullName = nullptr) {
+ Word = true;
+ if (!D) {
+ OS << "void";
+ return DWARFDie();
+ }
+ DWARFDie InnerDIE;
+ auto Inner = [&] { return InnerDIE = resolveReferencedType(D); };
+ const dwarf::Tag T = D.getTag();
+ switch (T) {
+ case DW_TAG_pointer_type: {
+ appendPointerLikeTypeBefore(D, Inner(), "*");
+ break;
+ }
+ case DW_TAG_subroutine_type: {
+ appendQualifiedNameBefore(Inner());
+ if (Word) {
+ OS << ' ';
+ }
+ Word = false;
+ break;
+ }
+ case DW_TAG_array_type: {
+ appendQualifiedNameBefore(Inner());
+ break;
+ }
+ case DW_TAG_reference_type:
+ appendPointerLikeTypeBefore(D, Inner(), "&");
+ break;
+ case DW_TAG_rvalue_reference_type:
+ appendPointerLikeTypeBefore(D, Inner(), "&&");
+ break;
+ case DW_TAG_ptr_to_member_type: {
+ appendQualifiedNameBefore(Inner());
+ if (needsParens(InnerDIE))
+ OS << '(';
+ else if (Word)
+ OS << ' ';
+ if (DWARFDie Cont = resolveReferencedType(D, DW_AT_containing_type)) {
+ appendQualifiedName(Cont);
+ OS << "::";
+ }
+ OS << "*";
+ Word = false;
+ break;
+ }
+ case DW_TAG_const_type:
+ case DW_TAG_volatile_type:
+ appendConstVolatileQualifierBefore(D);
+ break;
+ case DW_TAG_namespace: {
+ if (const char *Name = dwarf::toString(D.find(DW_AT_name), nullptr))
+ OS << Name;
+ else
+ OS << "(anonymous namespace)";
+ break;
+ }
+ case DW_TAG_unspecified_type: {
+ StringRef TypeName = D.getShortName();
+ if (TypeName == "decltype(nullptr)")
+ TypeName = "std::nullptr_t";
+ Word = true;
+ OS << TypeName;
+ EndedWithTemplate = false;
+ break;
+ }
+ /*
+ case DW_TAG_structure_type:
+ case DW_TAG_class_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_base_type:
+ */
+ default: {
+ const char *NamePtr = dwarf::toString(D.find(DW_AT_name), nullptr);
+ if (!NamePtr) {
+ appendTypeTagName(D.getTag());
+ return DWARFDie();
+ }
+ Word = true;
+ StringRef Name = NamePtr;
+ static constexpr StringRef MangledPrefix = "_STN";
+ if (Name.startswith(MangledPrefix)) {
+ Name = Name.drop_front(MangledPrefix.size());
+ auto Separator = Name.find('|');
+ assert(Separator != StringRef::npos);
+ StringRef BaseName = Name.substr(0, Separator);
+ StringRef TemplateArgs = Name.substr(Separator + 1);
+ if (OriginalFullName)
+ *OriginalFullName = (BaseName + TemplateArgs).str();
+ Name = BaseName;
+ } else
+ EndedWithTemplate = Name.endswith(">");
+ OS << Name;
+ // This check would be insufficient for operator overloads like
+ // "operator>>" - but for now Clang doesn't try to simplify them, so this
+ // is OK. Add more nuanced operator overload handling here if/when needed.
+ if (Name.endswith(">"))
+ break;
+ if (!appendTemplateParameters(D))
+ break;
+
+ if (EndedWithTemplate)
+ OS << ' ';
+ OS << '>';
+ EndedWithTemplate = true;
+ Word = true;
+ break;
+ }
+ }
+ return InnerDIE;
+ }
+
+ void appendUnqualifiedNameAfter(DWARFDie D, DWARFDie Inner,
+ bool SkipFirstParamIfArtificial = false) {
+ if (!D)
+ return;
+ switch (D.getTag()) {
+ case DW_TAG_subroutine_type: {
+ appendSubroutineNameAfter(D, Inner, SkipFirstParamIfArtificial, false,
+ false);
+ break;
+ }
+ case DW_TAG_array_type: {
+ appendArrayType(D);
+ break;
+ }
+ case DW_TAG_const_type:
+ case DW_TAG_volatile_type:
+ appendConstVolatileQualifierAfter(D);
+ break;
+ case DW_TAG_ptr_to_member_type:
+ case DW_TAG_reference_type:
+ case DW_TAG_rvalue_reference_type:
+ case DW_TAG_pointer_type: {
+ if (needsParens(Inner))
+ OS << ')';
+ appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner),
+ /*SkipFirstParamIfArtificial=*/D.getTag() ==
+ DW_TAG_ptr_to_member_type);
+ break;
+ }
+ /*
+ case DW_TAG_structure_type:
+ case DW_TAG_class_type:
+ case DW_TAG_enumeration_type:
+ case DW_TAG_base_type:
+ case DW_TAG_namespace:
+ */
+ default:
+ break;
+ }
+ }
+
+ void appendQualifiedName(DWARFDie D) {
+ if (D)
+ appendScopes(D.getParent());
+ appendUnqualifiedName(D);
+ }
+ DWARFDie appendQualifiedNameBefore(DWARFDie D) {
+ if (D)
+ appendScopes(D.getParent());
+ return appendUnqualifiedNameBefore(D);
+ }
+ bool appendTemplateParameters(DWARFDie D, bool *FirstParameter = nullptr) {
+ bool FirstParameterValue = true;
+ bool IsTemplate = false;
+ if (!FirstParameter)
+ FirstParameter = &FirstParameterValue;
+ for (const DWARFDie &C : D) {
+ auto Sep = [&] {
+ if (*FirstParameter)
+ OS << '<';
+ else
+ OS << ", ";
+ IsTemplate = true;
+ EndedWithTemplate = false;
+ *FirstParameter = false;
+ };
+ if (C.getTag() == dwarf::DW_TAG_GNU_template_parameter_pack) {
+ IsTemplate = true;
+ appendTemplateParameters(C, FirstParameter);
+ }
+ if (C.getTag() == dwarf::DW_TAG_template_value_parameter) {
+ DWARFDie T = resolveReferencedType(C);
+ Sep();
+ if (T.getTag() == DW_TAG_enumeration_type) {
+ auto V = C.find(DW_AT_const_value);
+ bool FoundEnumerator = false;
+ for (const DWARFDie &Enumerator : T) {
+ auto EV = Enumerator.find(DW_AT_const_value);
+ if (V && EV &&
+ V->getAsSignedConstant() == EV->getAsSignedConstant()) {
+ if (T.find(DW_AT_enum_class)) {
+ appendQualifiedName(T);
+ OS << "::";
+ } else
+ appendScopes(T.getParent());
+ OS << Enumerator.getShortName();
+ FoundEnumerator = true;
+ break;
+ }
+ }
+ if (FoundEnumerator)
+ continue;
+ OS << '(';
+ appendQualifiedName(T);
+ OS << ')';
+ OS << to_string(*V->getAsSignedConstant());
+ continue;
+ }
+ // /Maybe/ we could do pointer type parameters, looking for the
+ // symbol in the ELF symbol table to get back to the variable...
+ // but probably not worth it.
+ if (T.getTag() == DW_TAG_pointer_type)
+ continue;
+ const char *RawName = dwarf::toString(T.find(DW_AT_name), nullptr);
+ assert(RawName);
+ StringRef Name = RawName;
+ auto V = C.find(DW_AT_const_value);
+ bool IsQualifiedChar = false;
+ if (Name == "bool") {
+ OS << (*V->getAsUnsignedConstant() ? "true" : "false");
+ } else if (Name == "short") {
+ OS << "(short)";
+ OS << to_string(*V->getAsSignedConstant());
+ } else if (Name == "unsigned short") {
+ OS << "(unsigned short)";
+ OS << to_string(*V->getAsSignedConstant());
+ } else if (Name == "int")
+ OS << to_string(*V->getAsSignedConstant());
+ else if (Name == "long") {
+ OS << to_string(*V->getAsSignedConstant());
+ OS << "L";
+ } else if (Name == "long long") {
+ OS << to_string(*V->getAsSignedConstant());
+ OS << "LL";
+ } else if (Name == "unsigned int") {
+ OS << to_string(*V->getAsUnsignedConstant());
+ OS << "U";
+ } else if (Name == "unsigned long") {
+ OS << to_string(*V->getAsUnsignedConstant());
+ OS << "UL";
+ } else if (Name == "unsigned long long") {
+ OS << to_string(*V->getAsUnsignedConstant());
+ OS << "ULL";
+ } else if (Name == "char" ||
+ (IsQualifiedChar =
+ (Name == "unsigned char" || Name == "signed char"))) {
+ // FIXME: check T's DW_AT_type to see if it's signed or not (since
+ // char signedness is implementation defined).
+ auto Val = *V->getAsSignedConstant();
+ // Copied/hacked up from Clang's CharacterLiteral::print - incomplete
+ // (doesn't actually support different character types/widths, sign
+ // handling's not done, and doesn't correctly test if a character is
+ // printable or needs to use a numeric escape sequence instead)
+ if (IsQualifiedChar) {
+ OS << '(';
+ OS << Name;
+ OS << ')';
+ }
+ switch (Val) {
+ case '\\':
+ OS << "'\\\\'";
+ break;
+ case '\'':
+ OS << "'\\''";
+ break;
+ case '\a':
+ // TODO: K&R: the meaning of '\\a' is different in traditional C
+ OS << "'\\a'";
+ break;
+ case '\b':
+ OS << "'\\b'";
+ break;
+ case '\f':
+ OS << "'\\f'";
+ break;
+ case '\n':
+ OS << "'\\n'";
+ break;
+ case '\r':
+ OS << "'\\r'";
+ break;
+ case '\t':
+ OS << "'\\t'";
+ break;
+ case '\v':
+ OS << "'\\v'";
+ break;
+ default:
+ if ((Val & ~0xFFu) == ~0xFFu)
+ Val &= 0xFFu;
+ if (Val < 127 && Val >= 32) {
+ OS << "'";
+ OS << (char)Val;
+ OS << "'";
+ } else if (Val < 256)
+ OS << to_string(llvm::format("'\\x%02x'", Val));
+ else if (Val <= 0xFFFF)
+ OS << to_string(llvm::format("'\\u%04x'", Val));
+ else
+ OS << to_string(llvm::format("'\\U%08x'", Val));
+ }
+ }
+ continue;
+ }
+ if (C.getTag() == dwarf::DW_TAG_GNU_template_template_param) {
+ const char *RawName =
+ dwarf::toString(C.find(DW_AT_GNU_template_name), nullptr);
+ assert(RawName);
+ StringRef Name = RawName;
+ Sep();
+ OS << Name;
+ continue;
+ }
+ if (C.getTag() != dwarf::DW_TAG_template_type_parameter)
+ continue;
+ auto TypeAttr = C.find(DW_AT_type);
+ Sep();
+ appendQualifiedName(TypeAttr ? resolveReferencedType(C, *TypeAttr)
+ : DWARFDie());
+ }
+ if (IsTemplate && *FirstParameter && FirstParameter == &FirstParameterValue)
+ OS << '<';
+ return IsTemplate;
+ }
+ void decomposeConstVolatile(DWARFDie &N, DWARFDie &T, DWARFDie &C,
+ DWARFDie &V) {
+ (N.getTag() == DW_TAG_const_type ? C : V) = N;
+ T = resolveReferencedType(N);
+ if (T) {
+ auto Tag = T.getTag();
+ if (Tag == DW_TAG_const_type) {
+ C = T;
+ T = resolveReferencedType(T);
+ } else if (Tag == DW_TAG_volatile_type) {
+ V = T;
+ T = resolveReferencedType(T);
+ }
+ }
+ }
+ void appendConstVolatileQualifierAfter(DWARFDie N) {
+ DWARFDie C;
+ DWARFDie V;
+ DWARFDie T;
+ decomposeConstVolatile(N, T, C, V);
+ if (T && T.getTag() == DW_TAG_subroutine_type)
+ appendSubroutineNameAfter(T, resolveReferencedType(T), false, C.isValid(),
+ V.isValid());
+ else
+ appendUnqualifiedNameAfter(T, resolveReferencedType(T));
+ }
+ void appendConstVolatileQualifierBefore(DWARFDie N) {
+ DWARFDie C;
+ DWARFDie V;
+ DWARFDie T;
+ decomposeConstVolatile(N, T, C, V);
+ bool Subroutine = T && T.getTag() == DW_TAG_subroutine_type;
+ DWARFDie A = T;
+ while (A && A.getTag() == DW_TAG_array_type)
+ A = resolveReferencedType(A);
+ bool Leading =
+ (!A || (A.getTag() != DW_TAG_pointer_type &&
+ A.getTag() != llvm::dwarf::DW_TAG_ptr_to_member_type)) &&
+ !Subroutine;
+ if (Leading) {
+ if (C)
+ OS << "const ";
+ if (V)
+ OS << "volatile ";
+ }
+ appendQualifiedNameBefore(T);
+ if (!Leading && !Subroutine) {
+ Word = true;
+ if (C)
+ OS << "const";
+ if (V) {
+ if (C)
+ OS << ' ';
+ OS << "volatile";
+ }
+ }
+ }
+
+ /// Recursively append the DIE type name when applicable.
+ void appendUnqualifiedName(DWARFDie D,
+ std::string *OriginalFullName = nullptr) {
+ // FIXME: We should have pretty printers per language. Currently we print
+ // everything as if it was C++ and fall back to the TAG type name.
+ DWARFDie Inner = appendUnqualifiedNameBefore(D, OriginalFullName);
+ appendUnqualifiedNameAfter(D, Inner);
+ }
+
+ void appendSubroutineNameAfter(DWARFDie D, DWARFDie Inner,
+ bool SkipFirstParamIfArtificial, bool Const,
+ bool Volatile) {
+ DWARFDie FirstParamIfArtificial;
+ OS << '(';
+ EndedWithTemplate = false;
+ bool First = true;
+ bool RealFirst = true;
+ for (DWARFDie P : D) {
+ if (P.getTag() != DW_TAG_formal_parameter &&
+ P.getTag() != DW_TAG_unspecified_parameters)
+ return;
+ DWARFDie T = resolveReferencedType(P);
+ if (SkipFirstParamIfArtificial && RealFirst && P.find(DW_AT_artificial)) {
+ FirstParamIfArtificial = T;
+ RealFirst = false;
+ continue;
+ }
+ if (!First) {
+ OS << ", ";
+ }
+ First = false;
+ if (P.getTag() == DW_TAG_unspecified_parameters)
+ OS << "...";
+ else
+ appendQualifiedName(T);
+ }
+ EndedWithTemplate = false;
+ OS << ')';
+ if (FirstParamIfArtificial) {
+ if (DWARFDie P = FirstParamIfArtificial) {
+ if (P.getTag() == DW_TAG_pointer_type) {
+ DWARFDie C;
+ DWARFDie V;
+ auto CVStep = [&](DWARFDie CV) {
+ if (DWARFDie U = resolveReferencedType(CV)) {
+ if (U.getTag() == DW_TAG_const_type)
+ return C = U;
+ if (U.getTag() == DW_TAG_volatile_type)
+ return V = U;
+ }
+ return DWARFDie();
+ };
+ if (DWARFDie CV = CVStep(P)) {
+ CVStep(CV);
+ }
+ if (C)
+ OS << " const";
+ if (V)
+ OS << " volatile";
+ }
+ }
+ } else {
+ if (Const)
+ OS << " const";
+ if (Volatile)
+ OS << " volatile";
+ }
+ if (D.find(DW_AT_reference))
+ OS << " &";
+ if (D.find(DW_AT_rvalue_reference))
+ OS << " &&";
+ appendUnqualifiedNameAfter(Inner, resolveReferencedType(Inner));
+ }
+ void appendScopes(DWARFDie D) {
+ if (D.getTag() == DW_TAG_compile_unit)
+ return;
+ if (D.getTag() == DW_TAG_type_unit)
+ return;
+ if (D.getTag() == DW_TAG_skeleton_unit)
+ return;
+ if (D.getTag() == DW_TAG_subprogram)
+ return;
+ if (D.getTag() == DW_TAG_lexical_block)
+ return;
+ D = D.resolveTypeUnitReference();
+ if (DWARFDie P = D.getParent())
+ appendScopes(P);
+ appendUnqualifiedName(D);
+ OS << "::";
+ }
+};
+} // anonymous namespace
+
+static void dumpAttribute(raw_ostream &OS, const DWARFDie &Die,
+ const DWARFAttribute &AttrValue, unsigned Indent,
+ DIDumpOptions DumpOpts) {
+ if (!Die.isValid())
+ return;
+ const char BaseIndent[] = " ";
+ OS << BaseIndent;
+ OS.indent(Indent + 2);
+ dwarf::Attribute Attr = AttrValue.Attr;
+ WithColor(OS, HighlightColor::Attribute) << formatv("{0}", Attr);
+
+ dwarf::Form Form = AttrValue.Value.getForm();
+ if (DumpOpts.Verbose || DumpOpts.ShowForm)
+ OS << formatv(" [{0}]", Form);
+
+ DWARFUnit *U = Die.getDwarfUnit();
+ const DWARFFormValue &FormValue = AttrValue.Value;
+
+ OS << "\t(";
+
+ StringRef Name;
+ std::string File;
+ auto Color = HighlightColor::Enumerator;
+ if (Attr == DW_AT_decl_file || Attr == DW_AT_call_file) {
+ Color = HighlightColor::String;
+ if (const auto *LT = U->getContext().getLineTableForUnit(U))
+ if (LT->getFileNameByIndex(
+ FormValue.getAsUnsignedConstant().getValue(),
+ U->getCompilationDir(),
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File)) {
+ File = '"' + File + '"';
+ Name = File;
+ }
+ } else if (Optional<uint64_t> Val = FormValue.getAsUnsignedConstant())
+ Name = AttributeValueString(Attr, *Val);
+
+ if (!Name.empty())
+ WithColor(OS, Color) << Name;
+ else if (Attr == DW_AT_decl_line || Attr == DW_AT_call_line)
+ OS << *FormValue.getAsUnsignedConstant();
+ else if (Attr == DW_AT_low_pc &&
+ (FormValue.getAsAddress() ==
+ dwarf::computeTombstoneAddress(U->getAddressByteSize()))) {
+ if (DumpOpts.Verbose) {
+ FormValue.dump(OS, DumpOpts);
+ OS << " (";
+ }
+ OS << "dead code";
+ if (DumpOpts.Verbose)
+ OS << ')';
+ } else if (Attr == DW_AT_high_pc && !DumpOpts.ShowForm && !DumpOpts.Verbose &&
+ FormValue.getAsUnsignedConstant()) {
+ if (DumpOpts.ShowAddresses) {
+ // Print the actual address rather than the offset.
+ uint64_t LowPC, HighPC, Index;
+ if (Die.getLowAndHighPC(LowPC, HighPC, Index))
+ DWARFFormValue::dumpAddress(OS, U->getAddressByteSize(), HighPC);
+ else
+ FormValue.dump(OS, DumpOpts);
+ }
+ } else if (DWARFAttribute::mayHaveLocationList(Attr) &&
+ FormValue.isFormClass(DWARFFormValue::FC_SectionOffset))
+ dumpLocationList(OS, FormValue, U, sizeof(BaseIndent) + Indent + 4,
+ DumpOpts);
+ else if (FormValue.isFormClass(DWARFFormValue::FC_Exprloc) ||
+ (DWARFAttribute::mayHaveLocationExpr(Attr) &&
+ FormValue.isFormClass(DWARFFormValue::FC_Block)))
+ dumpLocationExpr(OS, FormValue, U, sizeof(BaseIndent) + Indent + 4,
+ DumpOpts);
+ else
+ FormValue.dump(OS, DumpOpts);
+
+ std::string Space = DumpOpts.ShowAddresses ? " " : "";
+
+ // We have dumped the attribute raw value. For some attributes
+ // having both the raw value and the pretty-printed value is
+ // interesting. These attributes are handled below.
+ if (Attr == DW_AT_specification || Attr == DW_AT_abstract_origin) {
+ if (const char *Name =
+ Die.getAttributeValueAsReferencedDie(FormValue).getName(
+ DINameKind::LinkageName))
+ OS << Space << "\"" << Name << '\"';
+ } else if (Attr == DW_AT_type) {
+ DWARFDie D = resolveReferencedType(Die, FormValue);
+ if (D && !D.isNULL()) {
+ OS << Space << "\"";
+ dumpTypeQualifiedName(D, OS);
+ OS << '"';
+ }
+ } else if (Attr == DW_AT_APPLE_property_attribute) {
+ if (Optional<uint64_t> OptVal = FormValue.getAsUnsignedConstant())
+ dumpApplePropertyAttribute(OS, *OptVal);
+ } else if (Attr == DW_AT_ranges) {
+ const DWARFObject &Obj = Die.getDwarfUnit()->getContext().getDWARFObj();
+ // For DW_FORM_rnglistx we need to dump the offset separately, since
+ // we have only dumped the index so far.
+ if (FormValue.getForm() == DW_FORM_rnglistx)
+ if (auto RangeListOffset =
+ U->getRnglistOffset(*FormValue.getAsSectionOffset())) {
+ DWARFFormValue FV = DWARFFormValue::createFromUValue(
+ dwarf::DW_FORM_sec_offset, *RangeListOffset);
+ FV.dump(OS, DumpOpts);
+ }
+ if (auto RangesOrError = Die.getAddressRanges())
+ dumpRanges(Obj, OS, RangesOrError.get(), U->getAddressByteSize(),
+ sizeof(BaseIndent) + Indent + 4, DumpOpts);
+ else
+ DumpOpts.RecoverableErrorHandler(createStringError(
+ errc::invalid_argument, "decoding address ranges: %s",
+ toString(RangesOrError.takeError()).c_str()));
+ }
+
+ OS << ")\n";
+}
+
+void DWARFDie::getFullName(raw_string_ostream &OS,
+ std::string *OriginalFullName) const {
+ const char *NamePtr = getShortName();
+ if (!NamePtr)
+ return;
+ if (getTag() == DW_TAG_GNU_template_parameter_pack)
+ return;
+ dumpTypeUnqualifiedName(*this, OS, OriginalFullName);
+}
+
+bool DWARFDie::isSubprogramDIE() const { return getTag() == DW_TAG_subprogram; }
+
+bool DWARFDie::isSubroutineDIE() const {
+ auto Tag = getTag();
+ return Tag == DW_TAG_subprogram || Tag == DW_TAG_inlined_subroutine;
+}
+
+Optional<DWARFFormValue> DWARFDie::find(dwarf::Attribute Attr) const {
+ if (!isValid())
+ return None;
+ auto AbbrevDecl = getAbbreviationDeclarationPtr();
+ if (AbbrevDecl)
+ return AbbrevDecl->getAttributeValue(getOffset(), Attr, *U);
+ return None;
+}
+
+Optional<DWARFFormValue>
+DWARFDie::find(ArrayRef<dwarf::Attribute> Attrs) const {
+ if (!isValid())
+ return None;
+ auto AbbrevDecl = getAbbreviationDeclarationPtr();
+ if (AbbrevDecl) {
+ for (auto Attr : Attrs) {
+ if (auto Value = AbbrevDecl->getAttributeValue(getOffset(), Attr, *U))
+ return Value;
+ }
+ }
+ return None;
+}
+
+Optional<DWARFFormValue>
+DWARFDie::findRecursively(ArrayRef<dwarf::Attribute> Attrs) const {
+ SmallVector<DWARFDie, 3> Worklist;
+ Worklist.push_back(*this);
+
+ // Keep track if DIEs already seen to prevent infinite recursion.
+ // Empirically we rarely see a depth of more than 3 when dealing with valid
+ // DWARF. This corresponds to following the DW_AT_abstract_origin and
+ // DW_AT_specification just once.
+ SmallSet<DWARFDie, 3> Seen;
+ Seen.insert(*this);
+
+ while (!Worklist.empty()) {
+ DWARFDie Die = Worklist.pop_back_val();
+
+ if (!Die.isValid())
+ continue;
+
+ if (auto Value = Die.find(Attrs))
+ return Value;
+
+ if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_abstract_origin))
+ if (Seen.insert(D).second)
+ Worklist.push_back(D);
+
+ if (auto D = Die.getAttributeValueAsReferencedDie(DW_AT_specification))
+ if (Seen.insert(D).second)
+ Worklist.push_back(D);
+ }
+
+ return None;
+}
+
+DWARFDie
+DWARFDie::getAttributeValueAsReferencedDie(dwarf::Attribute Attr) const {
+ if (Optional<DWARFFormValue> F = find(Attr))
+ return getAttributeValueAsReferencedDie(*F);
+ return DWARFDie();
+}
+
+DWARFDie
+DWARFDie::getAttributeValueAsReferencedDie(const DWARFFormValue &V) const {
+ DWARFDie Result;
+ if (auto SpecRef = V.getAsRelativeReference()) {
+ if (SpecRef->Unit)
+ Result = SpecRef->Unit->getDIEForOffset(SpecRef->Unit->getOffset() +
+ SpecRef->Offset);
+ else if (auto SpecUnit =
+ U->getUnitVector().getUnitForOffset(SpecRef->Offset))
+ Result = SpecUnit->getDIEForOffset(SpecRef->Offset);
+ }
+ return Result;
+}
+
+DWARFDie DWARFDie::resolveTypeUnitReference() const {
+ if (auto Attr = find(DW_AT_signature)) {
+ if (Optional<uint64_t> Sig = Attr->getAsReferenceUVal()) {
+ if (DWARFTypeUnit *TU = U->getContext().getTypeUnitForHash(
+ U->getVersion(), *Sig, U->isDWOUnit()))
+ return TU->getDIEForOffset(TU->getTypeOffset() + TU->getOffset());
+ }
+ }
+ return *this;
+}
+
+Optional<uint64_t> DWARFDie::getRangesBaseAttribute() const {
+ return toSectionOffset(find({DW_AT_rnglists_base, DW_AT_GNU_ranges_base}));
+}
+
+Optional<uint64_t> DWARFDie::getLocBaseAttribute() const {
+ return toSectionOffset(find(DW_AT_loclists_base));
+}
+
+Optional<uint64_t> DWARFDie::getHighPC(uint64_t LowPC) const {
+ uint64_t Tombstone = dwarf::computeTombstoneAddress(U->getAddressByteSize());
+ if (LowPC == Tombstone)
+ return None;
+ if (auto FormValue = find(DW_AT_high_pc)) {
+ if (auto Address = FormValue->getAsAddress()) {
+ // High PC is an address.
+ return Address;
+ }
+ if (auto Offset = FormValue->getAsUnsignedConstant()) {
+ // High PC is an offset from LowPC.
+ return LowPC + *Offset;
+ }
+ }
+ return None;
+}
+
+bool DWARFDie::getLowAndHighPC(uint64_t &LowPC, uint64_t &HighPC,
+ uint64_t &SectionIndex) const {
+ auto F = find(DW_AT_low_pc);
+ auto LowPcAddr = toSectionedAddress(F);
+ if (!LowPcAddr)
+ return false;
+ if (auto HighPcAddr = getHighPC(LowPcAddr->Address)) {
+ LowPC = LowPcAddr->Address;
+ HighPC = *HighPcAddr;
+ SectionIndex = LowPcAddr->SectionIndex;
+ return true;
+ }
+ return false;
+}
+
+Expected<DWARFAddressRangesVector> DWARFDie::getAddressRanges() const {
+ if (isNULL())
+ return DWARFAddressRangesVector();
+ // Single range specified by low/high PC.
+ uint64_t LowPC, HighPC, Index;
+ if (getLowAndHighPC(LowPC, HighPC, Index))
+ return DWARFAddressRangesVector{{LowPC, HighPC, Index}};
+
+ Optional<DWARFFormValue> Value = find(DW_AT_ranges);
+ if (Value) {
+ if (Value->getForm() == DW_FORM_rnglistx)
+ return U->findRnglistFromIndex(*Value->getAsSectionOffset());
+ return U->findRnglistFromOffset(*Value->getAsSectionOffset());
+ }
+ return DWARFAddressRangesVector();
+}
+
+bool DWARFDie::addressRangeContainsAddress(const uint64_t Address) const {
+ auto RangesOrError = getAddressRanges();
+ if (!RangesOrError) {
+ llvm::consumeError(RangesOrError.takeError());
+ return false;
+ }
+
+ for (const auto &R : RangesOrError.get())
+ if (R.LowPC <= Address && Address < R.HighPC)
+ return true;
+ return false;
+}
+
+Expected<DWARFLocationExpressionsVector>
+DWARFDie::getLocations(dwarf::Attribute Attr) const {
+ Optional<DWARFFormValue> Location = find(Attr);
+ if (!Location)
+ return createStringError(inconvertibleErrorCode(), "No %s",
+ dwarf::AttributeString(Attr).data());
+
+ if (Optional<uint64_t> Off = Location->getAsSectionOffset()) {
+ uint64_t Offset = *Off;
+
+ if (Location->getForm() == DW_FORM_loclistx) {
+ if (auto LoclistOffset = U->getLoclistOffset(Offset))
+ Offset = *LoclistOffset;
+ else
+ return createStringError(inconvertibleErrorCode(),
+ "Loclist table not found");
+ }
+ return U->findLoclistFromOffset(Offset);
+ }
+
+ if (Optional<ArrayRef<uint8_t>> Expr = Location->getAsBlock()) {
+ return DWARFLocationExpressionsVector{
+ DWARFLocationExpression{None, to_vector<4>(*Expr)}};
+ }
+
+ return createStringError(
+ inconvertibleErrorCode(), "Unsupported %s encoding: %s",
+ dwarf::AttributeString(Attr).data(),
+ dwarf::FormEncodingString(Location->getForm()).data());
+}
+
+const char *DWARFDie::getSubroutineName(DINameKind Kind) const {
+ if (!isSubroutineDIE())
+ return nullptr;
+ return getName(Kind);
+}
+
+const char *DWARFDie::getName(DINameKind Kind) const {
+ if (!isValid() || Kind == DINameKind::None)
+ return nullptr;
+ // Try to get mangled name only if it was asked for.
+ if (Kind == DINameKind::LinkageName) {
+ if (auto Name = getLinkageName())
+ return Name;
+ }
+ return getShortName();
+}
+
+const char *DWARFDie::getShortName() const {
+ if (!isValid())
+ return nullptr;
+
+ return dwarf::toString(findRecursively(dwarf::DW_AT_name), nullptr);
+}
+
+const char *DWARFDie::getLinkageName() const {
+ if (!isValid())
+ return nullptr;
+
+ return dwarf::toString(findRecursively({dwarf::DW_AT_MIPS_linkage_name,
+ dwarf::DW_AT_linkage_name}),
+ nullptr);
+}
+
+uint64_t DWARFDie::getDeclLine() const {
+ return toUnsigned(findRecursively(DW_AT_decl_line), 0);
+}
+
+std::string
+DWARFDie::getDeclFile(DILineInfoSpecifier::FileLineInfoKind Kind) const {
+ if (auto FormValue = findRecursively(DW_AT_decl_file))
+ if (auto OptString = FormValue->getAsFile(Kind))
+ return *OptString;
+ return {};
+}
+
+void DWARFDie::getCallerFrame(uint32_t &CallFile, uint32_t &CallLine,
+ uint32_t &CallColumn,
+ uint32_t &CallDiscriminator) const {
+ CallFile = toUnsigned(find(DW_AT_call_file), 0);
+ CallLine = toUnsigned(find(DW_AT_call_line), 0);
+ CallColumn = toUnsigned(find(DW_AT_call_column), 0);
+ CallDiscriminator = toUnsigned(find(DW_AT_GNU_discriminator), 0);
+}
+
+/// Helper to dump a DIE with all of its parents, but no siblings.
+static unsigned dumpParentChain(DWARFDie Die, raw_ostream &OS, unsigned Indent,
+ DIDumpOptions DumpOpts, unsigned Depth = 0) {
+ if (!Die)
+ return Indent;
+ if (DumpOpts.ParentRecurseDepth > 0 && Depth >= DumpOpts.ParentRecurseDepth)
+ return Indent;
+ Indent = dumpParentChain(Die.getParent(), OS, Indent, DumpOpts, Depth + 1);
+ Die.dump(OS, Indent, DumpOpts);
+ return Indent + 2;
+}
+
+void DWARFDie::dump(raw_ostream &OS, unsigned Indent,
+ DIDumpOptions DumpOpts) const {
+ if (!isValid())
+ return;
+ DWARFDataExtractor debug_info_data = U->getDebugInfoExtractor();
+ const uint64_t Offset = getOffset();
+ uint64_t offset = Offset;
+ if (DumpOpts.ShowParents) {
+ DIDumpOptions ParentDumpOpts = DumpOpts;
+ ParentDumpOpts.ShowParents = false;
+ ParentDumpOpts.ShowChildren = false;
+ Indent = dumpParentChain(getParent(), OS, Indent, ParentDumpOpts);
+ }
+
+ if (debug_info_data.isValidOffset(offset)) {
+ uint32_t abbrCode = debug_info_data.getULEB128(&offset);
+ if (DumpOpts.ShowAddresses)
+ WithColor(OS, HighlightColor::Address).get()
+ << format("\n0x%8.8" PRIx64 ": ", Offset);
+
+ if (abbrCode) {
+ auto AbbrevDecl = getAbbreviationDeclarationPtr();
+ if (AbbrevDecl) {
+ WithColor(OS, HighlightColor::Tag).get().indent(Indent)
+ << formatv("{0}", getTag());
+ if (DumpOpts.Verbose) {
+ OS << format(" [%u] %c", abbrCode,
+ AbbrevDecl->hasChildren() ? '*' : ' ');
+ if (Optional<uint32_t> ParentIdx = Die->getParentIdx())
+ OS << format(" (0x%8.8" PRIx64 ")",
+ U->getDIEAtIndex(*ParentIdx).getOffset());
+ }
+ OS << '\n';
+
+ // Dump all data in the DIE for the attributes.
+ for (const DWARFAttribute &AttrValue : attributes())
+ dumpAttribute(OS, *this, AttrValue, Indent, DumpOpts);
+
+ if (DumpOpts.ShowChildren && DumpOpts.ChildRecurseDepth > 0) {
+ DWARFDie Child = getFirstChild();
+ DumpOpts.ChildRecurseDepth--;
+ DIDumpOptions ChildDumpOpts = DumpOpts;
+ ChildDumpOpts.ShowParents = false;
+ while (Child) {
+ Child.dump(OS, Indent + 2, ChildDumpOpts);
+ Child = Child.getSibling();
+ }
+ }
+ } else {
+ OS << "Abbreviation code not found in 'debug_abbrev' class for code: "
+ << abbrCode << '\n';
+ }
+ } else {
+ OS.indent(Indent) << "NULL\n";
+ }
+ }
+}
+
+LLVM_DUMP_METHOD void DWARFDie::dump() const { dump(llvm::errs(), 0); }
+
+DWARFDie DWARFDie::getParent() const {
+ if (isValid())
+ return U->getParent(Die);
+ return DWARFDie();
+}
+
+DWARFDie DWARFDie::getSibling() const {
+ if (isValid())
+ return U->getSibling(Die);
+ return DWARFDie();
+}
+
+DWARFDie DWARFDie::getPreviousSibling() const {
+ if (isValid())
+ return U->getPreviousSibling(Die);
+ return DWARFDie();
+}
+
+DWARFDie DWARFDie::getFirstChild() const {
+ if (isValid())
+ return U->getFirstChild(Die);
+ return DWARFDie();
+}
+
+DWARFDie DWARFDie::getLastChild() const {
+ if (isValid())
+ return U->getLastChild(Die);
+ return DWARFDie();
+}
+
+iterator_range<DWARFDie::attribute_iterator> DWARFDie::attributes() const {
+ return make_range(attribute_iterator(*this, false),
+ attribute_iterator(*this, true));
+}
+
+DWARFDie::attribute_iterator::attribute_iterator(DWARFDie D, bool End)
+ : Die(D), Index(0) {
+ auto AbbrDecl = Die.getAbbreviationDeclarationPtr();
+ assert(AbbrDecl && "Must have abbreviation declaration");
+ if (End) {
+ // This is the end iterator so we set the index to the attribute count.
+ Index = AbbrDecl->getNumAttributes();
+ } else {
+ // This is the begin iterator so we extract the value for this->Index.
+ AttrValue.Offset = D.getOffset() + AbbrDecl->getCodeByteSize();
+ updateForIndex(*AbbrDecl, 0);
+ }
+}
+
+void DWARFDie::attribute_iterator::updateForIndex(
+ const DWARFAbbreviationDeclaration &AbbrDecl, uint32_t I) {
+ Index = I;
+ // AbbrDecl must be valid before calling this function.
+ auto NumAttrs = AbbrDecl.getNumAttributes();
+ if (Index < NumAttrs) {
+ AttrValue.Attr = AbbrDecl.getAttrByIndex(Index);
+ // Add the previous byte size of any previous attribute value.
+ AttrValue.Offset += AttrValue.ByteSize;
+ uint64_t ParseOffset = AttrValue.Offset;
+ if (AbbrDecl.getAttrIsImplicitConstByIndex(Index))
+ AttrValue.Value = DWARFFormValue::createFromSValue(
+ AbbrDecl.getFormByIndex(Index),
+ AbbrDecl.getAttrImplicitConstValueByIndex(Index));
+ else {
+ auto U = Die.getDwarfUnit();
+ assert(U && "Die must have valid DWARF unit");
+ AttrValue.Value = DWARFFormValue::createFromUnit(
+ AbbrDecl.getFormByIndex(Index), U, &ParseOffset);
+ }
+ AttrValue.ByteSize = ParseOffset - AttrValue.Offset;
+ } else {
+ assert(Index == NumAttrs && "Indexes should be [0, NumAttrs) only");
+ AttrValue = {};
+ }
+}
+
+DWARFDie::attribute_iterator &DWARFDie::attribute_iterator::operator++() {
+ if (auto AbbrDecl = Die.getAbbreviationDeclarationPtr())
+ updateForIndex(*AbbrDecl, Index + 1);
+ return *this;
+}
+
+bool DWARFAttribute::mayHaveLocationList(dwarf::Attribute Attr) {
+ switch(Attr) {
+ case DW_AT_location:
+ case DW_AT_string_length:
+ case DW_AT_return_addr:
+ case DW_AT_data_member_location:
+ case DW_AT_frame_base:
+ case DW_AT_static_link:
+ case DW_AT_segment:
+ case DW_AT_use_location:
+ case DW_AT_vtable_elem_location:
+ return true;
+ default:
+ return false;
+ }
+}
+
+bool DWARFAttribute::mayHaveLocationExpr(dwarf::Attribute Attr) {
+ switch (Attr) {
+ // From the DWARF v5 specification.
+ case DW_AT_location:
+ case DW_AT_byte_size:
+ case DW_AT_bit_offset:
+ case DW_AT_bit_size:
+ case DW_AT_string_length:
+ case DW_AT_lower_bound:
+ case DW_AT_return_addr:
+ case DW_AT_bit_stride:
+ case DW_AT_upper_bound:
+ case DW_AT_count:
+ case DW_AT_data_member_location:
+ case DW_AT_frame_base:
+ case DW_AT_segment:
+ case DW_AT_static_link:
+ case DW_AT_use_location:
+ case DW_AT_vtable_elem_location:
+ case DW_AT_allocated:
+ case DW_AT_associated:
+ case DW_AT_data_location:
+ case DW_AT_byte_stride:
+ case DW_AT_rank:
+ case DW_AT_call_value:
+ case DW_AT_call_origin:
+ case DW_AT_call_target:
+ case DW_AT_call_target_clobbered:
+ case DW_AT_call_data_location:
+ case DW_AT_call_data_value:
+ // Extensions.
+ case DW_AT_GNU_call_site_value:
+ case DW_AT_GNU_call_site_target:
+ return true;
+ default:
+ return false;
+ }
+}
+
+namespace llvm {
+
+void dumpTypeQualifiedName(const DWARFDie &DIE, raw_ostream &OS) {
+ DWARFTypePrinter(OS).appendQualifiedName(DIE);
+}
+
+void dumpTypeUnqualifiedName(const DWARFDie &DIE, raw_ostream &OS,
+ std::string *OriginalFullName) {
+ DWARFTypePrinter(OS).appendUnqualifiedName(DIE, OriginalFullName);
+}
+
+} // namespace llvm
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFExpression.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFExpression.cpp
new file mode 100644
index 0000000000..e19f5b8138
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFExpression.cpp
@@ -0,0 +1,519 @@
+//===-- DWARFExpression.cpp -----------------------------------------------===//
+//
+// 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/DWARF/DWARFExpression.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/MC/MCRegisterInfo.h"
+#include "llvm/Support/Format.h"
+#include <cassert>
+#include <cstdint>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+
+namespace llvm {
+
+typedef std::vector<DWARFExpression::Operation::Description> DescVector;
+
+static DescVector getDescriptions() {
+ DescVector Descriptions;
+ typedef DWARFExpression::Operation Op;
+ typedef Op::Description Desc;
+
+ Descriptions.resize(0xff);
+ Descriptions[DW_OP_addr] = Desc(Op::Dwarf2, Op::SizeAddr);
+ Descriptions[DW_OP_deref] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_const1u] = Desc(Op::Dwarf2, Op::Size1);
+ Descriptions[DW_OP_const1s] = Desc(Op::Dwarf2, Op::SignedSize1);
+ Descriptions[DW_OP_const2u] = Desc(Op::Dwarf2, Op::Size2);
+ Descriptions[DW_OP_const2s] = Desc(Op::Dwarf2, Op::SignedSize2);
+ Descriptions[DW_OP_const4u] = Desc(Op::Dwarf2, Op::Size4);
+ Descriptions[DW_OP_const4s] = Desc(Op::Dwarf2, Op::SignedSize4);
+ Descriptions[DW_OP_const8u] = Desc(Op::Dwarf2, Op::Size8);
+ Descriptions[DW_OP_const8s] = Desc(Op::Dwarf2, Op::SignedSize8);
+ Descriptions[DW_OP_constu] = Desc(Op::Dwarf2, Op::SizeLEB);
+ Descriptions[DW_OP_consts] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
+ Descriptions[DW_OP_dup] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_drop] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_over] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_pick] = Desc(Op::Dwarf2, Op::Size1);
+ Descriptions[DW_OP_swap] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_rot] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_xderef] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_abs] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_and] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_div] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_minus] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_mod] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_mul] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_neg] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_not] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_or] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_plus] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_plus_uconst] = Desc(Op::Dwarf2, Op::SizeLEB);
+ Descriptions[DW_OP_shl] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_shr] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_shra] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_xor] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_skip] = Desc(Op::Dwarf2, Op::SignedSize2);
+ Descriptions[DW_OP_bra] = Desc(Op::Dwarf2, Op::SignedSize2);
+ Descriptions[DW_OP_eq] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_ge] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_gt] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_le] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_lt] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_ne] = Desc(Op::Dwarf2);
+ for (uint16_t LA = DW_OP_lit0; LA <= DW_OP_lit31; ++LA)
+ Descriptions[LA] = Desc(Op::Dwarf2);
+ for (uint16_t LA = DW_OP_reg0; LA <= DW_OP_reg31; ++LA)
+ Descriptions[LA] = Desc(Op::Dwarf2);
+ for (uint16_t LA = DW_OP_breg0; LA <= DW_OP_breg31; ++LA)
+ Descriptions[LA] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
+ Descriptions[DW_OP_regx] = Desc(Op::Dwarf2, Op::SizeLEB);
+ Descriptions[DW_OP_fbreg] = Desc(Op::Dwarf2, Op::SignedSizeLEB);
+ Descriptions[DW_OP_bregx] = Desc(Op::Dwarf2, Op::SizeLEB, Op::SignedSizeLEB);
+ Descriptions[DW_OP_piece] = Desc(Op::Dwarf2, Op::SizeLEB);
+ Descriptions[DW_OP_deref_size] = Desc(Op::Dwarf2, Op::Size1);
+ Descriptions[DW_OP_xderef_size] = Desc(Op::Dwarf2, Op::Size1);
+ Descriptions[DW_OP_nop] = Desc(Op::Dwarf2);
+ Descriptions[DW_OP_push_object_address] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_call2] = Desc(Op::Dwarf3, Op::Size2);
+ Descriptions[DW_OP_call4] = Desc(Op::Dwarf3, Op::Size4);
+ Descriptions[DW_OP_call_ref] = Desc(Op::Dwarf3, Op::SizeRefAddr);
+ Descriptions[DW_OP_form_tls_address] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_call_frame_cfa] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_bit_piece] = Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeLEB);
+ Descriptions[DW_OP_implicit_value] =
+ Desc(Op::Dwarf3, Op::SizeLEB, Op::SizeBlock);
+ Descriptions[DW_OP_stack_value] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_WASM_location] =
+ Desc(Op::Dwarf4, Op::SizeLEB, Op::WasmLocationArg);
+ Descriptions[DW_OP_GNU_push_tls_address] = Desc(Op::Dwarf3);
+ Descriptions[DW_OP_addrx] = Desc(Op::Dwarf4, Op::SizeLEB);
+ Descriptions[DW_OP_GNU_addr_index] = Desc(Op::Dwarf4, Op::SizeLEB);
+ Descriptions[DW_OP_GNU_const_index] = Desc(Op::Dwarf4, Op::SizeLEB);
+ Descriptions[DW_OP_GNU_entry_value] = Desc(Op::Dwarf4, Op::SizeLEB);
+
+ Descriptions[DW_OP_convert] = Desc(Op::Dwarf5, Op::BaseTypeRef);
+ Descriptions[DW_OP_entry_value] = Desc(Op::Dwarf5, Op::SizeLEB);
+ Descriptions[DW_OP_regval_type] =
+ Desc(Op::Dwarf5, Op::SizeLEB, Op::BaseTypeRef);
+
+ return Descriptions;
+}
+
+static DWARFExpression::Operation::Description getOpDesc(unsigned OpCode) {
+ // FIXME: Make this constexpr once all compilers are smart enough to do it.
+ static DescVector Descriptions = getDescriptions();
+ // Handle possible corrupted or unsupported operation.
+ if (OpCode >= Descriptions.size())
+ return {};
+ return Descriptions[OpCode];
+}
+
+bool DWARFExpression::Operation::extract(DataExtractor Data,
+ uint8_t AddressSize, uint64_t Offset,
+ Optional<DwarfFormat> Format) {
+ EndOffset = Offset;
+ Opcode = Data.getU8(&Offset);
+
+ Desc = getOpDesc(Opcode);
+ if (Desc.Version == Operation::DwarfNA)
+ return false;
+
+ for (unsigned Operand = 0; Operand < 2; ++Operand) {
+ unsigned Size = Desc.Op[Operand];
+ unsigned Signed = Size & Operation::SignBit;
+
+ if (Size == Operation::SizeNA)
+ break;
+
+ switch (Size & ~Operation::SignBit) {
+ case Operation::Size1:
+ Operands[Operand] = Data.getU8(&Offset);
+ if (Signed)
+ Operands[Operand] = (int8_t)Operands[Operand];
+ break;
+ case Operation::Size2:
+ Operands[Operand] = Data.getU16(&Offset);
+ if (Signed)
+ Operands[Operand] = (int16_t)Operands[Operand];
+ break;
+ case Operation::Size4:
+ Operands[Operand] = Data.getU32(&Offset);
+ if (Signed)
+ Operands[Operand] = (int32_t)Operands[Operand];
+ break;
+ case Operation::Size8:
+ Operands[Operand] = Data.getU64(&Offset);
+ break;
+ case Operation::SizeAddr:
+ Operands[Operand] = Data.getUnsigned(&Offset, AddressSize);
+ break;
+ case Operation::SizeRefAddr:
+ if (!Format)
+ return false;
+ Operands[Operand] =
+ Data.getUnsigned(&Offset, dwarf::getDwarfOffsetByteSize(*Format));
+ break;
+ case Operation::SizeLEB:
+ if (Signed)
+ Operands[Operand] = Data.getSLEB128(&Offset);
+ else
+ Operands[Operand] = Data.getULEB128(&Offset);
+ break;
+ case Operation::BaseTypeRef:
+ Operands[Operand] = Data.getULEB128(&Offset);
+ break;
+ case Operation::WasmLocationArg:
+ assert(Operand == 1);
+ switch (Operands[0]) {
+ case 0:
+ case 1:
+ case 2:
+ case 4:
+ Operands[Operand] = Data.getULEB128(&Offset);
+ break;
+ case 3: // global as uint32
+ Operands[Operand] = Data.getU32(&Offset);
+ break;
+ default:
+ return false; // Unknown Wasm location
+ }
+ break;
+ case Operation::SizeBlock:
+ // We need a size, so this cannot be the first operand
+ if (Operand == 0)
+ return false;
+ // Store the offset of the block as the value.
+ Operands[Operand] = Offset;
+ Offset += Operands[Operand - 1];
+ break;
+ default:
+ llvm_unreachable("Unknown DWARFExpression Op size");
+ }
+
+ OperandEndOffsets[Operand] = Offset;
+ }
+
+ EndOffset = Offset;
+ return true;
+}
+
+static void prettyPrintBaseTypeRef(DWARFUnit *U, raw_ostream &OS,
+ DIDumpOptions DumpOpts,
+ const uint64_t Operands[2],
+ unsigned Operand) {
+ assert(Operand < 2 && "operand out of bounds");
+ auto Die = U->getDIEForOffset(U->getOffset() + Operands[Operand]);
+ if (Die && Die.getTag() == dwarf::DW_TAG_base_type) {
+ OS << " (";
+ if (DumpOpts.Verbose)
+ OS << format("0x%08" PRIx64 " -> ", Operands[Operand]);
+ OS << format("0x%08" PRIx64 ")", U->getOffset() + Operands[Operand]);
+ if (auto Name = dwarf::toString(Die.find(dwarf::DW_AT_name)))
+ OS << " \"" << *Name << "\"";
+ } else {
+ OS << format(" <invalid base_type ref: 0x%" PRIx64 ">",
+ Operands[Operand]);
+ }
+}
+
+static bool prettyPrintRegisterOp(DWARFUnit *U, raw_ostream &OS,
+ DIDumpOptions DumpOpts, uint8_t Opcode,
+ const uint64_t Operands[2],
+ const MCRegisterInfo *MRI, bool isEH) {
+ if (!MRI)
+ return false;
+
+ uint64_t DwarfRegNum;
+ unsigned OpNum = 0;
+
+ if (Opcode == DW_OP_bregx || Opcode == DW_OP_regx ||
+ Opcode == DW_OP_regval_type)
+ DwarfRegNum = Operands[OpNum++];
+ else if (Opcode >= DW_OP_breg0 && Opcode < DW_OP_bregx)
+ DwarfRegNum = Opcode - DW_OP_breg0;
+ else
+ DwarfRegNum = Opcode - DW_OP_reg0;
+
+ if (Optional<unsigned> LLVMRegNum = MRI->getLLVMRegNum(DwarfRegNum, isEH)) {
+ if (const char *RegName = MRI->getName(*LLVMRegNum)) {
+ if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
+ Opcode == DW_OP_bregx)
+ OS << format(" %s%+" PRId64, RegName, Operands[OpNum]);
+ else
+ OS << ' ' << RegName;
+
+ if (Opcode == DW_OP_regval_type)
+ prettyPrintBaseTypeRef(U, OS, DumpOpts, Operands, 1);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+bool DWARFExpression::Operation::print(raw_ostream &OS, DIDumpOptions DumpOpts,
+ const DWARFExpression *Expr,
+ const MCRegisterInfo *RegInfo,
+ DWARFUnit *U, bool isEH) const {
+ if (Error) {
+ OS << "<decoding error>";
+ return false;
+ }
+
+ StringRef Name = OperationEncodingString(Opcode);
+ assert(!Name.empty() && "DW_OP has no name!");
+ OS << Name;
+
+ if ((Opcode >= DW_OP_breg0 && Opcode <= DW_OP_breg31) ||
+ (Opcode >= DW_OP_reg0 && Opcode <= DW_OP_reg31) ||
+ Opcode == DW_OP_bregx || Opcode == DW_OP_regx ||
+ Opcode == DW_OP_regval_type)
+ if (prettyPrintRegisterOp(U, OS, DumpOpts, Opcode, Operands, RegInfo, isEH))
+ return true;
+
+ for (unsigned Operand = 0; Operand < 2; ++Operand) {
+ unsigned Size = Desc.Op[Operand];
+ unsigned Signed = Size & Operation::SignBit;
+
+ if (Size == Operation::SizeNA)
+ break;
+
+ if (Size == Operation::BaseTypeRef && U) {
+ // For DW_OP_convert the operand may be 0 to indicate that conversion to
+ // the generic type should be done. The same holds for DW_OP_reinterpret,
+ // which is currently not supported.
+ if (Opcode == DW_OP_convert && Operands[Operand] == 0)
+ OS << " 0x0";
+ else
+ prettyPrintBaseTypeRef(U, OS, DumpOpts, Operands, Operand);
+ } else if (Size == Operation::WasmLocationArg) {
+ assert(Operand == 1);
+ switch (Operands[0]) {
+ case 0:
+ case 1:
+ case 2:
+ case 3: // global as uint32
+ case 4:
+ OS << format(" 0x%" PRIx64, Operands[Operand]);
+ break;
+ default: assert(false);
+ }
+ } else if (Size == Operation::SizeBlock) {
+ uint64_t Offset = Operands[Operand];
+ for (unsigned i = 0; i < Operands[Operand - 1]; ++i)
+ OS << format(" 0x%02x", Expr->Data.getU8(&Offset));
+ } else {
+ if (Signed)
+ OS << format(" %+" PRId64, (int64_t)Operands[Operand]);
+ else if (Opcode != DW_OP_entry_value &&
+ Opcode != DW_OP_GNU_entry_value)
+ OS << format(" 0x%" PRIx64, Operands[Operand]);
+ }
+ }
+ return true;
+}
+
+void DWARFExpression::print(raw_ostream &OS, DIDumpOptions DumpOpts,
+ const MCRegisterInfo *RegInfo, DWARFUnit *U,
+ bool IsEH) const {
+ uint32_t EntryValExprSize = 0;
+ uint64_t EntryValStartOffset = 0;
+ if (Data.getData().empty())
+ OS << "<empty>";
+
+ for (auto &Op : *this) {
+ if (!Op.print(OS, DumpOpts, this, RegInfo, U, IsEH)) {
+ uint64_t FailOffset = Op.getEndOffset();
+ while (FailOffset < Data.getData().size())
+ OS << format(" %02x", Data.getU8(&FailOffset));
+ return;
+ }
+
+ if (Op.getCode() == DW_OP_entry_value ||
+ Op.getCode() == DW_OP_GNU_entry_value) {
+ OS << "(";
+ EntryValExprSize = Op.getRawOperand(0);
+ EntryValStartOffset = Op.getEndOffset();
+ continue;
+ }
+
+ if (EntryValExprSize) {
+ EntryValExprSize -= Op.getEndOffset() - EntryValStartOffset;
+ if (EntryValExprSize == 0)
+ OS << ")";
+ }
+
+ if (Op.getEndOffset() < Data.getData().size())
+ OS << ", ";
+ }
+}
+
+bool DWARFExpression::Operation::verify(const Operation &Op, DWARFUnit *U) {
+ for (unsigned Operand = 0; Operand < 2; ++Operand) {
+ unsigned Size = Op.Desc.Op[Operand];
+
+ if (Size == Operation::SizeNA)
+ break;
+
+ if (Size == Operation::BaseTypeRef) {
+ // For DW_OP_convert the operand may be 0 to indicate that conversion to
+ // the generic type should be done, so don't look up a base type in that
+ // case. The same holds for DW_OP_reinterpret, which is currently not
+ // supported.
+ if (Op.Opcode == DW_OP_convert && Op.Operands[Operand] == 0)
+ continue;
+ auto Die = U->getDIEForOffset(U->getOffset() + Op.Operands[Operand]);
+ if (!Die || Die.getTag() != dwarf::DW_TAG_base_type)
+ return false;
+ }
+ }
+
+ return true;
+}
+
+bool DWARFExpression::verify(DWARFUnit *U) {
+ for (auto &Op : *this)
+ if (!Operation::verify(Op, U))
+ return false;
+
+ return true;
+}
+
+/// A user-facing string representation of a DWARF expression. This might be an
+/// Address expression, in which case it will be implicitly dereferenced, or a
+/// Value expression.
+struct PrintedExpr {
+ enum ExprKind {
+ Address,
+ Value,
+ };
+ ExprKind Kind;
+ SmallString<16> String;
+
+ PrintedExpr(ExprKind K = Address) : Kind(K) {}
+};
+
+static bool printCompactDWARFExpr(raw_ostream &OS, DWARFExpression::iterator I,
+ const DWARFExpression::iterator E,
+ const MCRegisterInfo &MRI) {
+ SmallVector<PrintedExpr, 4> Stack;
+
+ while (I != E) {
+ const DWARFExpression::Operation &Op = *I;
+ uint8_t Opcode = Op.getCode();
+ switch (Opcode) {
+ case dwarf::DW_OP_regx: {
+ // DW_OP_regx: A register, with the register num given as an operand.
+ // Printed as the plain register name.
+ uint64_t DwarfRegNum = Op.getRawOperand(0);
+ Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false);
+ if (!LLVMRegNum) {
+ OS << "<unknown register " << DwarfRegNum << ">";
+ return false;
+ }
+ raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String);
+ S << MRI.getName(*LLVMRegNum);
+ break;
+ }
+ case dwarf::DW_OP_bregx: {
+ int DwarfRegNum = Op.getRawOperand(0);
+ int64_t Offset = Op.getRawOperand(1);
+ Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false);
+ if (!LLVMRegNum) {
+ OS << "<unknown register " << DwarfRegNum << ">";
+ return false;
+ }
+ raw_svector_ostream S(Stack.emplace_back().String);
+ S << MRI.getName(*LLVMRegNum);
+ if (Offset)
+ S << format("%+" PRId64, Offset);
+ break;
+ }
+ case dwarf::DW_OP_entry_value:
+ case dwarf::DW_OP_GNU_entry_value: {
+ // DW_OP_entry_value contains a sub-expression which must be rendered
+ // separately.
+ uint64_t SubExprLength = Op.getRawOperand(0);
+ DWARFExpression::iterator SubExprEnd = I.skipBytes(SubExprLength);
+ ++I;
+ raw_svector_ostream S(Stack.emplace_back().String);
+ S << "entry(";
+ printCompactDWARFExpr(S, I, SubExprEnd, MRI);
+ S << ")";
+ I = SubExprEnd;
+ continue;
+ }
+ case dwarf::DW_OP_stack_value: {
+ // The top stack entry should be treated as the actual value of tne
+ // variable, rather than the address of the variable in memory.
+ assert(!Stack.empty());
+ Stack.back().Kind = PrintedExpr::Value;
+ break;
+ }
+ default:
+ if (Opcode >= dwarf::DW_OP_reg0 && Opcode <= dwarf::DW_OP_reg31) {
+ // DW_OP_reg<N>: A register, with the register num implied by the
+ // opcode. Printed as the plain register name.
+ uint64_t DwarfRegNum = Opcode - dwarf::DW_OP_reg0;
+ Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false);
+ if (!LLVMRegNum) {
+ OS << "<unknown register " << DwarfRegNum << ">";
+ return false;
+ }
+ raw_svector_ostream S(Stack.emplace_back(PrintedExpr::Value).String);
+ S << MRI.getName(*LLVMRegNum);
+ } else if (Opcode >= dwarf::DW_OP_breg0 &&
+ Opcode <= dwarf::DW_OP_breg31) {
+ int DwarfRegNum = Opcode - dwarf::DW_OP_breg0;
+ int64_t Offset = Op.getRawOperand(0);
+ Optional<unsigned> LLVMRegNum = MRI.getLLVMRegNum(DwarfRegNum, false);
+ if (!LLVMRegNum) {
+ OS << "<unknown register " << DwarfRegNum << ">";
+ return false;
+ }
+ raw_svector_ostream S(Stack.emplace_back().String);
+ S << MRI.getName(*LLVMRegNum);
+ if (Offset)
+ S << format("%+" PRId64, Offset);
+ } else {
+ // If we hit an unknown operand, we don't know its effect on the stack,
+ // so bail out on the whole expression.
+ OS << "<unknown op " << dwarf::OperationEncodingString(Opcode) << " ("
+ << (int)Opcode << ")>";
+ return false;
+ }
+ break;
+ }
+ ++I;
+ }
+
+ assert(Stack.size() == 1 && "expected one value on stack");
+
+ if (Stack.front().Kind == PrintedExpr::Address)
+ OS << "[" << Stack.front().String << "]";
+ else
+ OS << Stack.front().String;
+
+ return true;
+}
+
+bool DWARFExpression::printCompact(raw_ostream &OS, const MCRegisterInfo &MRI) {
+ return printCompactDWARFExpr(OS, begin(), end(), MRI);
+}
+
+bool DWARFExpression::operator==(const DWARFExpression &RHS) const {
+ if (AddressSize != RHS.AddressSize || Format != RHS.Format)
+ return false;
+ return Data.getData() == RHS.Data.getData();
+}
+
+} // namespace llvm
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFFormValue.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFFormValue.cpp
new file mode 100644
index 0000000000..86991a3949
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFFormValue.cpp
@@ -0,0 +1,781 @@
+//===- DWARFFormValue.cpp -------------------------------------------------===//
+//
+// 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/DWARF/DWARFFormValue.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/None.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFRelocMap.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cinttypes>
+#include <cstdint>
+#include <limits>
+
+using namespace llvm;
+using namespace dwarf;
+
+static const DWARFFormValue::FormClass DWARF5FormClasses[] = {
+ DWARFFormValue::FC_Unknown, // 0x0
+ DWARFFormValue::FC_Address, // 0x01 DW_FORM_addr
+ DWARFFormValue::FC_Unknown, // 0x02 unused
+ DWARFFormValue::FC_Block, // 0x03 DW_FORM_block2
+ DWARFFormValue::FC_Block, // 0x04 DW_FORM_block4
+ DWARFFormValue::FC_Constant, // 0x05 DW_FORM_data2
+ // --- These can be FC_SectionOffset in DWARF3 and below:
+ DWARFFormValue::FC_Constant, // 0x06 DW_FORM_data4
+ DWARFFormValue::FC_Constant, // 0x07 DW_FORM_data8
+ // ---
+ DWARFFormValue::FC_String, // 0x08 DW_FORM_string
+ DWARFFormValue::FC_Block, // 0x09 DW_FORM_block
+ DWARFFormValue::FC_Block, // 0x0a DW_FORM_block1
+ DWARFFormValue::FC_Constant, // 0x0b DW_FORM_data1
+ DWARFFormValue::FC_Flag, // 0x0c DW_FORM_flag
+ DWARFFormValue::FC_Constant, // 0x0d DW_FORM_sdata
+ DWARFFormValue::FC_String, // 0x0e DW_FORM_strp
+ DWARFFormValue::FC_Constant, // 0x0f DW_FORM_udata
+ DWARFFormValue::FC_Reference, // 0x10 DW_FORM_ref_addr
+ DWARFFormValue::FC_Reference, // 0x11 DW_FORM_ref1
+ DWARFFormValue::FC_Reference, // 0x12 DW_FORM_ref2
+ DWARFFormValue::FC_Reference, // 0x13 DW_FORM_ref4
+ DWARFFormValue::FC_Reference, // 0x14 DW_FORM_ref8
+ DWARFFormValue::FC_Reference, // 0x15 DW_FORM_ref_udata
+ DWARFFormValue::FC_Indirect, // 0x16 DW_FORM_indirect
+ DWARFFormValue::FC_SectionOffset, // 0x17 DW_FORM_sec_offset
+ DWARFFormValue::FC_Exprloc, // 0x18 DW_FORM_exprloc
+ DWARFFormValue::FC_Flag, // 0x19 DW_FORM_flag_present
+ DWARFFormValue::FC_String, // 0x1a DW_FORM_strx
+ DWARFFormValue::FC_Address, // 0x1b DW_FORM_addrx
+ DWARFFormValue::FC_Reference, // 0x1c DW_FORM_ref_sup4
+ DWARFFormValue::FC_String, // 0x1d DW_FORM_strp_sup
+ DWARFFormValue::FC_Constant, // 0x1e DW_FORM_data16
+ DWARFFormValue::FC_String, // 0x1f DW_FORM_line_strp
+ DWARFFormValue::FC_Reference, // 0x20 DW_FORM_ref_sig8
+ DWARFFormValue::FC_Constant, // 0x21 DW_FORM_implicit_const
+ DWARFFormValue::FC_SectionOffset, // 0x22 DW_FORM_loclistx
+ DWARFFormValue::FC_SectionOffset, // 0x23 DW_FORM_rnglistx
+ DWARFFormValue::FC_Reference, // 0x24 DW_FORM_ref_sup8
+ DWARFFormValue::FC_String, // 0x25 DW_FORM_strx1
+ DWARFFormValue::FC_String, // 0x26 DW_FORM_strx2
+ DWARFFormValue::FC_String, // 0x27 DW_FORM_strx3
+ DWARFFormValue::FC_String, // 0x28 DW_FORM_strx4
+ DWARFFormValue::FC_Address, // 0x29 DW_FORM_addrx1
+ DWARFFormValue::FC_Address, // 0x2a DW_FORM_addrx2
+ DWARFFormValue::FC_Address, // 0x2b DW_FORM_addrx3
+ DWARFFormValue::FC_Address, // 0x2c DW_FORM_addrx4
+ DWARFFormValue::FC_Address, // 0x2001 DW_FORM_addrx_offset
+};
+
+DWARFFormValue DWARFFormValue::createFromSValue(dwarf::Form F, int64_t V) {
+ return DWARFFormValue(F, ValueType(V));
+}
+
+DWARFFormValue DWARFFormValue::createFromUValue(dwarf::Form F, uint64_t V) {
+ return DWARFFormValue(F, ValueType(V));
+}
+
+DWARFFormValue DWARFFormValue::createFromPValue(dwarf::Form F, const char *V) {
+ return DWARFFormValue(F, ValueType(V));
+}
+
+DWARFFormValue DWARFFormValue::createFromBlockValue(dwarf::Form F,
+ ArrayRef<uint8_t> D) {
+ ValueType V;
+ V.uval = D.size();
+ V.data = D.data();
+ return DWARFFormValue(F, V);
+}
+
+DWARFFormValue DWARFFormValue::createFromUnit(dwarf::Form F, const DWARFUnit *U,
+ uint64_t *OffsetPtr) {
+ DWARFFormValue FormValue(F);
+ FormValue.extractValue(U->getDebugInfoExtractor(), OffsetPtr,
+ U->getFormParams(), U);
+ return FormValue;
+}
+
+bool DWARFFormValue::skipValue(dwarf::Form Form, DataExtractor DebugInfoData,
+ uint64_t *OffsetPtr,
+ const dwarf::FormParams Params) {
+ bool Indirect = false;
+ do {
+ switch (Form) {
+ // Blocks of inlined data that have a length field and the data bytes
+ // inlined in the .debug_info.
+ case DW_FORM_exprloc:
+ case DW_FORM_block: {
+ uint64_t size = DebugInfoData.getULEB128(OffsetPtr);
+ *OffsetPtr += size;
+ return true;
+ }
+ case DW_FORM_block1: {
+ uint8_t size = DebugInfoData.getU8(OffsetPtr);
+ *OffsetPtr += size;
+ return true;
+ }
+ case DW_FORM_block2: {
+ uint16_t size = DebugInfoData.getU16(OffsetPtr);
+ *OffsetPtr += size;
+ return true;
+ }
+ case DW_FORM_block4: {
+ uint32_t size = DebugInfoData.getU32(OffsetPtr);
+ *OffsetPtr += size;
+ return true;
+ }
+
+ // Inlined NULL terminated C-strings.
+ case DW_FORM_string:
+ DebugInfoData.getCStr(OffsetPtr);
+ return true;
+
+ case DW_FORM_addr:
+ case DW_FORM_ref_addr:
+ case DW_FORM_flag_present:
+ case DW_FORM_data1:
+ case DW_FORM_data2:
+ case DW_FORM_data4:
+ case DW_FORM_data8:
+ case DW_FORM_data16:
+ case DW_FORM_flag:
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_sig8:
+ case DW_FORM_ref_sup4:
+ case DW_FORM_ref_sup8:
+ case DW_FORM_strx1:
+ case DW_FORM_strx2:
+ case DW_FORM_strx4:
+ case DW_FORM_addrx1:
+ case DW_FORM_addrx2:
+ case DW_FORM_addrx4:
+ case DW_FORM_sec_offset:
+ case DW_FORM_strp:
+ case DW_FORM_strp_sup:
+ case DW_FORM_line_strp:
+ case DW_FORM_GNU_ref_alt:
+ case DW_FORM_GNU_strp_alt:
+ case DW_FORM_implicit_const:
+ if (Optional<uint8_t> FixedSize =
+ dwarf::getFixedFormByteSize(Form, Params)) {
+ *OffsetPtr += *FixedSize;
+ return true;
+ }
+ return false;
+
+ // signed or unsigned LEB 128 values.
+ case DW_FORM_sdata:
+ DebugInfoData.getSLEB128(OffsetPtr);
+ return true;
+
+ case DW_FORM_udata:
+ case DW_FORM_ref_udata:
+ case DW_FORM_strx:
+ case DW_FORM_addrx:
+ case DW_FORM_loclistx:
+ case DW_FORM_rnglistx:
+ case DW_FORM_GNU_addr_index:
+ case DW_FORM_GNU_str_index:
+ DebugInfoData.getULEB128(OffsetPtr);
+ return true;
+
+ case DW_FORM_LLVM_addrx_offset:
+ DebugInfoData.getULEB128(OffsetPtr);
+ *OffsetPtr += 4;
+ return true;
+
+ case DW_FORM_indirect:
+ Indirect = true;
+ Form = static_cast<dwarf::Form>(DebugInfoData.getULEB128(OffsetPtr));
+ break;
+
+ default:
+ return false;
+ }
+ } while (Indirect);
+ return true;
+}
+
+bool DWARFFormValue::isFormClass(DWARFFormValue::FormClass FC) const {
+ // First, check DWARF5 form classes.
+ if (Form < makeArrayRef(DWARF5FormClasses).size() &&
+ DWARF5FormClasses[Form] == FC)
+ return true;
+ // Check more forms from extensions and proposals.
+ switch (Form) {
+ case DW_FORM_GNU_ref_alt:
+ return (FC == FC_Reference);
+ case DW_FORM_GNU_addr_index:
+ return (FC == FC_Address);
+ case DW_FORM_GNU_str_index:
+ case DW_FORM_GNU_strp_alt:
+ return (FC == FC_String);
+ case DW_FORM_LLVM_addrx_offset:
+ return (FC == FC_Address);
+ default:
+ break;
+ }
+
+ if (FC == FC_SectionOffset) {
+ if (Form == DW_FORM_strp || Form == DW_FORM_line_strp)
+ return true;
+ // In DWARF3 DW_FORM_data4 and DW_FORM_data8 served also as a section
+ // offset. If we don't have a DWARFUnit, default to the old behavior.
+ if (Form == DW_FORM_data4 || Form == DW_FORM_data8)
+ return !U || U->getVersion() <= 3;
+ }
+
+ return false;
+}
+
+bool DWARFFormValue::extractValue(const DWARFDataExtractor &Data,
+ uint64_t *OffsetPtr, dwarf::FormParams FP,
+ const DWARFContext *Ctx,
+ const DWARFUnit *CU) {
+ if (!Ctx && CU)
+ Ctx = &CU->getContext();
+ C = Ctx;
+ U = CU;
+ Format = FP.Format;
+ bool Indirect = false;
+ bool IsBlock = false;
+ Value.data = nullptr;
+ // Read the value for the form into value and follow and DW_FORM_indirect
+ // instances we run into
+ Error Err = Error::success();
+ do {
+ Indirect = false;
+ switch (Form) {
+ case DW_FORM_addr:
+ case DW_FORM_ref_addr: {
+ uint16_t Size =
+ (Form == DW_FORM_addr) ? FP.AddrSize : FP.getRefAddrByteSize();
+ Value.uval =
+ Data.getRelocatedValue(Size, OffsetPtr, &Value.SectionIndex, &Err);
+ break;
+ }
+ case DW_FORM_exprloc:
+ case DW_FORM_block:
+ Value.uval = Data.getULEB128(OffsetPtr, &Err);
+ IsBlock = true;
+ break;
+ case DW_FORM_block1:
+ Value.uval = Data.getU8(OffsetPtr, &Err);
+ IsBlock = true;
+ break;
+ case DW_FORM_block2:
+ Value.uval = Data.getU16(OffsetPtr, &Err);
+ IsBlock = true;
+ break;
+ case DW_FORM_block4:
+ Value.uval = Data.getU32(OffsetPtr, &Err);
+ IsBlock = true;
+ break;
+ case DW_FORM_data1:
+ case DW_FORM_ref1:
+ case DW_FORM_flag:
+ case DW_FORM_strx1:
+ case DW_FORM_addrx1:
+ Value.uval = Data.getU8(OffsetPtr, &Err);
+ break;
+ case DW_FORM_data2:
+ case DW_FORM_ref2:
+ case DW_FORM_strx2:
+ case DW_FORM_addrx2:
+ Value.uval = Data.getU16(OffsetPtr, &Err);
+ break;
+ case DW_FORM_strx3:
+ Value.uval = Data.getU24(OffsetPtr, &Err);
+ break;
+ case DW_FORM_data4:
+ case DW_FORM_ref4:
+ case DW_FORM_ref_sup4:
+ case DW_FORM_strx4:
+ case DW_FORM_addrx4:
+ Value.uval = Data.getRelocatedValue(4, OffsetPtr, nullptr, &Err);
+ break;
+ case DW_FORM_data8:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_sup8:
+ Value.uval = Data.getRelocatedValue(8, OffsetPtr, nullptr, &Err);
+ break;
+ case DW_FORM_data16:
+ // Treat this like a 16-byte block.
+ Value.uval = 16;
+ IsBlock = true;
+ break;
+ case DW_FORM_sdata:
+ Value.sval = Data.getSLEB128(OffsetPtr, &Err);
+ break;
+ case DW_FORM_udata:
+ case DW_FORM_ref_udata:
+ case DW_FORM_rnglistx:
+ case DW_FORM_loclistx:
+ case DW_FORM_GNU_addr_index:
+ case DW_FORM_GNU_str_index:
+ case DW_FORM_addrx:
+ case DW_FORM_strx:
+ Value.uval = Data.getULEB128(OffsetPtr, &Err);
+ break;
+ case DW_FORM_LLVM_addrx_offset:
+ Value.uval = Data.getULEB128(OffsetPtr, &Err) << 32;
+ Value.uval |= Data.getU32(OffsetPtr, &Err);
+ break;
+ case DW_FORM_string:
+ Value.cstr = Data.getCStr(OffsetPtr, &Err);
+ break;
+ case DW_FORM_indirect:
+ Form = static_cast<dwarf::Form>(Data.getULEB128(OffsetPtr, &Err));
+ Indirect = true;
+ break;
+ case DW_FORM_strp:
+ case DW_FORM_sec_offset:
+ case DW_FORM_GNU_ref_alt:
+ case DW_FORM_GNU_strp_alt:
+ case DW_FORM_line_strp:
+ case DW_FORM_strp_sup: {
+ Value.uval = Data.getRelocatedValue(FP.getDwarfOffsetByteSize(),
+ OffsetPtr, nullptr, &Err);
+ break;
+ }
+ case DW_FORM_flag_present:
+ Value.uval = 1;
+ break;
+ case DW_FORM_ref_sig8:
+ Value.uval = Data.getU64(OffsetPtr, &Err);
+ break;
+ case DW_FORM_implicit_const:
+ // Value has been already set by DWARFFormValue::createFromSValue.
+ break;
+ default:
+ // DWARFFormValue::skipValue() will have caught this and caused all
+ // DWARF DIEs to fail to be parsed, so this code is not be reachable.
+ llvm_unreachable("unsupported form");
+ }
+ } while (Indirect && !Err);
+
+ if (IsBlock)
+ Value.data = Data.getBytes(OffsetPtr, Value.uval, &Err).bytes_begin();
+
+ return !errorToBool(std::move(Err));
+}
+
+void DWARFFormValue::dumpAddress(raw_ostream &OS, uint8_t AddressSize,
+ uint64_t Address) {
+ uint8_t HexDigits = AddressSize * 2;
+ OS << format("0x%*.*" PRIx64, HexDigits, HexDigits, Address);
+}
+
+void DWARFFormValue::dumpSectionedAddress(raw_ostream &OS,
+ DIDumpOptions DumpOpts,
+ object::SectionedAddress SA) const {
+ dumpAddress(OS, U->getAddressByteSize(), SA.Address);
+ dumpAddressSection(U->getContext().getDWARFObj(), OS, DumpOpts,
+ SA.SectionIndex);
+}
+
+void DWARFFormValue::dumpAddressSection(const DWARFObject &Obj, raw_ostream &OS,
+ DIDumpOptions DumpOpts,
+ uint64_t SectionIndex) {
+ if (!DumpOpts.Verbose || SectionIndex == -1ULL)
+ return;
+ ArrayRef<SectionName> SectionNames = Obj.getSectionNames();
+ const auto &SecRef = SectionNames[SectionIndex];
+
+ OS << " \"" << SecRef.Name << '\"';
+
+ // Print section index if name is not unique.
+ if (!SecRef.IsNameUnique)
+ OS << format(" [%" PRIu64 "]", SectionIndex);
+}
+
+void DWARFFormValue::dump(raw_ostream &OS, DIDumpOptions DumpOpts) const {
+ uint64_t UValue = Value.uval;
+ bool CURelativeOffset = false;
+ raw_ostream &AddrOS = DumpOpts.ShowAddresses
+ ? WithColor(OS, HighlightColor::Address).get()
+ : nulls();
+ int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format);
+ switch (Form) {
+ case DW_FORM_addr:
+ dumpSectionedAddress(AddrOS, DumpOpts, {Value.uval, Value.SectionIndex});
+ break;
+ case DW_FORM_addrx:
+ case DW_FORM_addrx1:
+ case DW_FORM_addrx2:
+ case DW_FORM_addrx3:
+ case DW_FORM_addrx4:
+ case DW_FORM_GNU_addr_index: {
+ if (U == nullptr) {
+ OS << "<invalid dwarf unit>";
+ break;
+ }
+ Optional<object::SectionedAddress> A = U->getAddrOffsetSectionItem(UValue);
+ if (!A || DumpOpts.Verbose)
+ AddrOS << format("indexed (%8.8x) address = ", (uint32_t)UValue);
+ if (A)
+ dumpSectionedAddress(AddrOS, DumpOpts, *A);
+ else
+ OS << "<unresolved>";
+ break;
+ }
+ case DW_FORM_LLVM_addrx_offset: {
+ if (U == nullptr) {
+ OS << "<invalid dwarf unit>";
+ break;
+ }
+ uint32_t Index = UValue >> 32;
+ uint32_t Offset = UValue & 0xffffffff;
+ Optional<object::SectionedAddress> A = U->getAddrOffsetSectionItem(Index);
+ if (!A || DumpOpts.Verbose)
+ AddrOS << format("indexed (%8.8x) + 0x%x address = ", Index, Offset);
+ if (A) {
+ A->Address += Offset;
+ dumpSectionedAddress(AddrOS, DumpOpts, *A);
+ } else
+ OS << "<unresolved>";
+ break;
+ }
+ case DW_FORM_flag_present:
+ OS << "true";
+ break;
+ case DW_FORM_flag:
+ case DW_FORM_data1:
+ OS << format("0x%02x", (uint8_t)UValue);
+ break;
+ case DW_FORM_data2:
+ OS << format("0x%04x", (uint16_t)UValue);
+ break;
+ case DW_FORM_data4:
+ OS << format("0x%08x", (uint32_t)UValue);
+ break;
+ case DW_FORM_ref_sig8:
+ AddrOS << format("0x%016" PRIx64, UValue);
+ break;
+ case DW_FORM_data8:
+ OS << format("0x%016" PRIx64, UValue);
+ break;
+ case DW_FORM_data16:
+ OS << format_bytes(ArrayRef<uint8_t>(Value.data, 16), None, 16, 16);
+ break;
+ case DW_FORM_string:
+ OS << '"';
+ OS.write_escaped(Value.cstr);
+ OS << '"';
+ break;
+ case DW_FORM_exprloc:
+ case DW_FORM_block:
+ case DW_FORM_block1:
+ case DW_FORM_block2:
+ case DW_FORM_block4:
+ if (UValue > 0) {
+ switch (Form) {
+ case DW_FORM_exprloc:
+ case DW_FORM_block:
+ AddrOS << format("<0x%" PRIx64 "> ", UValue);
+ break;
+ case DW_FORM_block1:
+ AddrOS << format("<0x%2.2x> ", (uint8_t)UValue);
+ break;
+ case DW_FORM_block2:
+ AddrOS << format("<0x%4.4x> ", (uint16_t)UValue);
+ break;
+ case DW_FORM_block4:
+ AddrOS << format("<0x%8.8x> ", (uint32_t)UValue);
+ break;
+ default:
+ break;
+ }
+
+ const uint8_t *DataPtr = Value.data;
+ if (DataPtr) {
+ // UValue contains size of block
+ const uint8_t *EndDataPtr = DataPtr + UValue;
+ while (DataPtr < EndDataPtr) {
+ AddrOS << format("%2.2x ", *DataPtr);
+ ++DataPtr;
+ }
+ } else
+ OS << "NULL";
+ }
+ break;
+
+ case DW_FORM_sdata:
+ case DW_FORM_implicit_const:
+ OS << Value.sval;
+ break;
+ case DW_FORM_udata:
+ OS << Value.uval;
+ break;
+ case DW_FORM_strp:
+ if (DumpOpts.Verbose)
+ OS << format(" .debug_str[0x%0*" PRIx64 "] = ", OffsetDumpWidth, UValue);
+ dumpString(OS);
+ break;
+ case DW_FORM_line_strp:
+ if (DumpOpts.Verbose)
+ OS << format(" .debug_line_str[0x%0*" PRIx64 "] = ", OffsetDumpWidth,
+ UValue);
+ dumpString(OS);
+ break;
+ case DW_FORM_strx:
+ case DW_FORM_strx1:
+ case DW_FORM_strx2:
+ case DW_FORM_strx3:
+ case DW_FORM_strx4:
+ case DW_FORM_GNU_str_index:
+ if (DumpOpts.Verbose)
+ OS << format("indexed (%8.8x) string = ", (uint32_t)UValue);
+ dumpString(OS);
+ break;
+ case DW_FORM_GNU_strp_alt:
+ if (DumpOpts.Verbose)
+ OS << format("alt indirect string, offset: 0x%" PRIx64 "", UValue);
+ dumpString(OS);
+ break;
+ case DW_FORM_ref_addr:
+ AddrOS << format("0x%016" PRIx64, UValue);
+ break;
+ case DW_FORM_ref1:
+ CURelativeOffset = true;
+ if (DumpOpts.Verbose)
+ AddrOS << format("cu + 0x%2.2x", (uint8_t)UValue);
+ break;
+ case DW_FORM_ref2:
+ CURelativeOffset = true;
+ if (DumpOpts.Verbose)
+ AddrOS << format("cu + 0x%4.4x", (uint16_t)UValue);
+ break;
+ case DW_FORM_ref4:
+ CURelativeOffset = true;
+ if (DumpOpts.Verbose)
+ AddrOS << format("cu + 0x%4.4x", (uint32_t)UValue);
+ break;
+ case DW_FORM_ref8:
+ CURelativeOffset = true;
+ if (DumpOpts.Verbose)
+ AddrOS << format("cu + 0x%8.8" PRIx64, UValue);
+ break;
+ case DW_FORM_ref_udata:
+ CURelativeOffset = true;
+ if (DumpOpts.Verbose)
+ AddrOS << format("cu + 0x%" PRIx64, UValue);
+ break;
+ case DW_FORM_GNU_ref_alt:
+ AddrOS << format("<alt 0x%" PRIx64 ">", UValue);
+ break;
+
+ // All DW_FORM_indirect attributes should be resolved prior to calling
+ // this function
+ case DW_FORM_indirect:
+ OS << "DW_FORM_indirect";
+ break;
+
+ case DW_FORM_rnglistx:
+ OS << format("indexed (0x%x) rangelist = ", (uint32_t)UValue);
+ break;
+
+ case DW_FORM_loclistx:
+ OS << format("indexed (0x%x) loclist = ", (uint32_t)UValue);
+ break;
+
+ case DW_FORM_sec_offset:
+ AddrOS << format("0x%0*" PRIx64, OffsetDumpWidth, UValue);
+ break;
+
+ default:
+ OS << format("DW_FORM(0x%4.4x)", Form);
+ break;
+ }
+
+ if (CURelativeOffset) {
+ if (DumpOpts.Verbose)
+ OS << " => {";
+ if (DumpOpts.ShowAddresses)
+ WithColor(OS, HighlightColor::Address).get()
+ << format("0x%8.8" PRIx64, UValue + (U ? U->getOffset() : 0));
+ if (DumpOpts.Verbose)
+ OS << "}";
+ }
+}
+
+void DWARFFormValue::dumpString(raw_ostream &OS) const {
+ if (auto DbgStr = dwarf::toString(*this)) {
+ auto COS = WithColor(OS, HighlightColor::String);
+ COS.get() << '"';
+ COS.get().write_escaped(*DbgStr);
+ COS.get() << '"';
+ }
+}
+
+Expected<const char *> DWARFFormValue::getAsCString() const {
+ if (!isFormClass(FC_String))
+ return make_error<StringError>("Invalid form for string attribute",
+ inconvertibleErrorCode());
+ if (Form == DW_FORM_string)
+ return Value.cstr;
+ // FIXME: Add support for DW_FORM_GNU_strp_alt
+ if (Form == DW_FORM_GNU_strp_alt || C == nullptr)
+ return make_error<StringError>("Unsupported form for string attribute",
+ inconvertibleErrorCode());
+ uint64_t Offset = Value.uval;
+ Optional<uint32_t> Index;
+ if (Form == DW_FORM_GNU_str_index || Form == DW_FORM_strx ||
+ Form == DW_FORM_strx1 || Form == DW_FORM_strx2 || Form == DW_FORM_strx3 ||
+ Form == DW_FORM_strx4) {
+ if (!U)
+ return make_error<StringError>("API limitation - string extraction not "
+ "available without a DWARFUnit",
+ inconvertibleErrorCode());
+ Expected<uint64_t> StrOffset = U->getStringOffsetSectionItem(Offset);
+ Index = Offset;
+ if (!StrOffset)
+ return StrOffset.takeError();
+ Offset = *StrOffset;
+ }
+ // Prefer the Unit's string extractor, because for .dwo it will point to
+ // .debug_str.dwo, while the Context's extractor always uses .debug_str.
+ DataExtractor StrData = Form == DW_FORM_line_strp
+ ? C->getLineStringExtractor()
+ : U ? U->getStringExtractor()
+ : C->getStringExtractor();
+ if (const char *Str = StrData.getCStr(&Offset))
+ return Str;
+ std::string Msg = FormEncodingString(Form).str();
+ if (Index)
+ Msg += (" uses index " + Twine(*Index) + ", but the referenced string").str();
+ Msg += (" offset " + Twine(Offset) + " is beyond .debug_str bounds").str();
+ return make_error<StringError>(Msg,
+ inconvertibleErrorCode());
+}
+
+Optional<uint64_t> DWARFFormValue::getAsAddress() const {
+ if (auto SA = getAsSectionedAddress())
+ return SA->Address;
+ return None;
+}
+
+Optional<object::SectionedAddress>
+DWARFFormValue::getAsSectionedAddress() const {
+ if (!isFormClass(FC_Address))
+ return None;
+ bool AddrOffset = Form == dwarf::DW_FORM_LLVM_addrx_offset;
+ if (Form == DW_FORM_GNU_addr_index || Form == DW_FORM_addrx || AddrOffset) {
+
+ uint32_t Index = AddrOffset ? (Value.uval >> 32) : Value.uval;
+ if (!U)
+ return None;
+ Optional<object::SectionedAddress> SA = U->getAddrOffsetSectionItem(Index);
+ if (!SA)
+ return None;
+ if (AddrOffset)
+ SA->Address += (Value.uval & 0xffffffff);
+ return SA;
+ }
+ return {{Value.uval, Value.SectionIndex}};
+}
+
+Optional<uint64_t> DWARFFormValue::getAsReference() const {
+ if (auto R = getAsRelativeReference())
+ return R->Unit ? R->Unit->getOffset() + R->Offset : R->Offset;
+ return None;
+}
+
+Optional<DWARFFormValue::UnitOffset> DWARFFormValue::getAsRelativeReference() const {
+ if (!isFormClass(FC_Reference))
+ return None;
+ switch (Form) {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata:
+ if (!U)
+ return None;
+ return UnitOffset{const_cast<DWARFUnit*>(U), Value.uval};
+ case DW_FORM_ref_addr:
+ case DW_FORM_ref_sig8:
+ case DW_FORM_GNU_ref_alt:
+ return UnitOffset{nullptr, Value.uval};
+ default:
+ return None;
+ }
+}
+
+Optional<uint64_t> DWARFFormValue::getAsSectionOffset() const {
+ if (!isFormClass(FC_SectionOffset))
+ return None;
+ return Value.uval;
+}
+
+Optional<uint64_t> DWARFFormValue::getAsUnsignedConstant() const {
+ if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) ||
+ Form == DW_FORM_sdata)
+ return None;
+ return Value.uval;
+}
+
+Optional<int64_t> DWARFFormValue::getAsSignedConstant() const {
+ if ((!isFormClass(FC_Constant) && !isFormClass(FC_Flag)) ||
+ (Form == DW_FORM_udata &&
+ uint64_t(std::numeric_limits<int64_t>::max()) < Value.uval))
+ return None;
+ switch (Form) {
+ case DW_FORM_data4:
+ return int32_t(Value.uval);
+ case DW_FORM_data2:
+ return int16_t(Value.uval);
+ case DW_FORM_data1:
+ return int8_t(Value.uval);
+ case DW_FORM_sdata:
+ case DW_FORM_data8:
+ default:
+ return Value.sval;
+ }
+}
+
+Optional<ArrayRef<uint8_t>> DWARFFormValue::getAsBlock() const {
+ if (!isFormClass(FC_Block) && !isFormClass(FC_Exprloc) &&
+ Form != DW_FORM_data16)
+ return None;
+ return makeArrayRef(Value.data, Value.uval);
+}
+
+Optional<uint64_t> DWARFFormValue::getAsCStringOffset() const {
+ if (!isFormClass(FC_String) && Form == DW_FORM_string)
+ return None;
+ return Value.uval;
+}
+
+Optional<uint64_t> DWARFFormValue::getAsReferenceUVal() const {
+ if (!isFormClass(FC_Reference))
+ return None;
+ return Value.uval;
+}
+
+Optional<std::string>
+DWARFFormValue::getAsFile(DILineInfoSpecifier::FileLineInfoKind Kind) const {
+ if (U == nullptr || !isFormClass(FC_Constant))
+ return None;
+ DWARFUnit *DLU = const_cast<DWARFUnit *>(U)->getLinkedUnit();
+ if (auto *LT = DLU->getContext().getLineTableForUnit(DLU)) {
+ std::string FileName;
+ if (LT->getFileNameByIndex(Value.uval, DLU->getCompilationDir(), Kind,
+ FileName))
+ return FileName;
+ }
+ return None;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp
new file mode 100644
index 0000000000..ace7000f07
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFGdbIndex.cpp
@@ -0,0 +1,199 @@
+//===- DWARFGdbIndex.cpp --------------------------------------------------===//
+//
+// 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/DWARF/DWARFGdbIndex.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cassert>
+#include <cinttypes>
+#include <cstdint>
+#include <utility>
+
+using namespace llvm;
+
+// .gdb_index section format reference:
+// https://sourceware.org/gdb/onlinedocs/gdb/Index-Section-Format.html
+
+void DWARFGdbIndex::dumpCUList(raw_ostream &OS) const {
+ OS << format("\n CU list offset = 0x%x, has %" PRId64 " entries:",
+ CuListOffset, (uint64_t)CuList.size())
+ << '\n';
+ uint32_t I = 0;
+ for (const CompUnitEntry &CU : CuList)
+ OS << format(" %d: Offset = 0x%llx, Length = 0x%llx\n", I++, CU.Offset,
+ CU.Length);
+}
+
+void DWARFGdbIndex::dumpTUList(raw_ostream &OS) const {
+ OS << formatv("\n Types CU list offset = {0:x}, has {1} entries:\n",
+ TuListOffset, TuList.size());
+ uint32_t I = 0;
+ for (const TypeUnitEntry &TU : TuList)
+ OS << formatv(" {0}: offset = {1:x8}, type_offset = {2:x8}, "
+ "type_signature = {3:x16}\n",
+ I++, TU.Offset, TU.TypeOffset, TU.TypeSignature);
+}
+
+void DWARFGdbIndex::dumpAddressArea(raw_ostream &OS) const {
+ OS << format("\n Address area offset = 0x%x, has %" PRId64 " entries:",
+ AddressAreaOffset, (uint64_t)AddressArea.size())
+ << '\n';
+ for (const AddressEntry &Addr : AddressArea)
+ OS << format(
+ " Low/High address = [0x%llx, 0x%llx) (Size: 0x%llx), CU id = %d\n",
+ Addr.LowAddress, Addr.HighAddress, Addr.HighAddress - Addr.LowAddress,
+ Addr.CuIndex);
+}
+
+void DWARFGdbIndex::dumpSymbolTable(raw_ostream &OS) const {
+ OS << format("\n Symbol table offset = 0x%x, size = %" PRId64
+ ", filled slots:",
+ SymbolTableOffset, (uint64_t)SymbolTable.size())
+ << '\n';
+ uint32_t I = -1;
+ for (const SymTableEntry &E : SymbolTable) {
+ ++I;
+ if (!E.NameOffset && !E.VecOffset)
+ continue;
+
+ OS << format(" %d: Name offset = 0x%x, CU vector offset = 0x%x\n", I,
+ E.NameOffset, E.VecOffset);
+
+ StringRef Name = ConstantPoolStrings.substr(
+ ConstantPoolOffset - StringPoolOffset + E.NameOffset);
+
+ auto CuVector = llvm::find_if(
+ ConstantPoolVectors,
+ [&](const std::pair<uint32_t, SmallVector<uint32_t, 0>> &V) {
+ return V.first == E.VecOffset;
+ });
+ assert(CuVector != ConstantPoolVectors.end() && "Invalid symbol table");
+ uint32_t CuVectorId = CuVector - ConstantPoolVectors.begin();
+ OS << format(" String name: %s, CU vector index: %d\n", Name.data(),
+ CuVectorId);
+ }
+}
+
+void DWARFGdbIndex::dumpConstantPool(raw_ostream &OS) const {
+ OS << format("\n Constant pool offset = 0x%x, has %" PRId64 " CU vectors:",
+ ConstantPoolOffset, (uint64_t)ConstantPoolVectors.size());
+ uint32_t I = 0;
+ for (const auto &V : ConstantPoolVectors) {
+ OS << format("\n %d(0x%x): ", I++, V.first);
+ for (uint32_t Val : V.second)
+ OS << format("0x%x ", Val);
+ }
+ OS << '\n';
+}
+
+void DWARFGdbIndex::dump(raw_ostream &OS) {
+ if (HasError) {
+ OS << "\n<error parsing>\n";
+ return;
+ }
+
+ if (HasContent) {
+ OS << " Version = " << Version << '\n';
+ dumpCUList(OS);
+ dumpTUList(OS);
+ dumpAddressArea(OS);
+ dumpSymbolTable(OS);
+ dumpConstantPool(OS);
+ }
+}
+
+bool DWARFGdbIndex::parseImpl(DataExtractor Data) {
+ uint64_t Offset = 0;
+
+ // Only version 7 is supported at this moment.
+ Version = Data.getU32(&Offset);
+ if (Version != 7)
+ return false;
+
+ CuListOffset = Data.getU32(&Offset);
+ TuListOffset = Data.getU32(&Offset);
+ AddressAreaOffset = Data.getU32(&Offset);
+ SymbolTableOffset = Data.getU32(&Offset);
+ ConstantPoolOffset = Data.getU32(&Offset);
+
+ if (Offset != CuListOffset)
+ return false;
+
+ uint32_t CuListSize = (TuListOffset - CuListOffset) / 16;
+ CuList.reserve(CuListSize);
+ for (uint32_t i = 0; i < CuListSize; ++i) {
+ uint64_t CuOffset = Data.getU64(&Offset);
+ uint64_t CuLength = Data.getU64(&Offset);
+ CuList.push_back({CuOffset, CuLength});
+ }
+
+ // CU Types are no longer needed as DWARF skeleton type units never made it
+ // into the standard.
+ uint32_t TuListSize = (AddressAreaOffset - TuListOffset) / 24;
+ TuList.resize(TuListSize);
+ for (uint32_t I = 0; I < TuListSize; ++I) {
+ uint64_t CuOffset = Data.getU64(&Offset);
+ uint64_t TypeOffset = Data.getU64(&Offset);
+ uint64_t Signature = Data.getU64(&Offset);
+ TuList[I] = {CuOffset, TypeOffset, Signature};
+ }
+
+ uint32_t AddressAreaSize = (SymbolTableOffset - AddressAreaOffset) / 20;
+ AddressArea.reserve(AddressAreaSize);
+ for (uint32_t i = 0; i < AddressAreaSize; ++i) {
+ uint64_t LowAddress = Data.getU64(&Offset);
+ uint64_t HighAddress = Data.getU64(&Offset);
+ uint32_t CuIndex = Data.getU32(&Offset);
+ AddressArea.push_back({LowAddress, HighAddress, CuIndex});
+ }
+
+ // The symbol table. This is an open addressed hash table. The size of the
+ // hash table is always a power of 2.
+ // Each slot in the hash table consists of a pair of offset_type values. The
+ // first value is the offset of the symbol's name in the constant pool. The
+ // second value is the offset of the CU vector in the constant pool.
+ // If both values are 0, then this slot in the hash table is empty. This is ok
+ // because while 0 is a valid constant pool index, it cannot be a valid index
+ // for both a string and a CU vector.
+ uint32_t SymTableSize = (ConstantPoolOffset - SymbolTableOffset) / 8;
+ SymbolTable.reserve(SymTableSize);
+ uint32_t CuVectorsTotal = 0;
+ for (uint32_t i = 0; i < SymTableSize; ++i) {
+ uint32_t NameOffset = Data.getU32(&Offset);
+ uint32_t CuVecOffset = Data.getU32(&Offset);
+ SymbolTable.push_back({NameOffset, CuVecOffset});
+ if (NameOffset || CuVecOffset)
+ ++CuVectorsTotal;
+ }
+
+ // The constant pool. CU vectors are stored first, followed by strings.
+ // The first value is the number of CU indices in the vector. Each subsequent
+ // value is the index and symbol attributes of a CU in the CU list.
+ for (uint32_t i = 0; i < CuVectorsTotal; ++i) {
+ ConstantPoolVectors.emplace_back(0, SmallVector<uint32_t, 0>());
+ auto &Vec = ConstantPoolVectors.back();
+ Vec.first = Offset - ConstantPoolOffset;
+
+ uint32_t Num = Data.getU32(&Offset);
+ for (uint32_t j = 0; j < Num; ++j)
+ Vec.second.push_back(Data.getU32(&Offset));
+ }
+
+ ConstantPoolStrings = Data.getData().drop_front(Offset);
+ StringPoolOffset = Offset;
+ return true;
+}
+
+void DWARFGdbIndex::parse(DataExtractor Data) {
+ HasContent = !Data.getData().empty();
+ HasError = HasContent && !parseImpl(Data);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFListTable.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFListTable.cpp
new file mode 100644
index 0000000000..b73dda3ff9
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFListTable.cpp
@@ -0,0 +1,109 @@
+//===- DWARFListTable.cpp ---------------------------------------------===//
+//
+// 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/DWARF/DWARFListTable.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+
+Error DWARFListTableHeader::extract(DWARFDataExtractor Data,
+ uint64_t *OffsetPtr) {
+ HeaderOffset = *OffsetPtr;
+ Error Err = Error::success();
+
+ std::tie(HeaderData.Length, Format) = Data.getInitialLength(OffsetPtr, &Err);
+ if (Err)
+ return createStringError(
+ errc::invalid_argument, "parsing %s table at offset 0x%" PRIx64 ": %s",
+ SectionName.data(), HeaderOffset, toString(std::move(Err)).c_str());
+
+ uint8_t OffsetByteSize = Format == dwarf::DWARF64 ? 8 : 4;
+ uint64_t FullLength =
+ HeaderData.Length + dwarf::getUnitLengthFieldByteSize(Format);
+ if (FullLength < getHeaderSize(Format))
+ return createStringError(errc::invalid_argument,
+ "%s table at offset 0x%" PRIx64
+ " has too small length (0x%" PRIx64
+ ") to contain a complete header",
+ SectionName.data(), HeaderOffset, FullLength);
+ assert(FullLength == length() && "Inconsistent calculation of length.");
+ uint64_t End = HeaderOffset + FullLength;
+ if (!Data.isValidOffsetForDataOfSize(HeaderOffset, FullLength))
+ return createStringError(errc::invalid_argument,
+ "section is not large enough to contain a %s table "
+ "of length 0x%" PRIx64 " at offset 0x%" PRIx64,
+ SectionName.data(), FullLength, HeaderOffset);
+
+ HeaderData.Version = Data.getU16(OffsetPtr);
+ HeaderData.AddrSize = Data.getU8(OffsetPtr);
+ HeaderData.SegSize = Data.getU8(OffsetPtr);
+ HeaderData.OffsetEntryCount = Data.getU32(OffsetPtr);
+
+ // Perform basic validation of the remaining header fields.
+ if (HeaderData.Version != 5)
+ return createStringError(errc::invalid_argument,
+ "unrecognised %s table version %" PRIu16
+ " in table at offset 0x%" PRIx64,
+ SectionName.data(), HeaderData.Version, HeaderOffset);
+ if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
+ HeaderData.AddrSize, errc::not_supported,
+ "%s table at offset 0x%" PRIx64, SectionName.data(), HeaderOffset))
+ return SizeErr;
+ if (HeaderData.SegSize != 0)
+ return createStringError(errc::not_supported,
+ "%s table at offset 0x%" PRIx64
+ " has unsupported segment selector size %" PRIu8,
+ SectionName.data(), HeaderOffset, HeaderData.SegSize);
+ if (End < HeaderOffset + getHeaderSize(Format) +
+ HeaderData.OffsetEntryCount * OffsetByteSize)
+ return createStringError(errc::invalid_argument,
+ "%s table at offset 0x%" PRIx64 " has more offset entries (%" PRIu32
+ ") than there is space for",
+ SectionName.data(), HeaderOffset, HeaderData.OffsetEntryCount);
+ Data.setAddressSize(HeaderData.AddrSize);
+ *OffsetPtr += HeaderData.OffsetEntryCount * OffsetByteSize;
+ return Error::success();
+}
+
+void DWARFListTableHeader::dump(DataExtractor Data, raw_ostream &OS,
+ DIDumpOptions DumpOpts) const {
+ if (DumpOpts.Verbose)
+ OS << format("0x%8.8" PRIx64 ": ", HeaderOffset);
+ int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(Format);
+ OS << format("%s list header: length = 0x%0*" PRIx64, ListTypeString.data(),
+ OffsetDumpWidth, HeaderData.Length)
+ << ", format = " << dwarf::FormatString(Format)
+ << format(", version = 0x%4.4" PRIx16 ", addr_size = 0x%2.2" PRIx8
+ ", seg_size = 0x%2.2" PRIx8
+ ", offset_entry_count = 0x%8.8" PRIx32 "\n",
+ HeaderData.Version, HeaderData.AddrSize, HeaderData.SegSize,
+ HeaderData.OffsetEntryCount);
+
+ if (HeaderData.OffsetEntryCount > 0) {
+ OS << "offsets: [";
+ for (uint32_t I = 0; I < HeaderData.OffsetEntryCount; ++I) {
+ auto Off = *getOffsetEntry(Data, I);
+ OS << format("\n0x%0*" PRIx64, OffsetDumpWidth, Off);
+ if (DumpOpts.Verbose)
+ OS << format(" => 0x%08" PRIx64,
+ Off + HeaderOffset + getHeaderSize(Format));
+ }
+ OS << "\n]\n";
+ }
+}
+
+uint64_t DWARFListTableHeader::length() const {
+ if (HeaderData.Length == 0)
+ return 0;
+ return HeaderData.Length + dwarf::getUnitLengthFieldByteSize(Format);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFLocationExpression.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFLocationExpression.cpp
new file mode 100644
index 0000000000..1cf73a6667
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFLocationExpression.cpp
@@ -0,0 +1,19 @@
+//===- DWARFLocationExpression.cpp ----------------------------------------===//
+//
+// 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/DWARF/DWARFLocationExpression.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+
+raw_ostream &llvm::operator<<(raw_ostream &OS,
+ const DWARFLocationExpression &Loc) {
+ return OS << Loc.Range << ": "
+ << formatv("{0}", make_range(Loc.Expr.begin(), Loc.Expr.end()));
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp
new file mode 100644
index 0000000000..a301b65dd4
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFTypeUnit.cpp
@@ -0,0 +1,53 @@
+//===- DWARFTypeUnit.cpp --------------------------------------------------===//
+//
+// 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/DWARF/DWARFTypeUnit.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnit.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cinttypes>
+
+using namespace llvm;
+
+void DWARFTypeUnit::dump(raw_ostream &OS, DIDumpOptions DumpOpts) {
+ DWARFDie TD = getDIEForOffset(getTypeOffset() + getOffset());
+ const char *Name = TD.getName(DINameKind::ShortName);
+ int OffsetDumpWidth = 2 * dwarf::getDwarfOffsetByteSize(getFormat());
+
+ if (DumpOpts.SummarizeTypes) {
+ OS << "name = '" << Name << "'"
+ << ", type_signature = " << format("0x%016" PRIx64, getTypeHash())
+ << ", length = " << format("0x%0*" PRIx64, OffsetDumpWidth, getLength())
+ << '\n';
+ return;
+ }
+
+ OS << format("0x%08" PRIx64, getOffset()) << ": Type Unit:"
+ << " length = " << format("0x%0*" PRIx64, OffsetDumpWidth, getLength())
+ << ", format = " << dwarf::FormatString(getFormat())
+ << ", version = " << format("0x%04x", getVersion());
+ if (getVersion() >= 5)
+ OS << ", unit_type = " << dwarf::UnitTypeString(getUnitType());
+ OS << ", abbr_offset = " << format("0x%04" PRIx64, getAbbrOffset());
+ if (!getAbbreviations())
+ OS << " (invalid)";
+ OS << ", addr_size = " << format("0x%02x", getAddressByteSize())
+ << ", name = '" << Name << "'"
+ << ", type_signature = " << format("0x%016" PRIx64, getTypeHash())
+ << ", type_offset = " << format("0x%04" PRIx64, getTypeOffset())
+ << " (next unit at " << format("0x%08" PRIx64, getNextUnitOffset())
+ << ")\n";
+
+ if (DWARFDie TU = getUnitDIE(false))
+ TU.dump(OS, 0, DumpOpts);
+ else
+ OS << "<type unit can't be parsed!>\n\n";
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFUnit.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFUnit.cpp
new file mode 100644
index 0000000000..eed0a60ec7
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFUnit.cpp
@@ -0,0 +1,1029 @@
+//===- DWARFUnit.cpp ------------------------------------------------------===//
+//
+// 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/DWARF/DWARFUnit.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/DWARF/DWARFAbbreviationDeclaration.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugAbbrev.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugInfoEntry.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugRnglists.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFTypeUnit.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/Path.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+#include <cstdio>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+
+void DWARFUnitVector::addUnitsForSection(DWARFContext &C,
+ const DWARFSection &Section,
+ DWARFSectionKind SectionKind) {
+ const DWARFObject &D = C.getDWARFObj();
+ addUnitsImpl(C, D, Section, C.getDebugAbbrev(), &D.getRangesSection(),
+ &D.getLocSection(), D.getStrSection(),
+ D.getStrOffsetsSection(), &D.getAddrSection(),
+ D.getLineSection(), D.isLittleEndian(), false, false,
+ SectionKind);
+}
+
+void DWARFUnitVector::addUnitsForDWOSection(DWARFContext &C,
+ const DWARFSection &DWOSection,
+ DWARFSectionKind SectionKind,
+ bool Lazy) {
+ const DWARFObject &D = C.getDWARFObj();
+ addUnitsImpl(C, D, DWOSection, C.getDebugAbbrevDWO(), &D.getRangesDWOSection(),
+ &D.getLocDWOSection(), D.getStrDWOSection(),
+ D.getStrOffsetsDWOSection(), &D.getAddrSection(),
+ D.getLineDWOSection(), C.isLittleEndian(), true, Lazy,
+ SectionKind);
+}
+
+void DWARFUnitVector::addUnitsImpl(
+ DWARFContext &Context, const DWARFObject &Obj, const DWARFSection &Section,
+ const DWARFDebugAbbrev *DA, const DWARFSection *RS,
+ const DWARFSection *LocSection, StringRef SS, const DWARFSection &SOS,
+ const DWARFSection *AOS, const DWARFSection &LS, bool LE, bool IsDWO,
+ bool Lazy, DWARFSectionKind SectionKind) {
+ DWARFDataExtractor Data(Obj, Section, LE, 0);
+ // Lazy initialization of Parser, now that we have all section info.
+ if (!Parser) {
+ Parser = [=, &Context, &Obj, &Section, &SOS,
+ &LS](uint64_t Offset, DWARFSectionKind SectionKind,
+ const DWARFSection *CurSection,
+ const DWARFUnitIndex::Entry *IndexEntry)
+ -> std::unique_ptr<DWARFUnit> {
+ const DWARFSection &InfoSection = CurSection ? *CurSection : Section;
+ DWARFDataExtractor Data(Obj, InfoSection, LE, 0);
+ if (!Data.isValidOffset(Offset))
+ return nullptr;
+ DWARFUnitHeader Header;
+ if (!Header.extract(Context, Data, &Offset, SectionKind))
+ return nullptr;
+ if (!IndexEntry && IsDWO) {
+ const DWARFUnitIndex &Index = getDWARFUnitIndex(
+ Context, Header.isTypeUnit() ? DW_SECT_EXT_TYPES : DW_SECT_INFO);
+ IndexEntry = Index.getFromOffset(Header.getOffset());
+ }
+ if (IndexEntry && !Header.applyIndexEntry(IndexEntry))
+ return nullptr;
+ std::unique_ptr<DWARFUnit> U;
+ if (Header.isTypeUnit())
+ U = std::make_unique<DWARFTypeUnit>(Context, InfoSection, Header, DA,
+ RS, LocSection, SS, SOS, AOS, LS,
+ LE, IsDWO, *this);
+ else
+ U = std::make_unique<DWARFCompileUnit>(Context, InfoSection, Header,
+ DA, RS, LocSection, SS, SOS,
+ AOS, LS, LE, IsDWO, *this);
+ return U;
+ };
+ }
+ if (Lazy)
+ return;
+ // Find a reasonable insertion point within the vector. We skip over
+ // (a) units from a different section, (b) units from the same section
+ // but with lower offset-within-section. This keeps units in order
+ // within a section, although not necessarily within the object file,
+ // even if we do lazy parsing.
+ auto I = this->begin();
+ uint64_t Offset = 0;
+ while (Data.isValidOffset(Offset)) {
+ if (I != this->end() &&
+ (&(*I)->getInfoSection() != &Section || (*I)->getOffset() == Offset)) {
+ ++I;
+ continue;
+ }
+ auto U = Parser(Offset, SectionKind, &Section, nullptr);
+ // If parsing failed, we're done with this section.
+ if (!U)
+ break;
+ Offset = U->getNextUnitOffset();
+ I = std::next(this->insert(I, std::move(U)));
+ }
+}
+
+DWARFUnit *DWARFUnitVector::addUnit(std::unique_ptr<DWARFUnit> Unit) {
+ auto I = std::upper_bound(begin(), end(), Unit,
+ [](const std::unique_ptr<DWARFUnit> &LHS,
+ const std::unique_ptr<DWARFUnit> &RHS) {
+ return LHS->getOffset() < RHS->getOffset();
+ });
+ return this->insert(I, std::move(Unit))->get();
+}
+
+DWARFUnit *DWARFUnitVector::getUnitForOffset(uint64_t Offset) const {
+ auto end = begin() + getNumInfoUnits();
+ auto *CU =
+ std::upper_bound(begin(), end, Offset,
+ [](uint64_t LHS, const std::unique_ptr<DWARFUnit> &RHS) {
+ return LHS < RHS->getNextUnitOffset();
+ });
+ if (CU != end && (*CU)->getOffset() <= Offset)
+ return CU->get();
+ return nullptr;
+}
+
+DWARFUnit *
+DWARFUnitVector::getUnitForIndexEntry(const DWARFUnitIndex::Entry &E) {
+ const auto *CUOff = E.getContribution(DW_SECT_INFO);
+ if (!CUOff)
+ return nullptr;
+
+ auto Offset = CUOff->Offset;
+ auto end = begin() + getNumInfoUnits();
+
+ auto *CU =
+ std::upper_bound(begin(), end, CUOff->Offset,
+ [](uint64_t LHS, const std::unique_ptr<DWARFUnit> &RHS) {
+ return LHS < RHS->getNextUnitOffset();
+ });
+ if (CU != end && (*CU)->getOffset() <= Offset)
+ return CU->get();
+
+ if (!Parser)
+ return nullptr;
+
+ auto U = Parser(Offset, DW_SECT_INFO, nullptr, &E);
+ if (!U)
+ U = nullptr;
+
+ auto *NewCU = U.get();
+ this->insert(CU, std::move(U));
+ ++NumInfoUnits;
+ return NewCU;
+}
+
+DWARFUnit::DWARFUnit(DWARFContext &DC, const DWARFSection &Section,
+ const DWARFUnitHeader &Header, const DWARFDebugAbbrev *DA,
+ const DWARFSection *RS, const DWARFSection *LocSection,
+ StringRef SS, const DWARFSection &SOS,
+ const DWARFSection *AOS, const DWARFSection &LS, bool LE,
+ bool IsDWO, const DWARFUnitVector &UnitVector)
+ : Context(DC), InfoSection(Section), Header(Header), Abbrev(DA),
+ RangeSection(RS), LineSection(LS), StringSection(SS),
+ StringOffsetSection(SOS), AddrOffsetSection(AOS), isLittleEndian(LE),
+ IsDWO(IsDWO), UnitVector(UnitVector) {
+ clear();
+}
+
+DWARFUnit::~DWARFUnit() = default;
+
+DWARFDataExtractor DWARFUnit::getDebugInfoExtractor() const {
+ return DWARFDataExtractor(Context.getDWARFObj(), InfoSection, isLittleEndian,
+ getAddressByteSize());
+}
+
+Optional<object::SectionedAddress>
+DWARFUnit::getAddrOffsetSectionItem(uint32_t Index) const {
+ if (!AddrOffsetSectionBase) {
+ auto R = Context.info_section_units();
+ // Surprising if a DWO file has more than one skeleton unit in it - this
+ // probably shouldn't be valid, but if a use case is found, here's where to
+ // support it (probably have to linearly search for the matching skeleton CU
+ // here)
+ if (IsDWO && hasSingleElement(R))
+ return (*R.begin())->getAddrOffsetSectionItem(Index);
+
+ return None;
+ }
+
+ uint64_t Offset = *AddrOffsetSectionBase + Index * getAddressByteSize();
+ if (AddrOffsetSection->Data.size() < Offset + getAddressByteSize())
+ return None;
+ DWARFDataExtractor DA(Context.getDWARFObj(), *AddrOffsetSection,
+ isLittleEndian, getAddressByteSize());
+ uint64_t Section;
+ uint64_t Address = DA.getRelocatedAddress(&Offset, &Section);
+ return {{Address, Section}};
+}
+
+Expected<uint64_t> DWARFUnit::getStringOffsetSectionItem(uint32_t Index) const {
+ if (!StringOffsetsTableContribution)
+ return make_error<StringError>(
+ "DW_FORM_strx used without a valid string offsets table",
+ inconvertibleErrorCode());
+ unsigned ItemSize = getDwarfStringOffsetsByteSize();
+ uint64_t Offset = getStringOffsetsBase() + Index * ItemSize;
+ if (StringOffsetSection.Data.size() < Offset + ItemSize)
+ return make_error<StringError>("DW_FORM_strx uses index " + Twine(Index) +
+ ", which is too large",
+ inconvertibleErrorCode());
+ DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection,
+ isLittleEndian, 0);
+ return DA.getRelocatedValue(ItemSize, &Offset);
+}
+
+bool DWARFUnitHeader::extract(DWARFContext &Context,
+ const DWARFDataExtractor &debug_info,
+ uint64_t *offset_ptr,
+ DWARFSectionKind SectionKind) {
+ Offset = *offset_ptr;
+ Error Err = Error::success();
+ IndexEntry = nullptr;
+ std::tie(Length, FormParams.Format) =
+ debug_info.getInitialLength(offset_ptr, &Err);
+ FormParams.Version = debug_info.getU16(offset_ptr, &Err);
+ if (FormParams.Version >= 5) {
+ UnitType = debug_info.getU8(offset_ptr, &Err);
+ FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err);
+ AbbrOffset = debug_info.getRelocatedValue(
+ FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err);
+ } else {
+ AbbrOffset = debug_info.getRelocatedValue(
+ FormParams.getDwarfOffsetByteSize(), offset_ptr, nullptr, &Err);
+ FormParams.AddrSize = debug_info.getU8(offset_ptr, &Err);
+ // Fake a unit type based on the section type. This isn't perfect,
+ // but distinguishing compile and type units is generally enough.
+ if (SectionKind == DW_SECT_EXT_TYPES)
+ UnitType = DW_UT_type;
+ else
+ UnitType = DW_UT_compile;
+ }
+ if (isTypeUnit()) {
+ TypeHash = debug_info.getU64(offset_ptr, &Err);
+ TypeOffset = debug_info.getUnsigned(
+ offset_ptr, FormParams.getDwarfOffsetByteSize(), &Err);
+ } else if (UnitType == DW_UT_split_compile || UnitType == DW_UT_skeleton)
+ DWOId = debug_info.getU64(offset_ptr, &Err);
+
+ if (Err) {
+ Context.getWarningHandler()(joinErrors(
+ createStringError(
+ errc::invalid_argument,
+ "DWARF unit at 0x%8.8" PRIx64 " cannot be parsed:", Offset),
+ std::move(Err)));
+ return false;
+ }
+
+ // Header fields all parsed, capture the size of this unit header.
+ assert(*offset_ptr - Offset <= 255 && "unexpected header size");
+ Size = uint8_t(*offset_ptr - Offset);
+ uint64_t NextCUOffset = Offset + getUnitLengthFieldByteSize() + getLength();
+
+ if (!debug_info.isValidOffset(getNextUnitOffset() - 1)) {
+ Context.getWarningHandler()(
+ createStringError(errc::invalid_argument,
+ "DWARF unit from offset 0x%8.8" PRIx64 " incl. "
+ "to offset 0x%8.8" PRIx64 " excl. "
+ "extends past section size 0x%8.8zx",
+ Offset, NextCUOffset, debug_info.size()));
+ return false;
+ }
+
+ if (!DWARFContext::isSupportedVersion(getVersion())) {
+ Context.getWarningHandler()(createStringError(
+ errc::invalid_argument,
+ "DWARF unit at offset 0x%8.8" PRIx64 " "
+ "has unsupported version %" PRIu16 ", supported are 2-%u",
+ Offset, getVersion(), DWARFContext::getMaxSupportedVersion()));
+ return false;
+ }
+
+ // Type offset is unit-relative; should be after the header and before
+ // the end of the current unit.
+ if (isTypeUnit() && TypeOffset < Size) {
+ Context.getWarningHandler()(
+ createStringError(errc::invalid_argument,
+ "DWARF type unit at offset "
+ "0x%8.8" PRIx64 " "
+ "has its relocated type_offset 0x%8.8" PRIx64 " "
+ "pointing inside the header",
+ Offset, Offset + TypeOffset));
+ return false;
+ }
+ if (isTypeUnit() &&
+ TypeOffset >= getUnitLengthFieldByteSize() + getLength()) {
+ Context.getWarningHandler()(createStringError(
+ errc::invalid_argument,
+ "DWARF type unit from offset 0x%8.8" PRIx64 " incl. "
+ "to offset 0x%8.8" PRIx64 " excl. has its "
+ "relocated type_offset 0x%8.8" PRIx64 " pointing past the unit end",
+ Offset, NextCUOffset, Offset + TypeOffset));
+ return false;
+ }
+
+ if (Error SizeErr = DWARFContext::checkAddressSizeSupported(
+ getAddressByteSize(), errc::invalid_argument,
+ "DWARF unit at offset 0x%8.8" PRIx64, Offset)) {
+ Context.getWarningHandler()(std::move(SizeErr));
+ return false;
+ }
+
+ // Keep track of the highest DWARF version we encounter across all units.
+ Context.setMaxVersionIfGreater(getVersion());
+ return true;
+}
+
+bool DWARFUnitHeader::applyIndexEntry(const DWARFUnitIndex::Entry *Entry) {
+ assert(Entry);
+ assert(!IndexEntry);
+ IndexEntry = Entry;
+ if (AbbrOffset)
+ return false;
+ auto *UnitContrib = IndexEntry->getContribution();
+ if (!UnitContrib ||
+ UnitContrib->Length != (getLength() + getUnitLengthFieldByteSize()))
+ return false;
+ auto *AbbrEntry = IndexEntry->getContribution(DW_SECT_ABBREV);
+ if (!AbbrEntry)
+ return false;
+ AbbrOffset = AbbrEntry->Offset;
+ return true;
+}
+
+Error DWARFUnit::extractRangeList(uint64_t RangeListOffset,
+ DWARFDebugRangeList &RangeList) const {
+ // Require that compile unit is extracted.
+ assert(!DieArray.empty());
+ DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
+ isLittleEndian, getAddressByteSize());
+ uint64_t ActualRangeListOffset = RangeSectionBase + RangeListOffset;
+ return RangeList.extract(RangesData, &ActualRangeListOffset);
+}
+
+void DWARFUnit::clear() {
+ Abbrevs = nullptr;
+ BaseAddr.reset();
+ RangeSectionBase = 0;
+ LocSectionBase = 0;
+ AddrOffsetSectionBase = None;
+ SU = nullptr;
+ clearDIEs(false);
+ DWO.reset();
+}
+
+const char *DWARFUnit::getCompilationDir() {
+ return dwarf::toString(getUnitDIE().find(DW_AT_comp_dir), nullptr);
+}
+
+void DWARFUnit::extractDIEsToVector(
+ bool AppendCUDie, bool AppendNonCUDies,
+ std::vector<DWARFDebugInfoEntry> &Dies) const {
+ if (!AppendCUDie && !AppendNonCUDies)
+ return;
+
+ // Set the offset to that of the first DIE and calculate the start of the
+ // next compilation unit header.
+ uint64_t DIEOffset = getOffset() + getHeaderSize();
+ uint64_t NextCUOffset = getNextUnitOffset();
+ DWARFDebugInfoEntry DIE;
+ DWARFDataExtractor DebugInfoData = getDebugInfoExtractor();
+ // The end offset has been already checked by DWARFUnitHeader::extract.
+ assert(DebugInfoData.isValidOffset(NextCUOffset - 1));
+ std::vector<uint32_t> Parents;
+ std::vector<uint32_t> PrevSiblings;
+ bool IsCUDie = true;
+
+ assert(
+ ((AppendCUDie && Dies.empty()) || (!AppendCUDie && Dies.size() == 1)) &&
+ "Dies array is not empty");
+
+ // Fill Parents and Siblings stacks with initial value.
+ Parents.push_back(UINT32_MAX);
+ if (!AppendCUDie)
+ Parents.push_back(0);
+ PrevSiblings.push_back(0);
+
+ // Start to extract dies.
+ do {
+ assert(Parents.size() > 0 && "Empty parents stack");
+ assert((Parents.back() == UINT32_MAX || Parents.back() <= Dies.size()) &&
+ "Wrong parent index");
+
+ // Extract die. Stop if any error occured.
+ if (!DIE.extractFast(*this, &DIEOffset, DebugInfoData, NextCUOffset,
+ Parents.back()))
+ break;
+
+ // If previous sibling is remembered then update it`s SiblingIdx field.
+ if (PrevSiblings.back() > 0) {
+ assert(PrevSiblings.back() < Dies.size() &&
+ "Previous sibling index is out of Dies boundaries");
+ Dies[PrevSiblings.back()].setSiblingIdx(Dies.size());
+ }
+
+ // Store die into the Dies vector.
+ if (IsCUDie) {
+ if (AppendCUDie)
+ Dies.push_back(DIE);
+ if (!AppendNonCUDies)
+ break;
+ // The average bytes per DIE entry has been seen to be
+ // around 14-20 so let's pre-reserve the needed memory for
+ // our DIE entries accordingly.
+ Dies.reserve(Dies.size() + getDebugInfoSize() / 14);
+ } else {
+ // Remember last previous sibling.
+ PrevSiblings.back() = Dies.size();
+
+ Dies.push_back(DIE);
+ }
+
+ // Check for new children scope.
+ if (const DWARFAbbreviationDeclaration *AbbrDecl =
+ DIE.getAbbreviationDeclarationPtr()) {
+ if (AbbrDecl->hasChildren()) {
+ if (AppendCUDie || !IsCUDie) {
+ assert(Dies.size() > 0 && "Dies does not contain any die");
+ Parents.push_back(Dies.size() - 1);
+ PrevSiblings.push_back(0);
+ }
+ } else if (IsCUDie)
+ // Stop if we have single compile unit die w/o children.
+ break;
+ } else {
+ // NULL DIE: finishes current children scope.
+ Parents.pop_back();
+ PrevSiblings.pop_back();
+ }
+
+ if (IsCUDie)
+ IsCUDie = false;
+
+ // Stop when compile unit die is removed from the parents stack.
+ } while (Parents.size() > 1);
+}
+
+void DWARFUnit::extractDIEsIfNeeded(bool CUDieOnly) {
+ if (Error e = tryExtractDIEsIfNeeded(CUDieOnly))
+ Context.getRecoverableErrorHandler()(std::move(e));
+}
+
+Error DWARFUnit::tryExtractDIEsIfNeeded(bool CUDieOnly) {
+ if ((CUDieOnly && !DieArray.empty()) ||
+ DieArray.size() > 1)
+ return Error::success(); // Already parsed.
+
+ bool HasCUDie = !DieArray.empty();
+ extractDIEsToVector(!HasCUDie, !CUDieOnly, DieArray);
+
+ if (DieArray.empty())
+ return Error::success();
+
+ // If CU DIE was just parsed, copy several attribute values from it.
+ if (HasCUDie)
+ return Error::success();
+
+ DWARFDie UnitDie(this, &DieArray[0]);
+ if (Optional<uint64_t> DWOId = toUnsigned(UnitDie.find(DW_AT_GNU_dwo_id)))
+ Header.setDWOId(*DWOId);
+ if (!IsDWO) {
+ assert(AddrOffsetSectionBase == None);
+ assert(RangeSectionBase == 0);
+ assert(LocSectionBase == 0);
+ AddrOffsetSectionBase = toSectionOffset(UnitDie.find(DW_AT_addr_base));
+ if (!AddrOffsetSectionBase)
+ AddrOffsetSectionBase =
+ toSectionOffset(UnitDie.find(DW_AT_GNU_addr_base));
+ RangeSectionBase = toSectionOffset(UnitDie.find(DW_AT_rnglists_base), 0);
+ LocSectionBase = toSectionOffset(UnitDie.find(DW_AT_loclists_base), 0);
+ }
+
+ // In general, in DWARF v5 and beyond we derive the start of the unit's
+ // contribution to the string offsets table from the unit DIE's
+ // DW_AT_str_offsets_base attribute. Split DWARF units do not use this
+ // attribute, so we assume that there is a contribution to the string
+ // offsets table starting at offset 0 of the debug_str_offsets.dwo section.
+ // In both cases we need to determine the format of the contribution,
+ // which may differ from the unit's format.
+ DWARFDataExtractor DA(Context.getDWARFObj(), StringOffsetSection,
+ isLittleEndian, 0);
+ if (IsDWO || getVersion() >= 5) {
+ auto StringOffsetOrError =
+ IsDWO ? determineStringOffsetsTableContributionDWO(DA)
+ : determineStringOffsetsTableContribution(DA);
+ if (!StringOffsetOrError)
+ return createStringError(errc::invalid_argument,
+ "invalid reference to or invalid content in "
+ ".debug_str_offsets[.dwo]: " +
+ toString(StringOffsetOrError.takeError()));
+
+ StringOffsetsTableContribution = *StringOffsetOrError;
+ }
+
+ // DWARF v5 uses the .debug_rnglists and .debug_rnglists.dwo sections to
+ // describe address ranges.
+ if (getVersion() >= 5) {
+ // In case of DWP, the base offset from the index has to be added.
+ if (IsDWO) {
+ uint64_t ContributionBaseOffset = 0;
+ if (auto *IndexEntry = Header.getIndexEntry())
+ if (auto *Contrib = IndexEntry->getContribution(DW_SECT_RNGLISTS))
+ ContributionBaseOffset = Contrib->Offset;
+ setRangesSection(
+ &Context.getDWARFObj().getRnglistsDWOSection(),
+ ContributionBaseOffset +
+ DWARFListTableHeader::getHeaderSize(Header.getFormat()));
+ } else
+ setRangesSection(&Context.getDWARFObj().getRnglistsSection(),
+ toSectionOffset(UnitDie.find(DW_AT_rnglists_base),
+ DWARFListTableHeader::getHeaderSize(
+ Header.getFormat())));
+ }
+
+ if (IsDWO) {
+ // If we are reading a package file, we need to adjust the location list
+ // data based on the index entries.
+ StringRef Data = Header.getVersion() >= 5
+ ? Context.getDWARFObj().getLoclistsDWOSection().Data
+ : Context.getDWARFObj().getLocDWOSection().Data;
+ if (auto *IndexEntry = Header.getIndexEntry())
+ if (const auto *C = IndexEntry->getContribution(
+ Header.getVersion() >= 5 ? DW_SECT_LOCLISTS : DW_SECT_EXT_LOC))
+ Data = Data.substr(C->Offset, C->Length);
+
+ DWARFDataExtractor DWARFData(Data, isLittleEndian, getAddressByteSize());
+ LocTable =
+ std::make_unique<DWARFDebugLoclists>(DWARFData, Header.getVersion());
+ LocSectionBase = DWARFListTableHeader::getHeaderSize(Header.getFormat());
+ } else if (getVersion() >= 5) {
+ LocTable = std::make_unique<DWARFDebugLoclists>(
+ DWARFDataExtractor(Context.getDWARFObj(),
+ Context.getDWARFObj().getLoclistsSection(),
+ isLittleEndian, getAddressByteSize()),
+ getVersion());
+ } else {
+ LocTable = std::make_unique<DWARFDebugLoc>(DWARFDataExtractor(
+ Context.getDWARFObj(), Context.getDWARFObj().getLocSection(),
+ isLittleEndian, getAddressByteSize()));
+ }
+
+ // Don't fall back to DW_AT_GNU_ranges_base: it should be ignored for
+ // skeleton CU DIE, so that DWARF users not aware of it are not broken.
+ return Error::success();
+}
+
+bool DWARFUnit::parseDWO() {
+ if (IsDWO)
+ return false;
+ if (DWO.get())
+ return false;
+ DWARFDie UnitDie = getUnitDIE();
+ if (!UnitDie)
+ return false;
+ auto DWOFileName = getVersion() >= 5
+ ? dwarf::toString(UnitDie.find(DW_AT_dwo_name))
+ : dwarf::toString(UnitDie.find(DW_AT_GNU_dwo_name));
+ if (!DWOFileName)
+ return false;
+ auto CompilationDir = dwarf::toString(UnitDie.find(DW_AT_comp_dir));
+ SmallString<16> AbsolutePath;
+ if (sys::path::is_relative(*DWOFileName) && CompilationDir &&
+ *CompilationDir) {
+ sys::path::append(AbsolutePath, *CompilationDir);
+ }
+ sys::path::append(AbsolutePath, *DWOFileName);
+ auto DWOId = getDWOId();
+ if (!DWOId)
+ return false;
+ auto DWOContext = Context.getDWOContext(AbsolutePath);
+ if (!DWOContext)
+ return false;
+
+ DWARFCompileUnit *DWOCU = DWOContext->getDWOCompileUnitForHash(*DWOId);
+ if (!DWOCU)
+ return false;
+ DWO = std::shared_ptr<DWARFCompileUnit>(std::move(DWOContext), DWOCU);
+ DWO->setSkeletonUnit(this);
+ // Share .debug_addr and .debug_ranges section with compile unit in .dwo
+ if (AddrOffsetSectionBase)
+ DWO->setAddrOffsetSection(AddrOffsetSection, *AddrOffsetSectionBase);
+ if (getVersion() == 4) {
+ auto DWORangesBase = UnitDie.getRangesBaseAttribute();
+ DWO->setRangesSection(RangeSection, DWORangesBase.getValueOr(0));
+ }
+
+ return true;
+}
+
+void DWARFUnit::clearDIEs(bool KeepCUDie) {
+ // Do not use resize() + shrink_to_fit() to free memory occupied by dies.
+ // shrink_to_fit() is a *non-binding* request to reduce capacity() to size().
+ // It depends on the implementation whether the request is fulfilled.
+ // Create a new vector with a small capacity and assign it to the DieArray to
+ // have previous contents freed.
+ DieArray = (KeepCUDie && !DieArray.empty())
+ ? std::vector<DWARFDebugInfoEntry>({DieArray[0]})
+ : std::vector<DWARFDebugInfoEntry>();
+}
+
+Expected<DWARFAddressRangesVector>
+DWARFUnit::findRnglistFromOffset(uint64_t Offset) {
+ if (getVersion() <= 4) {
+ DWARFDebugRangeList RangeList;
+ if (Error E = extractRangeList(Offset, RangeList))
+ return std::move(E);
+ return RangeList.getAbsoluteRanges(getBaseAddress());
+ }
+ DWARFDataExtractor RangesData(Context.getDWARFObj(), *RangeSection,
+ isLittleEndian, Header.getAddressByteSize());
+ DWARFDebugRnglistTable RnglistTable;
+ auto RangeListOrError = RnglistTable.findList(RangesData, Offset);
+ if (RangeListOrError)
+ return RangeListOrError.get().getAbsoluteRanges(getBaseAddress(), *this);
+ return RangeListOrError.takeError();
+}
+
+Expected<DWARFAddressRangesVector>
+DWARFUnit::findRnglistFromIndex(uint32_t Index) {
+ if (auto Offset = getRnglistOffset(Index))
+ return findRnglistFromOffset(*Offset);
+
+ return createStringError(errc::invalid_argument,
+ "invalid range list table index %d (possibly "
+ "missing the entire range list table)",
+ Index);
+}
+
+Expected<DWARFAddressRangesVector> DWARFUnit::collectAddressRanges() {
+ DWARFDie UnitDie = getUnitDIE();
+ if (!UnitDie)
+ return createStringError(errc::invalid_argument, "No unit DIE");
+
+ // First, check if unit DIE describes address ranges for the whole unit.
+ auto CUDIERangesOrError = UnitDie.getAddressRanges();
+ if (!CUDIERangesOrError)
+ return createStringError(errc::invalid_argument,
+ "decoding address ranges: %s",
+ toString(CUDIERangesOrError.takeError()).c_str());
+ return *CUDIERangesOrError;
+}
+
+Expected<DWARFLocationExpressionsVector>
+DWARFUnit::findLoclistFromOffset(uint64_t Offset) {
+ DWARFLocationExpressionsVector Result;
+
+ Error InterpretationError = Error::success();
+
+ Error ParseError = getLocationTable().visitAbsoluteLocationList(
+ Offset, getBaseAddress(),
+ [this](uint32_t Index) { return getAddrOffsetSectionItem(Index); },
+ [&](Expected<DWARFLocationExpression> L) {
+ if (L)
+ Result.push_back(std::move(*L));
+ else
+ InterpretationError =
+ joinErrors(L.takeError(), std::move(InterpretationError));
+ return !InterpretationError;
+ });
+
+ if (ParseError || InterpretationError)
+ return joinErrors(std::move(ParseError), std::move(InterpretationError));
+
+ return Result;
+}
+
+void DWARFUnit::updateAddressDieMap(DWARFDie Die) {
+ if (Die.isSubroutineDIE()) {
+ auto DIERangesOrError = Die.getAddressRanges();
+ if (DIERangesOrError) {
+ for (const auto &R : DIERangesOrError.get()) {
+ // Ignore 0-sized ranges.
+ if (R.LowPC == R.HighPC)
+ continue;
+ auto B = AddrDieMap.upper_bound(R.LowPC);
+ if (B != AddrDieMap.begin() && R.LowPC < (--B)->second.first) {
+ // The range is a sub-range of existing ranges, we need to split the
+ // existing range.
+ if (R.HighPC < B->second.first)
+ AddrDieMap[R.HighPC] = B->second;
+ if (R.LowPC > B->first)
+ AddrDieMap[B->first].first = R.LowPC;
+ }
+ AddrDieMap[R.LowPC] = std::make_pair(R.HighPC, Die);
+ }
+ } else
+ llvm::consumeError(DIERangesOrError.takeError());
+ }
+ // Parent DIEs are added to the AddrDieMap prior to the Children DIEs to
+ // simplify the logic to update AddrDieMap. The child's range will always
+ // be equal or smaller than the parent's range. With this assumption, when
+ // adding one range into the map, it will at most split a range into 3
+ // sub-ranges.
+ for (DWARFDie Child = Die.getFirstChild(); Child; Child = Child.getSibling())
+ updateAddressDieMap(Child);
+}
+
+DWARFDie DWARFUnit::getSubroutineForAddress(uint64_t Address) {
+ extractDIEsIfNeeded(false);
+ if (AddrDieMap.empty())
+ updateAddressDieMap(getUnitDIE());
+ auto R = AddrDieMap.upper_bound(Address);
+ if (R == AddrDieMap.begin())
+ return DWARFDie();
+ // upper_bound's previous item contains Address.
+ --R;
+ if (Address >= R->second.first)
+ return DWARFDie();
+ return R->second.second;
+}
+
+void
+DWARFUnit::getInlinedChainForAddress(uint64_t Address,
+ SmallVectorImpl<DWARFDie> &InlinedChain) {
+ assert(InlinedChain.empty());
+ // Try to look for subprogram DIEs in the DWO file.
+ parseDWO();
+ // First, find the subroutine that contains the given address (the leaf
+ // of inlined chain).
+ DWARFDie SubroutineDIE =
+ (DWO ? *DWO : *this).getSubroutineForAddress(Address);
+
+ while (SubroutineDIE) {
+ if (SubroutineDIE.isSubprogramDIE()) {
+ InlinedChain.push_back(SubroutineDIE);
+ return;
+ }
+ if (SubroutineDIE.getTag() == DW_TAG_inlined_subroutine)
+ InlinedChain.push_back(SubroutineDIE);
+ SubroutineDIE = SubroutineDIE.getParent();
+ }
+}
+
+const DWARFUnitIndex &llvm::getDWARFUnitIndex(DWARFContext &Context,
+ DWARFSectionKind Kind) {
+ if (Kind == DW_SECT_INFO)
+ return Context.getCUIndex();
+ assert(Kind == DW_SECT_EXT_TYPES);
+ return Context.getTUIndex();
+}
+
+DWARFDie DWARFUnit::getParent(const DWARFDebugInfoEntry *Die) {
+ if (!Die)
+ return DWARFDie();
+
+ if (Optional<uint32_t> ParentIdx = Die->getParentIdx()) {
+ assert(*ParentIdx < DieArray.size() &&
+ "ParentIdx is out of DieArray boundaries");
+ return DWARFDie(this, &DieArray[*ParentIdx]);
+ }
+
+ return DWARFDie();
+}
+
+DWARFDie DWARFUnit::getSibling(const DWARFDebugInfoEntry *Die) {
+ if (!Die)
+ return DWARFDie();
+
+ if (Optional<uint32_t> SiblingIdx = Die->getSiblingIdx()) {
+ assert(*SiblingIdx < DieArray.size() &&
+ "SiblingIdx is out of DieArray boundaries");
+ return DWARFDie(this, &DieArray[*SiblingIdx]);
+ }
+
+ return DWARFDie();
+}
+
+DWARFDie DWARFUnit::getPreviousSibling(const DWARFDebugInfoEntry *Die) {
+ if (!Die)
+ return DWARFDie();
+
+ Optional<uint32_t> ParentIdx = Die->getParentIdx();
+ if (!ParentIdx)
+ // Die is a root die, there is no previous sibling.
+ return DWARFDie();
+
+ assert(*ParentIdx < DieArray.size() &&
+ "ParentIdx is out of DieArray boundaries");
+ assert(getDIEIndex(Die) > 0 && "Die is a root die");
+
+ uint32_t PrevDieIdx = getDIEIndex(Die) - 1;
+ if (PrevDieIdx == *ParentIdx)
+ // Immediately previous node is parent, there is no previous sibling.
+ return DWARFDie();
+
+ while (DieArray[PrevDieIdx].getParentIdx() != *ParentIdx) {
+ PrevDieIdx = *DieArray[PrevDieIdx].getParentIdx();
+
+ assert(PrevDieIdx < DieArray.size() &&
+ "PrevDieIdx is out of DieArray boundaries");
+ assert(PrevDieIdx >= *ParentIdx &&
+ "PrevDieIdx is not a child of parent of Die");
+ }
+
+ return DWARFDie(this, &DieArray[PrevDieIdx]);
+}
+
+DWARFDie DWARFUnit::getFirstChild(const DWARFDebugInfoEntry *Die) {
+ if (!Die->hasChildren())
+ return DWARFDie();
+
+ // TODO: Instead of checking here for invalid die we might reject
+ // invalid dies at parsing stage(DWARFUnit::extractDIEsToVector).
+ // We do not want access out of bounds when parsing corrupted debug data.
+ size_t I = getDIEIndex(Die) + 1;
+ if (I >= DieArray.size())
+ return DWARFDie();
+ return DWARFDie(this, &DieArray[I]);
+}
+
+DWARFDie DWARFUnit::getLastChild(const DWARFDebugInfoEntry *Die) {
+ if (!Die->hasChildren())
+ return DWARFDie();
+
+ if (Optional<uint32_t> SiblingIdx = Die->getSiblingIdx()) {
+ assert(*SiblingIdx < DieArray.size() &&
+ "SiblingIdx is out of DieArray boundaries");
+ assert(DieArray[*SiblingIdx - 1].getTag() == dwarf::DW_TAG_null &&
+ "Bad end of children marker");
+ return DWARFDie(this, &DieArray[*SiblingIdx - 1]);
+ }
+
+ // If SiblingIdx is set for non-root dies we could be sure that DWARF is
+ // correct and "end of children marker" must be found. For root die we do not
+ // have such a guarantee(parsing root die might be stopped if "end of children
+ // marker" is missing, SiblingIdx is always zero for root die). That is why we
+ // do not use assertion for checking for "end of children marker" for root
+ // die.
+
+ // TODO: Instead of checking here for invalid die we might reject
+ // invalid dies at parsing stage(DWARFUnit::extractDIEsToVector).
+ if (getDIEIndex(Die) == 0 && DieArray.size() > 1 &&
+ DieArray.back().getTag() == dwarf::DW_TAG_null) {
+ // For the unit die we might take last item from DieArray.
+ assert(getDIEIndex(Die) == getDIEIndex(getUnitDIE()) && "Bad unit die");
+ return DWARFDie(this, &DieArray.back());
+ }
+
+ return DWARFDie();
+}
+
+const DWARFAbbreviationDeclarationSet *DWARFUnit::getAbbreviations() const {
+ if (!Abbrevs)
+ Abbrevs = Abbrev->getAbbreviationDeclarationSet(getAbbreviationsOffset());
+ return Abbrevs;
+}
+
+llvm::Optional<object::SectionedAddress> DWARFUnit::getBaseAddress() {
+ if (BaseAddr)
+ return BaseAddr;
+
+ DWARFDie UnitDie = getUnitDIE();
+ Optional<DWARFFormValue> PC = UnitDie.find({DW_AT_low_pc, DW_AT_entry_pc});
+ BaseAddr = toSectionedAddress(PC);
+ return BaseAddr;
+}
+
+Expected<StrOffsetsContributionDescriptor>
+StrOffsetsContributionDescriptor::validateContributionSize(
+ DWARFDataExtractor &DA) {
+ uint8_t EntrySize = getDwarfOffsetByteSize();
+ // In order to ensure that we don't read a partial record at the end of
+ // the section we validate for a multiple of the entry size.
+ uint64_t ValidationSize = alignTo(Size, EntrySize);
+ // Guard against overflow.
+ if (ValidationSize >= Size)
+ if (DA.isValidOffsetForDataOfSize((uint32_t)Base, ValidationSize))
+ return *this;
+ return createStringError(errc::invalid_argument, "length exceeds section size");
+}
+
+// Look for a DWARF64-formatted contribution to the string offsets table
+// starting at a given offset and record it in a descriptor.
+static Expected<StrOffsetsContributionDescriptor>
+parseDWARF64StringOffsetsTableHeader(DWARFDataExtractor &DA, uint64_t Offset) {
+ if (!DA.isValidOffsetForDataOfSize(Offset, 16))
+ return createStringError(errc::invalid_argument, "section offset exceeds section size");
+
+ if (DA.getU32(&Offset) != dwarf::DW_LENGTH_DWARF64)
+ return createStringError(errc::invalid_argument, "32 bit contribution referenced from a 64 bit unit");
+
+ uint64_t Size = DA.getU64(&Offset);
+ uint8_t Version = DA.getU16(&Offset);
+ (void)DA.getU16(&Offset); // padding
+ // The encoded length includes the 2-byte version field and the 2-byte
+ // padding, so we need to subtract them out when we populate the descriptor.
+ return StrOffsetsContributionDescriptor(Offset, Size - 4, Version, DWARF64);
+}
+
+// Look for a DWARF32-formatted contribution to the string offsets table
+// starting at a given offset and record it in a descriptor.
+static Expected<StrOffsetsContributionDescriptor>
+parseDWARF32StringOffsetsTableHeader(DWARFDataExtractor &DA, uint64_t Offset) {
+ if (!DA.isValidOffsetForDataOfSize(Offset, 8))
+ return createStringError(errc::invalid_argument, "section offset exceeds section size");
+
+ uint32_t ContributionSize = DA.getU32(&Offset);
+ if (ContributionSize >= dwarf::DW_LENGTH_lo_reserved)
+ return createStringError(errc::invalid_argument, "invalid length");
+
+ uint8_t Version = DA.getU16(&Offset);
+ (void)DA.getU16(&Offset); // padding
+ // The encoded length includes the 2-byte version field and the 2-byte
+ // padding, so we need to subtract them out when we populate the descriptor.
+ return StrOffsetsContributionDescriptor(Offset, ContributionSize - 4, Version,
+ DWARF32);
+}
+
+static Expected<StrOffsetsContributionDescriptor>
+parseDWARFStringOffsetsTableHeader(DWARFDataExtractor &DA,
+ llvm::dwarf::DwarfFormat Format,
+ uint64_t Offset) {
+ StrOffsetsContributionDescriptor Desc;
+ switch (Format) {
+ case dwarf::DwarfFormat::DWARF64: {
+ if (Offset < 16)
+ return createStringError(errc::invalid_argument, "insufficient space for 64 bit header prefix");
+ auto DescOrError = parseDWARF64StringOffsetsTableHeader(DA, Offset - 16);
+ if (!DescOrError)
+ return DescOrError.takeError();
+ Desc = *DescOrError;
+ break;
+ }
+ case dwarf::DwarfFormat::DWARF32: {
+ if (Offset < 8)
+ return createStringError(errc::invalid_argument, "insufficient space for 32 bit header prefix");
+ auto DescOrError = parseDWARF32StringOffsetsTableHeader(DA, Offset - 8);
+ if (!DescOrError)
+ return DescOrError.takeError();
+ Desc = *DescOrError;
+ break;
+ }
+ }
+ return Desc.validateContributionSize(DA);
+}
+
+Expected<Optional<StrOffsetsContributionDescriptor>>
+DWARFUnit::determineStringOffsetsTableContribution(DWARFDataExtractor &DA) {
+ assert(!IsDWO);
+ auto OptOffset = toSectionOffset(getUnitDIE().find(DW_AT_str_offsets_base));
+ if (!OptOffset)
+ return None;
+ auto DescOrError =
+ parseDWARFStringOffsetsTableHeader(DA, Header.getFormat(), *OptOffset);
+ if (!DescOrError)
+ return DescOrError.takeError();
+ return *DescOrError;
+}
+
+Expected<Optional<StrOffsetsContributionDescriptor>>
+DWARFUnit::determineStringOffsetsTableContributionDWO(DWARFDataExtractor & DA) {
+ assert(IsDWO);
+ uint64_t Offset = 0;
+ auto IndexEntry = Header.getIndexEntry();
+ const auto *C =
+ IndexEntry ? IndexEntry->getContribution(DW_SECT_STR_OFFSETS) : nullptr;
+ if (C)
+ Offset = C->Offset;
+ if (getVersion() >= 5) {
+ if (DA.getData().data() == nullptr)
+ return None;
+ Offset += Header.getFormat() == dwarf::DwarfFormat::DWARF32 ? 8 : 16;
+ // Look for a valid contribution at the given offset.
+ auto DescOrError = parseDWARFStringOffsetsTableHeader(DA, Header.getFormat(), Offset);
+ if (!DescOrError)
+ return DescOrError.takeError();
+ return *DescOrError;
+ }
+ // Prior to DWARF v5, we derive the contribution size from the
+ // index table (in a package file). In a .dwo file it is simply
+ // the length of the string offsets section.
+ StrOffsetsContributionDescriptor Desc;
+ if (C)
+ Desc = StrOffsetsContributionDescriptor(C->Offset, C->Length, 4,
+ Header.getFormat());
+ else if (!IndexEntry && !StringOffsetSection.Data.empty())
+ Desc = StrOffsetsContributionDescriptor(0, StringOffsetSection.Data.size(),
+ 4, Header.getFormat());
+ else
+ return None;
+ auto DescOrError = Desc.validateContributionSize(DA);
+ if (!DescOrError)
+ return DescOrError.takeError();
+ return *DescOrError;
+}
+
+Optional<uint64_t> DWARFUnit::getRnglistOffset(uint32_t Index) {
+ DataExtractor RangesData(RangeSection->Data, isLittleEndian,
+ getAddressByteSize());
+ DWARFDataExtractor RangesDA(Context.getDWARFObj(), *RangeSection,
+ isLittleEndian, 0);
+ if (Optional<uint64_t> Off = llvm::DWARFListTableHeader::getOffsetEntry(
+ RangesData, RangeSectionBase, getFormat(), Index))
+ return *Off + RangeSectionBase;
+ return None;
+}
+
+Optional<uint64_t> DWARFUnit::getLoclistOffset(uint32_t Index) {
+ if (Optional<uint64_t> Off = llvm::DWARFListTableHeader::getOffsetEntry(
+ LocTable->getData(), LocSectionBase, getFormat(), Index))
+ return *Off + LocSectionBase;
+ return None;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp
new file mode 100644
index 0000000000..d27fd08db1
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFUnitIndex.cpp
@@ -0,0 +1,300 @@
+//===- DWARFUnitIndex.cpp -------------------------------------------------===//
+//
+// 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/DWARF/DWARFUnitIndex.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cinttypes>
+#include <cstdint>
+
+using namespace llvm;
+
+namespace {
+
+enum class DWARFSectionKindV2 {
+ DW_SECT_INFO = 1,
+ DW_SECT_TYPES = 2,
+ DW_SECT_ABBREV = 3,
+ DW_SECT_LINE = 4,
+ DW_SECT_LOC = 5,
+ DW_SECT_STR_OFFSETS = 6,
+ DW_SECT_MACINFO = 7,
+ DW_SECT_MACRO = 8,
+};
+
+} // namespace
+
+// Return true if the section identifier is defined in the DWARFv5 standard.
+constexpr bool isKnownV5SectionID(uint32_t ID) {
+ return ID >= DW_SECT_INFO && ID <= DW_SECT_RNGLISTS &&
+ ID != DW_SECT_EXT_TYPES;
+}
+
+uint32_t llvm::serializeSectionKind(DWARFSectionKind Kind,
+ unsigned IndexVersion) {
+ if (IndexVersion == 5) {
+ assert(isKnownV5SectionID(Kind));
+ return static_cast<uint32_t>(Kind);
+ }
+ assert(IndexVersion == 2);
+ switch (Kind) {
+#define CASE(S,T) \
+ case DW_SECT_##S: \
+ return static_cast<uint32_t>(DWARFSectionKindV2::DW_SECT_##T)
+ CASE(INFO, INFO);
+ CASE(EXT_TYPES, TYPES);
+ CASE(ABBREV, ABBREV);
+ CASE(LINE, LINE);
+ CASE(EXT_LOC, LOC);
+ CASE(STR_OFFSETS, STR_OFFSETS);
+ CASE(EXT_MACINFO, MACINFO);
+ CASE(MACRO, MACRO);
+#undef CASE
+ default:
+ // All other section kinds have no corresponding values in v2 indexes.
+ llvm_unreachable("Invalid DWARFSectionKind");
+ }
+}
+
+DWARFSectionKind llvm::deserializeSectionKind(uint32_t Value,
+ unsigned IndexVersion) {
+ if (IndexVersion == 5)
+ return isKnownV5SectionID(Value)
+ ? static_cast<DWARFSectionKind>(Value)
+ : DW_SECT_EXT_unknown;
+ assert(IndexVersion == 2);
+ switch (static_cast<DWARFSectionKindV2>(Value)) {
+#define CASE(S,T) \
+ case DWARFSectionKindV2::DW_SECT_##S: \
+ return DW_SECT_##T
+ CASE(INFO, INFO);
+ CASE(TYPES, EXT_TYPES);
+ CASE(ABBREV, ABBREV);
+ CASE(LINE, LINE);
+ CASE(LOC, EXT_LOC);
+ CASE(STR_OFFSETS, STR_OFFSETS);
+ CASE(MACINFO, EXT_MACINFO);
+ CASE(MACRO, MACRO);
+#undef CASE
+ }
+ return DW_SECT_EXT_unknown;
+}
+
+bool DWARFUnitIndex::Header::parse(DataExtractor IndexData,
+ uint64_t *OffsetPtr) {
+ const uint64_t BeginOffset = *OffsetPtr;
+ if (!IndexData.isValidOffsetForDataOfSize(*OffsetPtr, 16))
+ return false;
+ // GCC Debug Fission defines the version as an unsigned 32-bit field
+ // with value of 2, https://gcc.gnu.org/wiki/DebugFissionDWP.
+ // DWARFv5 defines the same space as an uhalf version field with value of 5
+ // and a 2 bytes long padding, see Section 7.3.5.3.
+ Version = IndexData.getU32(OffsetPtr);
+ if (Version != 2) {
+ *OffsetPtr = BeginOffset;
+ Version = IndexData.getU16(OffsetPtr);
+ if (Version != 5)
+ return false;
+ *OffsetPtr += 2; // Skip padding.
+ }
+ NumColumns = IndexData.getU32(OffsetPtr);
+ NumUnits = IndexData.getU32(OffsetPtr);
+ NumBuckets = IndexData.getU32(OffsetPtr);
+ return true;
+}
+
+void DWARFUnitIndex::Header::dump(raw_ostream &OS) const {
+ OS << format("version = %u, units = %u, slots = %u\n\n", Version, NumUnits, NumBuckets);
+}
+
+bool DWARFUnitIndex::parse(DataExtractor IndexData) {
+ bool b = parseImpl(IndexData);
+ if (!b) {
+ // Make sure we don't try to dump anything
+ Header.NumBuckets = 0;
+ // Release any partially initialized data.
+ ColumnKinds.reset();
+ Rows.reset();
+ }
+ return b;
+}
+
+bool DWARFUnitIndex::parseImpl(DataExtractor IndexData) {
+ uint64_t Offset = 0;
+ if (!Header.parse(IndexData, &Offset))
+ return false;
+
+ // Fix InfoColumnKind: in DWARFv5, type units are in .debug_info.dwo.
+ if (Header.Version == 5)
+ InfoColumnKind = DW_SECT_INFO;
+
+ if (!IndexData.isValidOffsetForDataOfSize(
+ Offset, Header.NumBuckets * (8 + 4) +
+ (2 * Header.NumUnits + 1) * 4 * Header.NumColumns))
+ return false;
+
+ Rows = std::make_unique<Entry[]>(Header.NumBuckets);
+ auto Contribs =
+ std::make_unique<Entry::SectionContribution *[]>(Header.NumUnits);
+ ColumnKinds = std::make_unique<DWARFSectionKind[]>(Header.NumColumns);
+ RawSectionIds = std::make_unique<uint32_t[]>(Header.NumColumns);
+
+ // Read Hash Table of Signatures
+ for (unsigned i = 0; i != Header.NumBuckets; ++i)
+ Rows[i].Signature = IndexData.getU64(&Offset);
+
+ // Read Parallel Table of Indexes
+ for (unsigned i = 0; i != Header.NumBuckets; ++i) {
+ auto Index = IndexData.getU32(&Offset);
+ if (!Index)
+ continue;
+ Rows[i].Index = this;
+ Rows[i].Contributions =
+ std::make_unique<Entry::SectionContribution[]>(Header.NumColumns);
+ Contribs[Index - 1] = Rows[i].Contributions.get();
+ }
+
+ // Read the Column Headers
+ for (unsigned i = 0; i != Header.NumColumns; ++i) {
+ RawSectionIds[i] = IndexData.getU32(&Offset);
+ ColumnKinds[i] = deserializeSectionKind(RawSectionIds[i], Header.Version);
+ if (ColumnKinds[i] == InfoColumnKind) {
+ if (InfoColumn != -1)
+ return false;
+ InfoColumn = i;
+ }
+ }
+
+ if (InfoColumn == -1)
+ return false;
+
+ // Read Table of Section Offsets
+ for (unsigned i = 0; i != Header.NumUnits; ++i) {
+ auto *Contrib = Contribs[i];
+ for (unsigned i = 0; i != Header.NumColumns; ++i)
+ Contrib[i].Offset = IndexData.getU32(&Offset);
+ }
+
+ // Read Table of Section Sizes
+ for (unsigned i = 0; i != Header.NumUnits; ++i) {
+ auto *Contrib = Contribs[i];
+ for (unsigned i = 0; i != Header.NumColumns; ++i)
+ Contrib[i].Length = IndexData.getU32(&Offset);
+ }
+
+ return true;
+}
+
+StringRef DWARFUnitIndex::getColumnHeader(DWARFSectionKind DS) {
+ switch (DS) {
+#define HANDLE_DW_SECT(ID, NAME) \
+ case DW_SECT_##NAME: \
+ return #NAME;
+#include "llvm/BinaryFormat/Dwarf.def"
+ case DW_SECT_EXT_TYPES:
+ return "TYPES";
+ case DW_SECT_EXT_LOC:
+ return "LOC";
+ case DW_SECT_EXT_MACINFO:
+ return "MACINFO";
+ case DW_SECT_EXT_unknown:
+ return StringRef();
+ }
+ llvm_unreachable("Unknown DWARFSectionKind");
+}
+
+void DWARFUnitIndex::dump(raw_ostream &OS) const {
+ if (!*this)
+ return;
+
+ Header.dump(OS);
+ OS << "Index Signature ";
+ for (unsigned i = 0; i != Header.NumColumns; ++i) {
+ DWARFSectionKind Kind = ColumnKinds[i];
+ StringRef Name = getColumnHeader(Kind);
+ if (!Name.empty())
+ OS << ' ' << left_justify(Name, 24);
+ else
+ OS << format(" Unknown: %-15" PRIu32, RawSectionIds[i]);
+ }
+ OS << "\n----- ------------------";
+ for (unsigned i = 0; i != Header.NumColumns; ++i)
+ OS << " ------------------------";
+ OS << '\n';
+ for (unsigned i = 0; i != Header.NumBuckets; ++i) {
+ auto &Row = Rows[i];
+ if (auto *Contribs = Row.Contributions.get()) {
+ OS << format("%5u 0x%016" PRIx64 " ", i + 1, Row.Signature);
+ for (unsigned i = 0; i != Header.NumColumns; ++i) {
+ auto &Contrib = Contribs[i];
+ OS << format("[0x%08x, 0x%08x) ", Contrib.Offset,
+ Contrib.Offset + Contrib.Length);
+ }
+ OS << '\n';
+ }
+ }
+}
+
+const DWARFUnitIndex::Entry::SectionContribution *
+DWARFUnitIndex::Entry::getContribution(DWARFSectionKind Sec) const {
+ uint32_t i = 0;
+ for (; i != Index->Header.NumColumns; ++i)
+ if (Index->ColumnKinds[i] == Sec)
+ return &Contributions[i];
+ return nullptr;
+}
+
+const DWARFUnitIndex::Entry::SectionContribution *
+DWARFUnitIndex::Entry::getContribution() const {
+ return &Contributions[Index->InfoColumn];
+}
+
+const DWARFUnitIndex::Entry *
+DWARFUnitIndex::getFromOffset(uint32_t Offset) const {
+ if (OffsetLookup.empty()) {
+ for (uint32_t i = 0; i != Header.NumBuckets; ++i)
+ if (Rows[i].Contributions)
+ OffsetLookup.push_back(&Rows[i]);
+ llvm::sort(OffsetLookup, [&](Entry *E1, Entry *E2) {
+ return E1->Contributions[InfoColumn].Offset <
+ E2->Contributions[InfoColumn].Offset;
+ });
+ }
+ auto I = partition_point(OffsetLookup, [&](Entry *E2) {
+ return E2->Contributions[InfoColumn].Offset <= Offset;
+ });
+ if (I == OffsetLookup.begin())
+ return nullptr;
+ --I;
+ const auto *E = *I;
+ const auto &InfoContrib = E->Contributions[InfoColumn];
+ if ((InfoContrib.Offset + InfoContrib.Length) <= Offset)
+ return nullptr;
+ return E;
+}
+
+const DWARFUnitIndex::Entry *DWARFUnitIndex::getFromHash(uint64_t S) const {
+ uint64_t Mask = Header.NumBuckets - 1;
+
+ auto H = S & Mask;
+ auto HP = ((S >> 32) & Mask) | 1;
+ // The spec says "while 0 is a valid hash value, the row index in a used slot
+ // will always be non-zero". Loop until we find a match or an empty slot.
+ while (Rows[H].getSignature() != S && Rows[H].Index != nullptr)
+ H = (H + HP) & Mask;
+
+ // If the slot is empty, we don't care whether the signature matches (it could
+ // be zero and still match the zeros in the empty slot).
+ if (Rows[H].Index == nullptr)
+ return nullptr;
+
+ return &Rows[H];
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFVerifier.cpp b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFVerifier.cpp
new file mode 100644
index 0000000000..ca7ac785b5
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/DWARFVerifier.cpp
@@ -0,0 +1,1563 @@
+//===- DWARFVerifier.cpp --------------------------------------------------===//
+//
+// 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/DWARF/DWARFVerifier.h"
+#include "llvm/ADT/SmallSet.h"
+#include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFCompileUnit.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFDebugLine.h"
+#include "llvm/DebugInfo/DWARF/DWARFDie.h"
+#include "llvm/DebugInfo/DWARF/DWARFExpression.h"
+#include "llvm/DebugInfo/DWARF/DWARFFormValue.h"
+#include "llvm/DebugInfo/DWARF/DWARFSection.h"
+#include "llvm/DebugInfo/DWARF/DWARFUnitIndex.h"
+#include "llvm/Support/DJB.h"
+#include "llvm/Support/FormatVariadic.h"
+#include "llvm/Support/WithColor.h"
+#include "llvm/Support/raw_ostream.h"
+#include <map>
+#include <set>
+#include <vector>
+
+using namespace llvm;
+using namespace dwarf;
+using namespace object;
+
+Optional<DWARFAddressRange>
+DWARFVerifier::DieRangeInfo::insert(const DWARFAddressRange &R) {
+ auto Begin = Ranges.begin();
+ auto End = Ranges.end();
+ auto Pos = std::lower_bound(Begin, End, R);
+
+ if (Pos != End) {
+ DWARFAddressRange Range(*Pos);
+ if (Pos->merge(R))
+ return Range;
+ }
+ if (Pos != Begin) {
+ auto Iter = Pos - 1;
+ DWARFAddressRange Range(*Iter);
+ if (Iter->merge(R))
+ return Range;
+ }
+
+ Ranges.insert(Pos, R);
+ return None;
+}
+
+DWARFVerifier::DieRangeInfo::die_range_info_iterator
+DWARFVerifier::DieRangeInfo::insert(const DieRangeInfo &RI) {
+ if (RI.Ranges.empty())
+ return Children.end();
+
+ auto End = Children.end();
+ auto Iter = Children.begin();
+ while (Iter != End) {
+ if (Iter->intersects(RI))
+ return Iter;
+ ++Iter;
+ }
+ Children.insert(RI);
+ return Children.end();
+}
+
+bool DWARFVerifier::DieRangeInfo::contains(const DieRangeInfo &RHS) const {
+ auto I1 = Ranges.begin(), E1 = Ranges.end();
+ auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end();
+ if (I2 == E2)
+ return true;
+
+ DWARFAddressRange R = *I2;
+ while (I1 != E1) {
+ bool Covered = I1->LowPC <= R.LowPC;
+ if (R.LowPC == R.HighPC || (Covered && R.HighPC <= I1->HighPC)) {
+ if (++I2 == E2)
+ return true;
+ R = *I2;
+ continue;
+ }
+ if (!Covered)
+ return false;
+ if (R.LowPC < I1->HighPC)
+ R.LowPC = I1->HighPC;
+ ++I1;
+ }
+ return false;
+}
+
+bool DWARFVerifier::DieRangeInfo::intersects(const DieRangeInfo &RHS) const {
+ auto I1 = Ranges.begin(), E1 = Ranges.end();
+ auto I2 = RHS.Ranges.begin(), E2 = RHS.Ranges.end();
+ while (I1 != E1 && I2 != E2) {
+ if (I1->intersects(*I2))
+ return true;
+ if (I1->LowPC < I2->LowPC)
+ ++I1;
+ else
+ ++I2;
+ }
+ return false;
+}
+
+bool DWARFVerifier::verifyUnitHeader(const DWARFDataExtractor DebugInfoData,
+ uint64_t *Offset, unsigned UnitIndex,
+ uint8_t &UnitType, bool &isUnitDWARF64) {
+ uint64_t AbbrOffset, Length;
+ uint8_t AddrSize = 0;
+ uint16_t Version;
+ bool Success = true;
+
+ bool ValidLength = false;
+ bool ValidVersion = false;
+ bool ValidAddrSize = false;
+ bool ValidType = true;
+ bool ValidAbbrevOffset = true;
+
+ uint64_t OffsetStart = *Offset;
+ DwarfFormat Format;
+ std::tie(Length, Format) = DebugInfoData.getInitialLength(Offset);
+ isUnitDWARF64 = Format == DWARF64;
+ Version = DebugInfoData.getU16(Offset);
+
+ if (Version >= 5) {
+ UnitType = DebugInfoData.getU8(Offset);
+ AddrSize = DebugInfoData.getU8(Offset);
+ AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset) : DebugInfoData.getU32(Offset);
+ ValidType = dwarf::isUnitType(UnitType);
+ } else {
+ UnitType = 0;
+ AbbrOffset = isUnitDWARF64 ? DebugInfoData.getU64(Offset) : DebugInfoData.getU32(Offset);
+ AddrSize = DebugInfoData.getU8(Offset);
+ }
+
+ if (!DCtx.getDebugAbbrev()->getAbbreviationDeclarationSet(AbbrOffset))
+ ValidAbbrevOffset = false;
+
+ ValidLength = DebugInfoData.isValidOffset(OffsetStart + Length + 3);
+ ValidVersion = DWARFContext::isSupportedVersion(Version);
+ ValidAddrSize = DWARFContext::isAddressSizeSupported(AddrSize);
+ if (!ValidLength || !ValidVersion || !ValidAddrSize || !ValidAbbrevOffset ||
+ !ValidType) {
+ Success = false;
+ error() << format("Units[%d] - start offset: 0x%08" PRIx64 " \n", UnitIndex,
+ OffsetStart);
+ if (!ValidLength)
+ note() << "The length for this unit is too "
+ "large for the .debug_info provided.\n";
+ if (!ValidVersion)
+ note() << "The 16 bit unit header version is not valid.\n";
+ if (!ValidType)
+ note() << "The unit type encoding is not valid.\n";
+ if (!ValidAbbrevOffset)
+ note() << "The offset into the .debug_abbrev section is "
+ "not valid.\n";
+ if (!ValidAddrSize)
+ note() << "The address size is unsupported.\n";
+ }
+ *Offset = OffsetStart + Length + (isUnitDWARF64 ? 12 : 4);
+ return Success;
+}
+
+bool DWARFVerifier::verifyName(const DWARFDie &Die) {
+ // FIXME Add some kind of record of which DIE names have already failed and
+ // don't bother checking a DIE that uses an already failed DIE.
+
+ std::string ReconstructedName;
+ raw_string_ostream OS(ReconstructedName);
+ std::string OriginalFullName;
+ Die.getFullName(OS, &OriginalFullName);
+ OS.flush();
+ if (OriginalFullName.empty() || OriginalFullName == ReconstructedName)
+ return false;
+
+ error() << "Simplified template DW_AT_name could not be reconstituted:\n"
+ << formatv(" original: {0}\n"
+ " reconstituted: {1}\n",
+ OriginalFullName, ReconstructedName);
+ dump(Die) << '\n';
+ dump(Die.getDwarfUnit()->getUnitDIE()) << '\n';
+ return true;
+}
+
+unsigned DWARFVerifier::verifyUnitContents(DWARFUnit &Unit,
+ ReferenceMap &UnitLocalReferences,
+ ReferenceMap &CrossUnitReferences) {
+ unsigned NumUnitErrors = 0;
+ unsigned NumDies = Unit.getNumDIEs();
+ for (unsigned I = 0; I < NumDies; ++I) {
+ auto Die = Unit.getDIEAtIndex(I);
+
+ if (Die.getTag() == DW_TAG_null)
+ continue;
+
+ for (auto AttrValue : Die.attributes()) {
+ NumUnitErrors += verifyDebugInfoAttribute(Die, AttrValue);
+ NumUnitErrors += verifyDebugInfoForm(Die, AttrValue, UnitLocalReferences,
+ CrossUnitReferences);
+ }
+
+ NumUnitErrors += verifyName(Die);
+
+ if (Die.hasChildren()) {
+ if (Die.getFirstChild().isValid() &&
+ Die.getFirstChild().getTag() == DW_TAG_null) {
+ warn() << dwarf::TagString(Die.getTag())
+ << " has DW_CHILDREN_yes but DIE has no children: ";
+ Die.dump(OS);
+ }
+ }
+
+ NumUnitErrors += verifyDebugInfoCallSite(Die);
+ }
+
+ DWARFDie Die = Unit.getUnitDIE(/* ExtractUnitDIEOnly = */ false);
+ if (!Die) {
+ error() << "Compilation unit without DIE.\n";
+ NumUnitErrors++;
+ return NumUnitErrors;
+ }
+
+ if (!dwarf::isUnitType(Die.getTag())) {
+ error() << "Compilation unit root DIE is not a unit DIE: "
+ << dwarf::TagString(Die.getTag()) << ".\n";
+ NumUnitErrors++;
+ }
+
+ uint8_t UnitType = Unit.getUnitType();
+ if (!DWARFUnit::isMatchingUnitTypeAndTag(UnitType, Die.getTag())) {
+ error() << "Compilation unit type (" << dwarf::UnitTypeString(UnitType)
+ << ") and root DIE (" << dwarf::TagString(Die.getTag())
+ << ") do not match.\n";
+ NumUnitErrors++;
+ }
+
+ // According to DWARF Debugging Information Format Version 5,
+ // 3.1.2 Skeleton Compilation Unit Entries:
+ // "A skeleton compilation unit has no children."
+ if (Die.getTag() == dwarf::DW_TAG_skeleton_unit && Die.hasChildren()) {
+ error() << "Skeleton compilation unit has children.\n";
+ NumUnitErrors++;
+ }
+
+ DieRangeInfo RI;
+ NumUnitErrors += verifyDieRanges(Die, RI);
+
+ return NumUnitErrors;
+}
+
+unsigned DWARFVerifier::verifyDebugInfoCallSite(const DWARFDie &Die) {
+ if (Die.getTag() != DW_TAG_call_site && Die.getTag() != DW_TAG_GNU_call_site)
+ return 0;
+
+ DWARFDie Curr = Die.getParent();
+ for (; Curr.isValid() && !Curr.isSubprogramDIE(); Curr = Die.getParent()) {
+ if (Curr.getTag() == DW_TAG_inlined_subroutine) {
+ error() << "Call site entry nested within inlined subroutine:";
+ Curr.dump(OS);
+ return 1;
+ }
+ }
+
+ if (!Curr.isValid()) {
+ error() << "Call site entry not nested within a valid subprogram:";
+ Die.dump(OS);
+ return 1;
+ }
+
+ Optional<DWARFFormValue> CallAttr =
+ Curr.find({DW_AT_call_all_calls, DW_AT_call_all_source_calls,
+ DW_AT_call_all_tail_calls, DW_AT_GNU_all_call_sites,
+ DW_AT_GNU_all_source_call_sites,
+ DW_AT_GNU_all_tail_call_sites});
+ if (!CallAttr) {
+ error() << "Subprogram with call site entry has no DW_AT_call attribute:";
+ Curr.dump(OS);
+ Die.dump(OS, /*indent*/ 1);
+ return 1;
+ }
+
+ return 0;
+}
+
+unsigned DWARFVerifier::verifyAbbrevSection(const DWARFDebugAbbrev *Abbrev) {
+ unsigned NumErrors = 0;
+ if (Abbrev) {
+ const DWARFAbbreviationDeclarationSet *AbbrDecls =
+ Abbrev->getAbbreviationDeclarationSet(0);
+ for (auto AbbrDecl : *AbbrDecls) {
+ SmallDenseSet<uint16_t> AttributeSet;
+ for (auto Attribute : AbbrDecl.attributes()) {
+ auto Result = AttributeSet.insert(Attribute.Attr);
+ if (!Result.second) {
+ error() << "Abbreviation declaration contains multiple "
+ << AttributeString(Attribute.Attr) << " attributes.\n";
+ AbbrDecl.dump(OS);
+ ++NumErrors;
+ }
+ }
+ }
+ }
+ return NumErrors;
+}
+
+bool DWARFVerifier::handleDebugAbbrev() {
+ OS << "Verifying .debug_abbrev...\n";
+
+ const DWARFObject &DObj = DCtx.getDWARFObj();
+ unsigned NumErrors = 0;
+ if (!DObj.getAbbrevSection().empty())
+ NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrev());
+ if (!DObj.getAbbrevDWOSection().empty())
+ NumErrors += verifyAbbrevSection(DCtx.getDebugAbbrevDWO());
+
+ return NumErrors == 0;
+}
+
+unsigned DWARFVerifier::verifyUnits(const DWARFUnitVector &Units) {
+ unsigned NumDebugInfoErrors = 0;
+ ReferenceMap CrossUnitReferences;
+
+ unsigned Index = 1;
+ for (const auto &Unit : Units) {
+ OS << "Verifying unit: " << Index << " / " << Units.getNumUnits();
+ if (const char* Name = Unit->getUnitDIE(true).getShortName())
+ OS << ", \"" << Name << '\"';
+ OS << '\n';
+ OS.flush();
+ ReferenceMap UnitLocalReferences;
+ NumDebugInfoErrors +=
+ verifyUnitContents(*Unit, UnitLocalReferences, CrossUnitReferences);
+ NumDebugInfoErrors += verifyDebugInfoReferences(
+ UnitLocalReferences, [&](uint64_t Offset) { return Unit.get(); });
+ ++Index;
+ }
+
+ NumDebugInfoErrors += verifyDebugInfoReferences(
+ CrossUnitReferences, [&](uint64_t Offset) -> DWARFUnit * {
+ if (DWARFUnit *U = Units.getUnitForOffset(Offset))
+ return U;
+ return nullptr;
+ });
+
+ return NumDebugInfoErrors;
+}
+
+unsigned DWARFVerifier::verifyUnitSection(const DWARFSection &S) {
+ const DWARFObject &DObj = DCtx.getDWARFObj();
+ DWARFDataExtractor DebugInfoData(DObj, S, DCtx.isLittleEndian(), 0);
+ unsigned NumDebugInfoErrors = 0;
+ uint64_t Offset = 0, UnitIdx = 0;
+ uint8_t UnitType = 0;
+ bool isUnitDWARF64 = false;
+ bool isHeaderChainValid = true;
+ bool hasDIE = DebugInfoData.isValidOffset(Offset);
+ DWARFUnitVector TypeUnitVector;
+ DWARFUnitVector CompileUnitVector;
+ /// A map that tracks all references (converted absolute references) so we
+ /// can verify each reference points to a valid DIE and not an offset that
+ /// lies between to valid DIEs.
+ ReferenceMap CrossUnitReferences;
+ while (hasDIE) {
+ if (!verifyUnitHeader(DebugInfoData, &Offset, UnitIdx, UnitType,
+ isUnitDWARF64)) {
+ isHeaderChainValid = false;
+ if (isUnitDWARF64)
+ break;
+ }
+ hasDIE = DebugInfoData.isValidOffset(Offset);
+ ++UnitIdx;
+ }
+ if (UnitIdx == 0 && !hasDIE) {
+ warn() << "Section is empty.\n";
+ isHeaderChainValid = true;
+ }
+ if (!isHeaderChainValid)
+ ++NumDebugInfoErrors;
+ return NumDebugInfoErrors;
+}
+
+bool DWARFVerifier::handleDebugInfo() {
+ const DWARFObject &DObj = DCtx.getDWARFObj();
+ unsigned NumErrors = 0;
+
+ OS << "Verifying .debug_info Unit Header Chain...\n";
+ DObj.forEachInfoSections([&](const DWARFSection &S) {
+ NumErrors += verifyUnitSection(S);
+ });
+
+ OS << "Verifying .debug_types Unit Header Chain...\n";
+ DObj.forEachTypesSections([&](const DWARFSection &S) {
+ NumErrors += verifyUnitSection(S);
+ });
+
+ OS << "Verifying non-dwo Units...\n";
+ NumErrors += verifyUnits(DCtx.getNormalUnitsVector());
+
+ OS << "Verifying dwo Units...\n";
+ NumErrors += verifyUnits(DCtx.getDWOUnitsVector());
+ return NumErrors == 0;
+}
+
+unsigned DWARFVerifier::verifyDieRanges(const DWARFDie &Die,
+ DieRangeInfo &ParentRI) {
+ unsigned NumErrors = 0;
+
+ if (!Die.isValid())
+ return NumErrors;
+
+ DWARFUnit *Unit = Die.getDwarfUnit();
+
+ auto RangesOrError = Die.getAddressRanges();
+ if (!RangesOrError) {
+ // FIXME: Report the error.
+ if (!Unit->isDWOUnit())
+ ++NumErrors;
+ llvm::consumeError(RangesOrError.takeError());
+ return NumErrors;
+ }
+
+ const DWARFAddressRangesVector &Ranges = RangesOrError.get();
+ // Build RI for this DIE and check that ranges within this DIE do not
+ // overlap.
+ DieRangeInfo RI(Die);
+
+ // TODO support object files better
+ //
+ // Some object file formats (i.e. non-MachO) support COMDAT. ELF in
+ // particular does so by placing each function into a section. The DWARF data
+ // for the function at that point uses a section relative DW_FORM_addrp for
+ // the DW_AT_low_pc and a DW_FORM_data4 for the offset as the DW_AT_high_pc.
+ // In such a case, when the Die is the CU, the ranges will overlap, and we
+ // will flag valid conflicting ranges as invalid.
+ //
+ // For such targets, we should read the ranges from the CU and partition them
+ // by the section id. The ranges within a particular section should be
+ // disjoint, although the ranges across sections may overlap. We would map
+ // the child die to the entity that it references and the section with which
+ // it is associated. The child would then be checked against the range
+ // information for the associated section.
+ //
+ // For now, simply elide the range verification for the CU DIEs if we are
+ // processing an object file.
+
+ if (!IsObjectFile || IsMachOObject || Die.getTag() != DW_TAG_compile_unit) {
+ bool DumpDieAfterError = false;
+ for (const auto &Range : Ranges) {
+ if (!Range.valid()) {
+ ++NumErrors;
+ error() << "Invalid address range " << Range << "\n";
+ DumpDieAfterError = true;
+ continue;
+ }
+
+ // Verify that ranges don't intersect and also build up the DieRangeInfo
+ // address ranges. Don't break out of the loop below early, or we will
+ // think this DIE doesn't have all of the address ranges it is supposed
+ // to have. Compile units often have DW_AT_ranges that can contain one or
+ // more dead stripped address ranges which tend to all be at the same
+ // address: 0 or -1.
+ if (auto PrevRange = RI.insert(Range)) {
+ ++NumErrors;
+ error() << "DIE has overlapping ranges in DW_AT_ranges attribute: "
+ << *PrevRange << " and " << Range << '\n';
+ DumpDieAfterError = true;
+ }
+ }
+ if (DumpDieAfterError)
+ dump(Die, 2) << '\n';
+ }
+
+ // Verify that children don't intersect.
+ const auto IntersectingChild = ParentRI.insert(RI);
+ if (IntersectingChild != ParentRI.Children.end()) {
+ ++NumErrors;
+ error() << "DIEs have overlapping address ranges:";
+ dump(Die);
+ dump(IntersectingChild->Die) << '\n';
+ }
+
+ // Verify that ranges are contained within their parent.
+ bool ShouldBeContained = !RI.Ranges.empty() && !ParentRI.Ranges.empty() &&
+ !(Die.getTag() == DW_TAG_subprogram &&
+ ParentRI.Die.getTag() == DW_TAG_subprogram);
+ if (ShouldBeContained && !ParentRI.contains(RI)) {
+ ++NumErrors;
+ error() << "DIE address ranges are not contained in its parent's ranges:";
+ dump(ParentRI.Die);
+ dump(Die, 2) << '\n';
+ }
+
+ // Recursively check children.
+ for (DWARFDie Child : Die)
+ NumErrors += verifyDieRanges(Child, RI);
+
+ return NumErrors;
+}
+
+unsigned DWARFVerifier::verifyDebugInfoAttribute(const DWARFDie &Die,
+ DWARFAttribute &AttrValue) {
+ unsigned NumErrors = 0;
+ auto ReportError = [&](const Twine &TitleMsg) {
+ ++NumErrors;
+ error() << TitleMsg << '\n';
+ dump(Die) << '\n';
+ };
+
+ const DWARFObject &DObj = DCtx.getDWARFObj();
+ DWARFUnit *U = Die.getDwarfUnit();
+ const auto Attr = AttrValue.Attr;
+ switch (Attr) {
+ case DW_AT_ranges:
+ // Make sure the offset in the DW_AT_ranges attribute is valid.
+ if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
+ unsigned DwarfVersion = U->getVersion();
+ const DWARFSection &RangeSection = DwarfVersion < 5
+ ? DObj.getRangesSection()
+ : DObj.getRnglistsSection();
+ if (U->isDWOUnit() && RangeSection.Data.empty())
+ break;
+ if (*SectionOffset >= RangeSection.Data.size())
+ ReportError(
+ "DW_AT_ranges offset is beyond " +
+ StringRef(DwarfVersion < 5 ? ".debug_ranges" : ".debug_rnglists") +
+ " bounds: " + llvm::formatv("{0:x8}", *SectionOffset));
+ break;
+ }
+ ReportError("DIE has invalid DW_AT_ranges encoding:");
+ break;
+ case DW_AT_stmt_list:
+ // Make sure the offset in the DW_AT_stmt_list attribute is valid.
+ if (auto SectionOffset = AttrValue.Value.getAsSectionOffset()) {
+ if (*SectionOffset >= U->getLineSection().Data.size())
+ ReportError("DW_AT_stmt_list offset is beyond .debug_line bounds: " +
+ llvm::formatv("{0:x8}", *SectionOffset));
+ break;
+ }
+ ReportError("DIE has invalid DW_AT_stmt_list encoding:");
+ break;
+ case DW_AT_location: {
+ // FIXME: It might be nice if there's a way to walk location expressions
+ // without trying to resolve the address ranges - it'd be a more efficient
+ // API (since the API is currently unnecessarily resolving addresses for
+ // this use case which only wants to validate the expressions themselves) &
+ // then the expressions could be validated even if the addresses can't be
+ // resolved.
+ // That sort of API would probably look like a callback "for each
+ // expression" with some way to lazily resolve the address ranges when
+ // needed (& then the existing API used here could be built on top of that -
+ // using the callback API to build the data structure and return it).
+ if (Expected<std::vector<DWARFLocationExpression>> Loc =
+ Die.getLocations(DW_AT_location)) {
+ for (const auto &Entry : *Loc) {
+ DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(), 0);
+ DWARFExpression Expression(Data, U->getAddressByteSize(),
+ U->getFormParams().Format);
+ bool Error =
+ any_of(Expression, [](const DWARFExpression::Operation &Op) {
+ return Op.isError();
+ });
+ if (Error || !Expression.verify(U))
+ ReportError("DIE contains invalid DWARF expression:");
+ }
+ } else if (Error Err = handleErrors(
+ Loc.takeError(), [&](std::unique_ptr<ResolverError> E) {
+ return U->isDWOUnit() ? Error::success()
+ : Error(std::move(E));
+ }))
+ ReportError(toString(std::move(Err)));
+ break;
+ }
+ case DW_AT_specification:
+ case DW_AT_abstract_origin: {
+ if (auto ReferencedDie = Die.getAttributeValueAsReferencedDie(Attr)) {
+ auto DieTag = Die.getTag();
+ auto RefTag = ReferencedDie.getTag();
+ if (DieTag == RefTag)
+ break;
+ if (DieTag == DW_TAG_inlined_subroutine && RefTag == DW_TAG_subprogram)
+ break;
+ if (DieTag == DW_TAG_variable && RefTag == DW_TAG_member)
+ break;
+ // This might be reference to a function declaration.
+ if (DieTag == DW_TAG_GNU_call_site && RefTag == DW_TAG_subprogram)
+ break;
+ ReportError("DIE with tag " + TagString(DieTag) + " has " +
+ AttributeString(Attr) +
+ " that points to DIE with "
+ "incompatible tag " +
+ TagString(RefTag));
+ }
+ break;
+ }
+ case DW_AT_type: {
+ DWARFDie TypeDie = Die.getAttributeValueAsReferencedDie(DW_AT_type);
+ if (TypeDie && !isType(TypeDie.getTag())) {
+ ReportError("DIE has " + AttributeString(Attr) +
+ " with incompatible tag " + TagString(TypeDie.getTag()));
+ }
+ break;
+ }
+ case DW_AT_call_file:
+ case DW_AT_decl_file: {
+ if (auto FileIdx = AttrValue.Value.getAsUnsignedConstant()) {
+ if (U->isDWOUnit() && !U->isTypeUnit())
+ break;
+ const auto *LT = U->getContext().getLineTableForUnit(U);
+ if (LT) {
+ if (!LT->hasFileAtIndex(*FileIdx)) {
+ bool IsZeroIndexed = LT->Prologue.getVersion() >= 5;
+ if (Optional<uint64_t> LastFileIdx = LT->getLastValidFileIndex()) {
+ ReportError("DIE has " + AttributeString(Attr) +
+ " with an invalid file index " +
+ llvm::formatv("{0}", *FileIdx) +
+ " (valid values are [" + (IsZeroIndexed ? "0-" : "1-") +
+ llvm::formatv("{0}", *LastFileIdx) + "])");
+ } else {
+ ReportError("DIE has " + AttributeString(Attr) +
+ " with an invalid file index " +
+ llvm::formatv("{0}", *FileIdx) +
+ " (the file table in the prologue is empty)");
+ }
+ }
+ } else {
+ ReportError("DIE has " + AttributeString(Attr) +
+ " that references a file with index " +
+ llvm::formatv("{0}", *FileIdx) +
+ " and the compile unit has no line table");
+ }
+ } else {
+ ReportError("DIE has " + AttributeString(Attr) +
+ " with invalid encoding");
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return NumErrors;
+}
+
+unsigned DWARFVerifier::verifyDebugInfoForm(const DWARFDie &Die,
+ DWARFAttribute &AttrValue,
+ ReferenceMap &LocalReferences,
+ ReferenceMap &CrossUnitReferences) {
+ auto DieCU = Die.getDwarfUnit();
+ unsigned NumErrors = 0;
+ const auto Form = AttrValue.Value.getForm();
+ switch (Form) {
+ case DW_FORM_ref1:
+ case DW_FORM_ref2:
+ case DW_FORM_ref4:
+ case DW_FORM_ref8:
+ case DW_FORM_ref_udata: {
+ // Verify all CU relative references are valid CU offsets.
+ Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
+ assert(RefVal);
+ if (RefVal) {
+ auto CUSize = DieCU->getNextUnitOffset() - DieCU->getOffset();
+ auto CUOffset = AttrValue.Value.getRawUValue();
+ if (CUOffset >= CUSize) {
+ ++NumErrors;
+ error() << FormEncodingString(Form) << " CU offset "
+ << format("0x%08" PRIx64, CUOffset)
+ << " is invalid (must be less than CU size of "
+ << format("0x%08" PRIx64, CUSize) << "):\n";
+ Die.dump(OS, 0, DumpOpts);
+ dump(Die) << '\n';
+ } else {
+ // Valid reference, but we will verify it points to an actual
+ // DIE later.
+ LocalReferences[*RefVal].insert(Die.getOffset());
+ }
+ }
+ break;
+ }
+ case DW_FORM_ref_addr: {
+ // Verify all absolute DIE references have valid offsets in the
+ // .debug_info section.
+ Optional<uint64_t> RefVal = AttrValue.Value.getAsReference();
+ assert(RefVal);
+ if (RefVal) {
+ if (*RefVal >= DieCU->getInfoSection().Data.size()) {
+ ++NumErrors;
+ error() << "DW_FORM_ref_addr offset beyond .debug_info "
+ "bounds:\n";
+ dump(Die) << '\n';
+ } else {
+ // Valid reference, but we will verify it points to an actual
+ // DIE later.
+ CrossUnitReferences[*RefVal].insert(Die.getOffset());
+ }
+ }
+ break;
+ }
+ case DW_FORM_strp:
+ case DW_FORM_strx:
+ case DW_FORM_strx1:
+ case DW_FORM_strx2:
+ case DW_FORM_strx3:
+ case DW_FORM_strx4: {
+ if (Error E = AttrValue.Value.getAsCString().takeError()) {
+ ++NumErrors;
+ error() << toString(std::move(E)) << ":\n";
+ dump(Die) << '\n';
+ }
+ break;
+ }
+ default:
+ break;
+ }
+ return NumErrors;
+}
+
+unsigned DWARFVerifier::verifyDebugInfoReferences(
+ const ReferenceMap &References,
+ llvm::function_ref<DWARFUnit *(uint64_t)> GetUnitForOffset) {
+ auto GetDIEForOffset = [&](uint64_t Offset) {
+ if (DWARFUnit *U = GetUnitForOffset(Offset))
+ return U->getDIEForOffset(Offset);
+ return DWARFDie();
+ };
+ unsigned NumErrors = 0;
+ for (const std::pair<const uint64_t, std::set<uint64_t>> &Pair :
+ References) {
+ if (GetDIEForOffset(Pair.first))
+ continue;
+ ++NumErrors;
+ error() << "invalid DIE reference " << format("0x%08" PRIx64, Pair.first)
+ << ". Offset is in between DIEs:\n";
+ for (auto Offset : Pair.second)
+ dump(GetDIEForOffset(Offset)) << '\n';
+ OS << "\n";
+ }
+ return NumErrors;
+}
+
+void DWARFVerifier::verifyDebugLineStmtOffsets() {
+ std::map<uint64_t, DWARFDie> StmtListToDie;
+ for (const auto &CU : DCtx.compile_units()) {
+ auto Die = CU->getUnitDIE();
+ // Get the attribute value as a section offset. No need to produce an
+ // error here if the encoding isn't correct because we validate this in
+ // the .debug_info verifier.
+ auto StmtSectionOffset = toSectionOffset(Die.find(DW_AT_stmt_list));
+ if (!StmtSectionOffset)
+ continue;
+ const uint64_t LineTableOffset = *StmtSectionOffset;
+ auto LineTable = DCtx.getLineTableForUnit(CU.get());
+ if (LineTableOffset < DCtx.getDWARFObj().getLineSection().Data.size()) {
+ if (!LineTable) {
+ ++NumDebugLineErrors;
+ error() << ".debug_line[" << format("0x%08" PRIx64, LineTableOffset)
+ << "] was not able to be parsed for CU:\n";
+ dump(Die) << '\n';
+ continue;
+ }
+ } else {
+ // Make sure we don't get a valid line table back if the offset is wrong.
+ assert(LineTable == nullptr);
+ // Skip this line table as it isn't valid. No need to create an error
+ // here because we validate this in the .debug_info verifier.
+ continue;
+ }
+ auto Iter = StmtListToDie.find(LineTableOffset);
+ if (Iter != StmtListToDie.end()) {
+ ++NumDebugLineErrors;
+ error() << "two compile unit DIEs, "
+ << format("0x%08" PRIx64, Iter->second.getOffset()) << " and "
+ << format("0x%08" PRIx64, Die.getOffset())
+ << ", have the same DW_AT_stmt_list section offset:\n";
+ dump(Iter->second);
+ dump(Die) << '\n';
+ // Already verified this line table before, no need to do it again.
+ continue;
+ }
+ StmtListToDie[LineTableOffset] = Die;
+ }
+}
+
+void DWARFVerifier::verifyDebugLineRows() {
+ for (const auto &CU : DCtx.compile_units()) {
+ auto Die = CU->getUnitDIE();
+ auto LineTable = DCtx.getLineTableForUnit(CU.get());
+ // If there is no line table we will have created an error in the
+ // .debug_info verifier or in verifyDebugLineStmtOffsets().
+ if (!LineTable)
+ continue;
+
+ // Verify prologue.
+ uint32_t MaxDirIndex = LineTable->Prologue.IncludeDirectories.size();
+ uint32_t FileIndex = 1;
+ StringMap<uint16_t> FullPathMap;
+ for (const auto &FileName : LineTable->Prologue.FileNames) {
+ // Verify directory index.
+ if (FileName.DirIdx > MaxDirIndex) {
+ ++NumDebugLineErrors;
+ error() << ".debug_line["
+ << format("0x%08" PRIx64,
+ *toSectionOffset(Die.find(DW_AT_stmt_list)))
+ << "].prologue.file_names[" << FileIndex
+ << "].dir_idx contains an invalid index: " << FileName.DirIdx
+ << "\n";
+ }
+
+ // Check file paths for duplicates.
+ std::string FullPath;
+ const bool HasFullPath = LineTable->getFileNameByIndex(
+ FileIndex, CU->getCompilationDir(),
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, FullPath);
+ assert(HasFullPath && "Invalid index?");
+ (void)HasFullPath;
+ auto It = FullPathMap.find(FullPath);
+ if (It == FullPathMap.end())
+ FullPathMap[FullPath] = FileIndex;
+ else if (It->second != FileIndex) {
+ warn() << ".debug_line["
+ << format("0x%08" PRIx64,
+ *toSectionOffset(Die.find(DW_AT_stmt_list)))
+ << "].prologue.file_names[" << FileIndex
+ << "] is a duplicate of file_names[" << It->second << "]\n";
+ }
+
+ FileIndex++;
+ }
+
+ // Verify rows.
+ uint64_t PrevAddress = 0;
+ uint32_t RowIndex = 0;
+ for (const auto &Row : LineTable->Rows) {
+ // Verify row address.
+ if (Row.Address.Address < PrevAddress) {
+ ++NumDebugLineErrors;
+ error() << ".debug_line["
+ << format("0x%08" PRIx64,
+ *toSectionOffset(Die.find(DW_AT_stmt_list)))
+ << "] row[" << RowIndex
+ << "] decreases in address from previous row:\n";
+
+ DWARFDebugLine::Row::dumpTableHeader(OS, 0);
+ if (RowIndex > 0)
+ LineTable->Rows[RowIndex - 1].dump(OS);
+ Row.dump(OS);
+ OS << '\n';
+ }
+
+ // Verify file index.
+ if (!LineTable->hasFileAtIndex(Row.File)) {
+ ++NumDebugLineErrors;
+ bool isDWARF5 = LineTable->Prologue.getVersion() >= 5;
+ error() << ".debug_line["
+ << format("0x%08" PRIx64,
+ *toSectionOffset(Die.find(DW_AT_stmt_list)))
+ << "][" << RowIndex << "] has invalid file index " << Row.File
+ << " (valid values are [" << (isDWARF5 ? "0," : "1,")
+ << LineTable->Prologue.FileNames.size()
+ << (isDWARF5 ? ")" : "]") << "):\n";
+ DWARFDebugLine::Row::dumpTableHeader(OS, 0);
+ Row.dump(OS);
+ OS << '\n';
+ }
+ if (Row.EndSequence)
+ PrevAddress = 0;
+ else
+ PrevAddress = Row.Address.Address;
+ ++RowIndex;
+ }
+ }
+}
+
+DWARFVerifier::DWARFVerifier(raw_ostream &S, DWARFContext &D,
+ DIDumpOptions DumpOpts)
+ : OS(S), DCtx(D), DumpOpts(std::move(DumpOpts)), IsObjectFile(false),
+ IsMachOObject(false) {
+ if (const auto *F = DCtx.getDWARFObj().getFile()) {
+ IsObjectFile = F->isRelocatableObject();
+ IsMachOObject = F->isMachO();
+ }
+}
+
+bool DWARFVerifier::handleDebugLine() {
+ NumDebugLineErrors = 0;
+ OS << "Verifying .debug_line...\n";
+ verifyDebugLineStmtOffsets();
+ verifyDebugLineRows();
+ return NumDebugLineErrors == 0;
+}
+
+unsigned DWARFVerifier::verifyAppleAccelTable(const DWARFSection *AccelSection,
+ DataExtractor *StrData,
+ const char *SectionName) {
+ unsigned NumErrors = 0;
+ DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), *AccelSection,
+ DCtx.isLittleEndian(), 0);
+ AppleAcceleratorTable AccelTable(AccelSectionData, *StrData);
+
+ OS << "Verifying " << SectionName << "...\n";
+
+ // Verify that the fixed part of the header is not too short.
+ if (!AccelSectionData.isValidOffset(AccelTable.getSizeHdr())) {
+ error() << "Section is too small to fit a section header.\n";
+ return 1;
+ }
+
+ // Verify that the section is not too short.
+ if (Error E = AccelTable.extract()) {
+ error() << toString(std::move(E)) << '\n';
+ return 1;
+ }
+
+ // Verify that all buckets have a valid hash index or are empty.
+ uint32_t NumBuckets = AccelTable.getNumBuckets();
+ uint32_t NumHashes = AccelTable.getNumHashes();
+
+ uint64_t BucketsOffset =
+ AccelTable.getSizeHdr() + AccelTable.getHeaderDataLength();
+ uint64_t HashesBase = BucketsOffset + NumBuckets * 4;
+ uint64_t OffsetsBase = HashesBase + NumHashes * 4;
+ for (uint32_t BucketIdx = 0; BucketIdx < NumBuckets; ++BucketIdx) {
+ uint32_t HashIdx = AccelSectionData.getU32(&BucketsOffset);
+ if (HashIdx >= NumHashes && HashIdx != UINT32_MAX) {
+ error() << format("Bucket[%d] has invalid hash index: %u.\n", BucketIdx,
+ HashIdx);
+ ++NumErrors;
+ }
+ }
+ uint32_t NumAtoms = AccelTable.getAtomsDesc().size();
+ if (NumAtoms == 0) {
+ error() << "No atoms: failed to read HashData.\n";
+ return 1;
+ }
+ if (!AccelTable.validateForms()) {
+ error() << "Unsupported form: failed to read HashData.\n";
+ return 1;
+ }
+
+ for (uint32_t HashIdx = 0; HashIdx < NumHashes; ++HashIdx) {
+ uint64_t HashOffset = HashesBase + 4 * HashIdx;
+ uint64_t DataOffset = OffsetsBase + 4 * HashIdx;
+ uint32_t Hash = AccelSectionData.getU32(&HashOffset);
+ uint64_t HashDataOffset = AccelSectionData.getU32(&DataOffset);
+ if (!AccelSectionData.isValidOffsetForDataOfSize(HashDataOffset,
+ sizeof(uint64_t))) {
+ error() << format("Hash[%d] has invalid HashData offset: "
+ "0x%08" PRIx64 ".\n",
+ HashIdx, HashDataOffset);
+ ++NumErrors;
+ }
+
+ uint64_t StrpOffset;
+ uint64_t StringOffset;
+ uint32_t StringCount = 0;
+ uint64_t Offset;
+ unsigned Tag;
+ while ((StrpOffset = AccelSectionData.getU32(&HashDataOffset)) != 0) {
+ const uint32_t NumHashDataObjects =
+ AccelSectionData.getU32(&HashDataOffset);
+ for (uint32_t HashDataIdx = 0; HashDataIdx < NumHashDataObjects;
+ ++HashDataIdx) {
+ std::tie(Offset, Tag) = AccelTable.readAtoms(&HashDataOffset);
+ auto Die = DCtx.getDIEForOffset(Offset);
+ if (!Die) {
+ const uint32_t BucketIdx =
+ NumBuckets ? (Hash % NumBuckets) : UINT32_MAX;
+ StringOffset = StrpOffset;
+ const char *Name = StrData->getCStr(&StringOffset);
+ if (!Name)
+ Name = "<NULL>";
+
+ error() << format(
+ "%s Bucket[%d] Hash[%d] = 0x%08x "
+ "Str[%u] = 0x%08" PRIx64 " DIE[%d] = 0x%08" PRIx64 " "
+ "is not a valid DIE offset for \"%s\".\n",
+ SectionName, BucketIdx, HashIdx, Hash, StringCount, StrpOffset,
+ HashDataIdx, Offset, Name);
+
+ ++NumErrors;
+ continue;
+ }
+ if ((Tag != dwarf::DW_TAG_null) && (Die.getTag() != Tag)) {
+ error() << "Tag " << dwarf::TagString(Tag)
+ << " in accelerator table does not match Tag "
+ << dwarf::TagString(Die.getTag()) << " of DIE[" << HashDataIdx
+ << "].\n";
+ ++NumErrors;
+ }
+ }
+ ++StringCount;
+ }
+ }
+ return NumErrors;
+}
+
+unsigned
+DWARFVerifier::verifyDebugNamesCULists(const DWARFDebugNames &AccelTable) {
+ // A map from CU offset to the (first) Name Index offset which claims to index
+ // this CU.
+ DenseMap<uint64_t, uint64_t> CUMap;
+ const uint64_t NotIndexed = std::numeric_limits<uint64_t>::max();
+
+ CUMap.reserve(DCtx.getNumCompileUnits());
+ for (const auto &CU : DCtx.compile_units())
+ CUMap[CU->getOffset()] = NotIndexed;
+
+ unsigned NumErrors = 0;
+ for (const DWARFDebugNames::NameIndex &NI : AccelTable) {
+ if (NI.getCUCount() == 0) {
+ error() << formatv("Name Index @ {0:x} does not index any CU\n",
+ NI.getUnitOffset());
+ ++NumErrors;
+ continue;
+ }
+ for (uint32_t CU = 0, End = NI.getCUCount(); CU < End; ++CU) {
+ uint64_t Offset = NI.getCUOffset(CU);
+ auto Iter = CUMap.find(Offset);
+
+ if (Iter == CUMap.end()) {
+ error() << formatv(
+ "Name Index @ {0:x} references a non-existing CU @ {1:x}\n",
+ NI.getUnitOffset(), Offset);
+ ++NumErrors;
+ continue;
+ }
+
+ if (Iter->second != NotIndexed) {
+ error() << formatv("Name Index @ {0:x} references a CU @ {1:x}, but "
+ "this CU is already indexed by Name Index @ {2:x}\n",
+ NI.getUnitOffset(), Offset, Iter->second);
+ continue;
+ }
+ Iter->second = NI.getUnitOffset();
+ }
+ }
+
+ for (const auto &KV : CUMap) {
+ if (KV.second == NotIndexed)
+ warn() << formatv("CU @ {0:x} not covered by any Name Index\n", KV.first);
+ }
+
+ return NumErrors;
+}
+
+unsigned
+DWARFVerifier::verifyNameIndexBuckets(const DWARFDebugNames::NameIndex &NI,
+ const DataExtractor &StrData) {
+ struct BucketInfo {
+ uint32_t Bucket;
+ uint32_t Index;
+
+ constexpr BucketInfo(uint32_t Bucket, uint32_t Index)
+ : Bucket(Bucket), Index(Index) {}
+ bool operator<(const BucketInfo &RHS) const { return Index < RHS.Index; }
+ };
+
+ uint32_t NumErrors = 0;
+ if (NI.getBucketCount() == 0) {
+ warn() << formatv("Name Index @ {0:x} does not contain a hash table.\n",
+ NI.getUnitOffset());
+ return NumErrors;
+ }
+
+ // Build up a list of (Bucket, Index) pairs. We use this later to verify that
+ // each Name is reachable from the appropriate bucket.
+ std::vector<BucketInfo> BucketStarts;
+ BucketStarts.reserve(NI.getBucketCount() + 1);
+ for (uint32_t Bucket = 0, End = NI.getBucketCount(); Bucket < End; ++Bucket) {
+ uint32_t Index = NI.getBucketArrayEntry(Bucket);
+ if (Index > NI.getNameCount()) {
+ error() << formatv("Bucket {0} of Name Index @ {1:x} contains invalid "
+ "value {2}. Valid range is [0, {3}].\n",
+ Bucket, NI.getUnitOffset(), Index, NI.getNameCount());
+ ++NumErrors;
+ continue;
+ }
+ if (Index > 0)
+ BucketStarts.emplace_back(Bucket, Index);
+ }
+
+ // If there were any buckets with invalid values, skip further checks as they
+ // will likely produce many errors which will only confuse the actual root
+ // problem.
+ if (NumErrors > 0)
+ return NumErrors;
+
+ // Sort the list in the order of increasing "Index" entries.
+ array_pod_sort(BucketStarts.begin(), BucketStarts.end());
+
+ // Insert a sentinel entry at the end, so we can check that the end of the
+ // table is covered in the loop below.
+ BucketStarts.emplace_back(NI.getBucketCount(), NI.getNameCount() + 1);
+
+ // Loop invariant: NextUncovered is the (1-based) index of the first Name
+ // which is not reachable by any of the buckets we processed so far (and
+ // hasn't been reported as uncovered).
+ uint32_t NextUncovered = 1;
+ for (const BucketInfo &B : BucketStarts) {
+ // Under normal circumstances B.Index be equal to NextUncovered, but it can
+ // be less if a bucket points to names which are already known to be in some
+ // bucket we processed earlier. In that case, we won't trigger this error,
+ // but report the mismatched hash value error instead. (We know the hash
+ // will not match because we have already verified that the name's hash
+ // puts it into the previous bucket.)
+ if (B.Index > NextUncovered) {
+ error() << formatv("Name Index @ {0:x}: Name table entries [{1}, {2}] "
+ "are not covered by the hash table.\n",
+ NI.getUnitOffset(), NextUncovered, B.Index - 1);
+ ++NumErrors;
+ }
+ uint32_t Idx = B.Index;
+
+ // The rest of the checks apply only to non-sentinel entries.
+ if (B.Bucket == NI.getBucketCount())
+ break;
+
+ // This triggers if a non-empty bucket points to a name with a mismatched
+ // hash. Clients are likely to interpret this as an empty bucket, because a
+ // mismatched hash signals the end of a bucket, but if this is indeed an
+ // empty bucket, the producer should have signalled this by marking the
+ // bucket as empty.
+ uint32_t FirstHash = NI.getHashArrayEntry(Idx);
+ if (FirstHash % NI.getBucketCount() != B.Bucket) {
+ error() << formatv(
+ "Name Index @ {0:x}: Bucket {1} is not empty but points to a "
+ "mismatched hash value {2:x} (belonging to bucket {3}).\n",
+ NI.getUnitOffset(), B.Bucket, FirstHash,
+ FirstHash % NI.getBucketCount());
+ ++NumErrors;
+ }
+
+ // This find the end of this bucket and also verifies that all the hashes in
+ // this bucket are correct by comparing the stored hashes to the ones we
+ // compute ourselves.
+ while (Idx <= NI.getNameCount()) {
+ uint32_t Hash = NI.getHashArrayEntry(Idx);
+ if (Hash % NI.getBucketCount() != B.Bucket)
+ break;
+
+ const char *Str = NI.getNameTableEntry(Idx).getString();
+ if (caseFoldingDjbHash(Str) != Hash) {
+ error() << formatv("Name Index @ {0:x}: String ({1}) at index {2} "
+ "hashes to {3:x}, but "
+ "the Name Index hash is {4:x}\n",
+ NI.getUnitOffset(), Str, Idx,
+ caseFoldingDjbHash(Str), Hash);
+ ++NumErrors;
+ }
+
+ ++Idx;
+ }
+ NextUncovered = std::max(NextUncovered, Idx);
+ }
+ return NumErrors;
+}
+
+unsigned DWARFVerifier::verifyNameIndexAttribute(
+ const DWARFDebugNames::NameIndex &NI, const DWARFDebugNames::Abbrev &Abbr,
+ DWARFDebugNames::AttributeEncoding AttrEnc) {
+ StringRef FormName = dwarf::FormEncodingString(AttrEnc.Form);
+ if (FormName.empty()) {
+ error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
+ "unknown form: {3}.\n",
+ NI.getUnitOffset(), Abbr.Code, AttrEnc.Index,
+ AttrEnc.Form);
+ return 1;
+ }
+
+ if (AttrEnc.Index == DW_IDX_type_hash) {
+ if (AttrEnc.Form != dwarf::DW_FORM_data8) {
+ error() << formatv(
+ "NameIndex @ {0:x}: Abbreviation {1:x}: DW_IDX_type_hash "
+ "uses an unexpected form {2} (should be {3}).\n",
+ NI.getUnitOffset(), Abbr.Code, AttrEnc.Form, dwarf::DW_FORM_data8);
+ return 1;
+ }
+ }
+
+ // A list of known index attributes and their expected form classes.
+ // DW_IDX_type_hash is handled specially in the check above, as it has a
+ // specific form (not just a form class) we should expect.
+ struct FormClassTable {
+ dwarf::Index Index;
+ DWARFFormValue::FormClass Class;
+ StringLiteral ClassName;
+ };
+ static constexpr FormClassTable Table[] = {
+ {dwarf::DW_IDX_compile_unit, DWARFFormValue::FC_Constant, {"constant"}},
+ {dwarf::DW_IDX_type_unit, DWARFFormValue::FC_Constant, {"constant"}},
+ {dwarf::DW_IDX_die_offset, DWARFFormValue::FC_Reference, {"reference"}},
+ {dwarf::DW_IDX_parent, DWARFFormValue::FC_Constant, {"constant"}},
+ };
+
+ ArrayRef<FormClassTable> TableRef(Table);
+ auto Iter = find_if(TableRef, [AttrEnc](const FormClassTable &T) {
+ return T.Index == AttrEnc.Index;
+ });
+ if (Iter == TableRef.end()) {
+ warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains an "
+ "unknown index attribute: {2}.\n",
+ NI.getUnitOffset(), Abbr.Code, AttrEnc.Index);
+ return 0;
+ }
+
+ if (!DWARFFormValue(AttrEnc.Form).isFormClass(Iter->Class)) {
+ error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x}: {2} uses an "
+ "unexpected form {3} (expected form class {4}).\n",
+ NI.getUnitOffset(), Abbr.Code, AttrEnc.Index,
+ AttrEnc.Form, Iter->ClassName);
+ return 1;
+ }
+ return 0;
+}
+
+unsigned
+DWARFVerifier::verifyNameIndexAbbrevs(const DWARFDebugNames::NameIndex &NI) {
+ if (NI.getLocalTUCount() + NI.getForeignTUCount() > 0) {
+ warn() << formatv("Name Index @ {0:x}: Verifying indexes of type units is "
+ "not currently supported.\n",
+ NI.getUnitOffset());
+ return 0;
+ }
+
+ unsigned NumErrors = 0;
+ for (const auto &Abbrev : NI.getAbbrevs()) {
+ StringRef TagName = dwarf::TagString(Abbrev.Tag);
+ if (TagName.empty()) {
+ warn() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} references an "
+ "unknown tag: {2}.\n",
+ NI.getUnitOffset(), Abbrev.Code, Abbrev.Tag);
+ }
+ SmallSet<unsigned, 5> Attributes;
+ for (const auto &AttrEnc : Abbrev.Attributes) {
+ if (!Attributes.insert(AttrEnc.Index).second) {
+ error() << formatv("NameIndex @ {0:x}: Abbreviation {1:x} contains "
+ "multiple {2} attributes.\n",
+ NI.getUnitOffset(), Abbrev.Code, AttrEnc.Index);
+ ++NumErrors;
+ continue;
+ }
+ NumErrors += verifyNameIndexAttribute(NI, Abbrev, AttrEnc);
+ }
+
+ if (NI.getCUCount() > 1 && !Attributes.count(dwarf::DW_IDX_compile_unit)) {
+ error() << formatv("NameIndex @ {0:x}: Indexing multiple compile units "
+ "and abbreviation {1:x} has no {2} attribute.\n",
+ NI.getUnitOffset(), Abbrev.Code,
+ dwarf::DW_IDX_compile_unit);
+ ++NumErrors;
+ }
+ if (!Attributes.count(dwarf::DW_IDX_die_offset)) {
+ error() << formatv(
+ "NameIndex @ {0:x}: Abbreviation {1:x} has no {2} attribute.\n",
+ NI.getUnitOffset(), Abbrev.Code, dwarf::DW_IDX_die_offset);
+ ++NumErrors;
+ }
+ }
+ return NumErrors;
+}
+
+static SmallVector<StringRef, 2> getNames(const DWARFDie &DIE,
+ bool IncludeLinkageName = true) {
+ SmallVector<StringRef, 2> Result;
+ if (const char *Str = DIE.getShortName())
+ Result.emplace_back(Str);
+ else if (DIE.getTag() == dwarf::DW_TAG_namespace)
+ Result.emplace_back("(anonymous namespace)");
+
+ if (IncludeLinkageName) {
+ if (const char *Str = DIE.getLinkageName())
+ Result.emplace_back(Str);
+ }
+
+ return Result;
+}
+
+unsigned DWARFVerifier::verifyNameIndexEntries(
+ const DWARFDebugNames::NameIndex &NI,
+ const DWARFDebugNames::NameTableEntry &NTE) {
+ // Verifying type unit indexes not supported.
+ if (NI.getLocalTUCount() + NI.getForeignTUCount() > 0)
+ return 0;
+
+ const char *CStr = NTE.getString();
+ if (!CStr) {
+ error() << formatv(
+ "Name Index @ {0:x}: Unable to get string associated with name {1}.\n",
+ NI.getUnitOffset(), NTE.getIndex());
+ return 1;
+ }
+ StringRef Str(CStr);
+
+ unsigned NumErrors = 0;
+ unsigned NumEntries = 0;
+ uint64_t EntryID = NTE.getEntryOffset();
+ uint64_t NextEntryID = EntryID;
+ Expected<DWARFDebugNames::Entry> EntryOr = NI.getEntry(&NextEntryID);
+ for (; EntryOr; ++NumEntries, EntryID = NextEntryID,
+ EntryOr = NI.getEntry(&NextEntryID)) {
+ uint32_t CUIndex = *EntryOr->getCUIndex();
+ if (CUIndex > NI.getCUCount()) {
+ error() << formatv("Name Index @ {0:x}: Entry @ {1:x} contains an "
+ "invalid CU index ({2}).\n",
+ NI.getUnitOffset(), EntryID, CUIndex);
+ ++NumErrors;
+ continue;
+ }
+ uint64_t CUOffset = NI.getCUOffset(CUIndex);
+ uint64_t DIEOffset = CUOffset + *EntryOr->getDIEUnitOffset();
+ DWARFDie DIE = DCtx.getDIEForOffset(DIEOffset);
+ if (!DIE) {
+ error() << formatv("Name Index @ {0:x}: Entry @ {1:x} references a "
+ "non-existing DIE @ {2:x}.\n",
+ NI.getUnitOffset(), EntryID, DIEOffset);
+ ++NumErrors;
+ continue;
+ }
+ if (DIE.getDwarfUnit()->getOffset() != CUOffset) {
+ error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched CU of "
+ "DIE @ {2:x}: index - {3:x}; debug_info - {4:x}.\n",
+ NI.getUnitOffset(), EntryID, DIEOffset, CUOffset,
+ DIE.getDwarfUnit()->getOffset());
+ ++NumErrors;
+ }
+ if (DIE.getTag() != EntryOr->tag()) {
+ error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Tag of "
+ "DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
+ NI.getUnitOffset(), EntryID, DIEOffset, EntryOr->tag(),
+ DIE.getTag());
+ ++NumErrors;
+ }
+
+ auto EntryNames = getNames(DIE);
+ if (!is_contained(EntryNames, Str)) {
+ error() << formatv("Name Index @ {0:x}: Entry @ {1:x}: mismatched Name "
+ "of DIE @ {2:x}: index - {3}; debug_info - {4}.\n",
+ NI.getUnitOffset(), EntryID, DIEOffset, Str,
+ make_range(EntryNames.begin(), EntryNames.end()));
+ ++NumErrors;
+ }
+ }
+ handleAllErrors(EntryOr.takeError(),
+ [&](const DWARFDebugNames::SentinelError &) {
+ if (NumEntries > 0)
+ return;
+ error() << formatv("Name Index @ {0:x}: Name {1} ({2}) is "
+ "not associated with any entries.\n",
+ NI.getUnitOffset(), NTE.getIndex(), Str);
+ ++NumErrors;
+ },
+ [&](const ErrorInfoBase &Info) {
+ error()
+ << formatv("Name Index @ {0:x}: Name {1} ({2}): {3}\n",
+ NI.getUnitOffset(), NTE.getIndex(), Str,
+ Info.message());
+ ++NumErrors;
+ });
+ return NumErrors;
+}
+
+static bool isVariableIndexable(const DWARFDie &Die, DWARFContext &DCtx) {
+ Expected<std::vector<DWARFLocationExpression>> Loc =
+ Die.getLocations(DW_AT_location);
+ if (!Loc) {
+ consumeError(Loc.takeError());
+ return false;
+ }
+ DWARFUnit *U = Die.getDwarfUnit();
+ for (const auto &Entry : *Loc) {
+ DataExtractor Data(toStringRef(Entry.Expr), DCtx.isLittleEndian(),
+ U->getAddressByteSize());
+ DWARFExpression Expression(Data, U->getAddressByteSize(),
+ U->getFormParams().Format);
+ bool IsInteresting =
+ any_of(Expression, [](const DWARFExpression::Operation &Op) {
+ return !Op.isError() && (Op.getCode() == DW_OP_addr ||
+ Op.getCode() == DW_OP_form_tls_address ||
+ Op.getCode() == DW_OP_GNU_push_tls_address);
+ });
+ if (IsInteresting)
+ return true;
+ }
+ return false;
+}
+
+unsigned DWARFVerifier::verifyNameIndexCompleteness(
+ const DWARFDie &Die, const DWARFDebugNames::NameIndex &NI) {
+
+ // First check, if the Die should be indexed. The code follows the DWARF v5
+ // wording as closely as possible.
+
+ // "All non-defining declarations (that is, debugging information entries
+ // with a DW_AT_declaration attribute) are excluded."
+ if (Die.find(DW_AT_declaration))
+ return 0;
+
+ // "DW_TAG_namespace debugging information entries without a DW_AT_name
+ // attribute are included with the name “(anonymous namespace)”.
+ // All other debugging information entries without a DW_AT_name attribute
+ // are excluded."
+ // "If a subprogram or inlined subroutine is included, and has a
+ // DW_AT_linkage_name attribute, there will be an additional index entry for
+ // the linkage name."
+ auto IncludeLinkageName = Die.getTag() == DW_TAG_subprogram ||
+ Die.getTag() == DW_TAG_inlined_subroutine;
+ auto EntryNames = getNames(Die, IncludeLinkageName);
+ if (EntryNames.empty())
+ return 0;
+
+ // We deviate from the specification here, which says:
+ // "The name index must contain an entry for each debugging information entry
+ // that defines a named subprogram, label, variable, type, or namespace,
+ // subject to ..."
+ // Explicitly exclude all TAGs that we know shouldn't be indexed.
+ switch (Die.getTag()) {
+ // Compile units and modules have names but shouldn't be indexed.
+ case DW_TAG_compile_unit:
+ case DW_TAG_module:
+ return 0;
+
+ // Function and template parameters are not globally visible, so we shouldn't
+ // index them.
+ case DW_TAG_formal_parameter:
+ case DW_TAG_template_value_parameter:
+ case DW_TAG_template_type_parameter:
+ case DW_TAG_GNU_template_parameter_pack:
+ case DW_TAG_GNU_template_template_param:
+ return 0;
+
+ // Object members aren't globally visible.
+ case DW_TAG_member:
+ return 0;
+
+ // According to a strict reading of the specification, enumerators should not
+ // be indexed (and LLVM currently does not do that). However, this causes
+ // problems for the debuggers, so we may need to reconsider this.
+ case DW_TAG_enumerator:
+ return 0;
+
+ // Imported declarations should not be indexed according to the specification
+ // and LLVM currently does not do that.
+ case DW_TAG_imported_declaration:
+ return 0;
+
+ // "DW_TAG_subprogram, DW_TAG_inlined_subroutine, and DW_TAG_label debugging
+ // information entries without an address attribute (DW_AT_low_pc,
+ // DW_AT_high_pc, DW_AT_ranges, or DW_AT_entry_pc) are excluded."
+ case DW_TAG_subprogram:
+ case DW_TAG_inlined_subroutine:
+ case DW_TAG_label:
+ if (Die.findRecursively(
+ {DW_AT_low_pc, DW_AT_high_pc, DW_AT_ranges, DW_AT_entry_pc}))
+ break;
+ return 0;
+
+ // "DW_TAG_variable debugging information entries with a DW_AT_location
+ // attribute that includes a DW_OP_addr or DW_OP_form_tls_address operator are
+ // included; otherwise, they are excluded."
+ //
+ // LLVM extension: We also add DW_OP_GNU_push_tls_address to this list.
+ case DW_TAG_variable:
+ if (isVariableIndexable(Die, DCtx))
+ break;
+ return 0;
+
+ default:
+ break;
+ }
+
+ // Now we know that our Die should be present in the Index. Let's check if
+ // that's the case.
+ unsigned NumErrors = 0;
+ uint64_t DieUnitOffset = Die.getOffset() - Die.getDwarfUnit()->getOffset();
+ for (StringRef Name : EntryNames) {
+ if (none_of(NI.equal_range(Name), [&](const DWARFDebugNames::Entry &E) {
+ return E.getDIEUnitOffset() == DieUnitOffset;
+ })) {
+ error() << formatv("Name Index @ {0:x}: Entry for DIE @ {1:x} ({2}) with "
+ "name {3} missing.\n",
+ NI.getUnitOffset(), Die.getOffset(), Die.getTag(),
+ Name);
+ ++NumErrors;
+ }
+ }
+ return NumErrors;
+}
+
+unsigned DWARFVerifier::verifyDebugNames(const DWARFSection &AccelSection,
+ const DataExtractor &StrData) {
+ unsigned NumErrors = 0;
+ DWARFDataExtractor AccelSectionData(DCtx.getDWARFObj(), AccelSection,
+ DCtx.isLittleEndian(), 0);
+ DWARFDebugNames AccelTable(AccelSectionData, StrData);
+
+ OS << "Verifying .debug_names...\n";
+
+ // This verifies that we can read individual name indices and their
+ // abbreviation tables.
+ if (Error E = AccelTable.extract()) {
+ error() << toString(std::move(E)) << '\n';
+ return 1;
+ }
+
+ NumErrors += verifyDebugNamesCULists(AccelTable);
+ for (const auto &NI : AccelTable)
+ NumErrors += verifyNameIndexBuckets(NI, StrData);
+ for (const auto &NI : AccelTable)
+ NumErrors += verifyNameIndexAbbrevs(NI);
+
+ // Don't attempt Entry validation if any of the previous checks found errors
+ if (NumErrors > 0)
+ return NumErrors;
+ for (const auto &NI : AccelTable)
+ for (const DWARFDebugNames::NameTableEntry &NTE : NI)
+ NumErrors += verifyNameIndexEntries(NI, NTE);
+
+ if (NumErrors > 0)
+ return NumErrors;
+
+ for (const std::unique_ptr<DWARFUnit> &U : DCtx.compile_units()) {
+ if (const DWARFDebugNames::NameIndex *NI =
+ AccelTable.getCUNameIndex(U->getOffset())) {
+ auto *CU = cast<DWARFCompileUnit>(U.get());
+ for (const DWARFDebugInfoEntry &Die : CU->dies())
+ NumErrors += verifyNameIndexCompleteness(DWARFDie(CU, &Die), *NI);
+ }
+ }
+ return NumErrors;
+}
+
+bool DWARFVerifier::handleAccelTables() {
+ const DWARFObject &D = DCtx.getDWARFObj();
+ DataExtractor StrData(D.getStrSection(), DCtx.isLittleEndian(), 0);
+ unsigned NumErrors = 0;
+ if (!D.getAppleNamesSection().Data.empty())
+ NumErrors += verifyAppleAccelTable(&D.getAppleNamesSection(), &StrData,
+ ".apple_names");
+ if (!D.getAppleTypesSection().Data.empty())
+ NumErrors += verifyAppleAccelTable(&D.getAppleTypesSection(), &StrData,
+ ".apple_types");
+ if (!D.getAppleNamespacesSection().Data.empty())
+ NumErrors += verifyAppleAccelTable(&D.getAppleNamespacesSection(), &StrData,
+ ".apple_namespaces");
+ if (!D.getAppleObjCSection().Data.empty())
+ NumErrors += verifyAppleAccelTable(&D.getAppleObjCSection(), &StrData,
+ ".apple_objc");
+
+ if (!D.getNamesSection().Data.empty())
+ NumErrors += verifyDebugNames(D.getNamesSection(), StrData);
+ return NumErrors == 0;
+}
+
+raw_ostream &DWARFVerifier::error() const { return WithColor::error(OS); }
+
+raw_ostream &DWARFVerifier::warn() const { return WithColor::warning(OS); }
+
+raw_ostream &DWARFVerifier::note() const { return WithColor::note(OS); }
+
+raw_ostream &DWARFVerifier::dump(const DWARFDie &Die, unsigned indent) const {
+ Die.dump(OS, indent, DumpOpts);
+ return OS;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/DWARF/ya.make b/contrib/libs/llvm14/lib/DebugInfo/DWARF/ya.make
new file mode 100644
index 0000000000..20dc24f025
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/DWARF/ya.make
@@ -0,0 +1,56 @@
+# Generated by devtools/yamaker.
+
+LIBRARY()
+
+LICENSE(Apache-2.0 WITH LLVM-exception)
+
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
+PEERDIR(
+ contrib/libs/llvm14
+ contrib/libs/llvm14/lib/BinaryFormat
+ contrib/libs/llvm14/lib/MC
+ contrib/libs/llvm14/lib/Object
+ contrib/libs/llvm14/lib/Support
+)
+
+ADDINCL(
+ contrib/libs/llvm14/lib/DebugInfo/DWARF
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ DWARFAbbreviationDeclaration.cpp
+ DWARFAcceleratorTable.cpp
+ DWARFAddressRange.cpp
+ DWARFCompileUnit.cpp
+ DWARFContext.cpp
+ DWARFDataExtractor.cpp
+ DWARFDebugAbbrev.cpp
+ DWARFDebugAddr.cpp
+ DWARFDebugArangeSet.cpp
+ DWARFDebugAranges.cpp
+ DWARFDebugFrame.cpp
+ DWARFDebugInfoEntry.cpp
+ DWARFDebugLine.cpp
+ DWARFDebugLoc.cpp
+ DWARFDebugMacro.cpp
+ DWARFDebugPubTable.cpp
+ DWARFDebugRangeList.cpp
+ DWARFDebugRnglists.cpp
+ DWARFDie.cpp
+ DWARFExpression.cpp
+ DWARFFormValue.cpp
+ DWARFGdbIndex.cpp
+ DWARFListTable.cpp
+ DWARFLocationExpression.cpp
+ DWARFTypeUnit.cpp
+ DWARFUnit.cpp
+ DWARFUnitIndex.cpp
+ DWARFVerifier.cpp
+)
+
+END()
diff --git a/contrib/libs/llvm14/lib/DebugInfo/GSYM/DwarfTransformer.cpp b/contrib/libs/llvm14/lib/DebugInfo/GSYM/DwarfTransformer.cpp
new file mode 100644
index 0000000000..6eef6f84ab
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/GSYM/DwarfTransformer.cpp
@@ -0,0 +1,575 @@
+//===- DwarfTransformer.cpp -----------------------------------------------===//
+//
+// 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 <thread>
+#include <unordered_set>
+
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ThreadPool.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "llvm/DebugInfo/GSYM/DwarfTransformer.h"
+#include "llvm/DebugInfo/GSYM/FunctionInfo.h"
+#include "llvm/DebugInfo/GSYM/GsymCreator.h"
+#include "llvm/DebugInfo/GSYM/GsymReader.h"
+#include "llvm/DebugInfo/GSYM/InlineInfo.h"
+
+using namespace llvm;
+using namespace gsym;
+
+struct llvm::gsym::CUInfo {
+ const DWARFDebugLine::LineTable *LineTable;
+ const char *CompDir;
+ std::vector<uint32_t> FileCache;
+ uint64_t Language = 0;
+ uint8_t AddrSize = 0;
+
+ CUInfo(DWARFContext &DICtx, DWARFCompileUnit *CU) {
+ LineTable = DICtx.getLineTableForUnit(CU);
+ CompDir = CU->getCompilationDir();
+ FileCache.clear();
+ if (LineTable)
+ FileCache.assign(LineTable->Prologue.FileNames.size() + 1, UINT32_MAX);
+ DWARFDie Die = CU->getUnitDIE();
+ Language = dwarf::toUnsigned(Die.find(dwarf::DW_AT_language), 0);
+ AddrSize = CU->getAddressByteSize();
+ }
+
+ /// Return true if Addr is the highest address for a given compile unit. The
+ /// highest address is encoded as -1, of all ones in the address. These high
+ /// addresses are used by some linkers to indicate that a function has been
+ /// dead stripped or didn't end up in the linked executable.
+ bool isHighestAddress(uint64_t Addr) const {
+ if (AddrSize == 4)
+ return Addr == UINT32_MAX;
+ else if (AddrSize == 8)
+ return Addr == UINT64_MAX;
+ return false;
+ }
+
+ /// Convert a DWARF compile unit file index into a GSYM global file index.
+ ///
+ /// Each compile unit in DWARF has its own file table in the line table
+ /// prologue. GSYM has a single large file table that applies to all files
+ /// from all of the info in a GSYM file. This function converts between the
+ /// two and caches and DWARF CU file index that has already been converted so
+ /// the first client that asks for a compile unit file index will end up
+ /// doing the conversion, and subsequent clients will get the cached GSYM
+ /// index.
+ uint32_t DWARFToGSYMFileIndex(GsymCreator &Gsym, uint32_t DwarfFileIdx) {
+ if (!LineTable)
+ return 0;
+ assert(DwarfFileIdx < FileCache.size());
+ uint32_t &GsymFileIdx = FileCache[DwarfFileIdx];
+ if (GsymFileIdx != UINT32_MAX)
+ return GsymFileIdx;
+ std::string File;
+ if (LineTable->getFileNameByIndex(
+ DwarfFileIdx, CompDir,
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath, File))
+ GsymFileIdx = Gsym.insertFile(File);
+ else
+ GsymFileIdx = 0;
+ return GsymFileIdx;
+ }
+};
+
+
+static DWARFDie GetParentDeclContextDIE(DWARFDie &Die) {
+ if (DWARFDie SpecDie =
+ Die.getAttributeValueAsReferencedDie(dwarf::DW_AT_specification)) {
+ if (DWARFDie SpecParent = GetParentDeclContextDIE(SpecDie))
+ return SpecParent;
+ }
+ if (DWARFDie AbstDie =
+ Die.getAttributeValueAsReferencedDie(dwarf::DW_AT_abstract_origin)) {
+ if (DWARFDie AbstParent = GetParentDeclContextDIE(AbstDie))
+ return AbstParent;
+ }
+
+ // We never want to follow parent for inlined subroutine - that would
+ // give us information about where the function is inlined, not what
+ // function is inlined
+ if (Die.getTag() == dwarf::DW_TAG_inlined_subroutine)
+ return DWARFDie();
+
+ DWARFDie ParentDie = Die.getParent();
+ if (!ParentDie)
+ return DWARFDie();
+
+ switch (ParentDie.getTag()) {
+ case dwarf::DW_TAG_namespace:
+ case dwarf::DW_TAG_structure_type:
+ case dwarf::DW_TAG_union_type:
+ case dwarf::DW_TAG_class_type:
+ case dwarf::DW_TAG_subprogram:
+ return ParentDie; // Found parent decl context DIE
+ case dwarf::DW_TAG_lexical_block:
+ return GetParentDeclContextDIE(ParentDie);
+ default:
+ break;
+ }
+
+ return DWARFDie();
+}
+
+/// Get the GsymCreator string table offset for the qualified name for the
+/// DIE passed in. This function will avoid making copies of any strings in
+/// the GsymCreator when possible. We don't need to copy a string when the
+/// string comes from our .debug_str section or is an inlined string in the
+/// .debug_info. If we create a qualified name string in this function by
+/// combining multiple strings in the DWARF string table or info, we will make
+/// a copy of the string when we add it to the string table.
+static Optional<uint32_t> getQualifiedNameIndex(DWARFDie &Die,
+ uint64_t Language,
+ GsymCreator &Gsym) {
+ // If the dwarf has mangled name, use mangled name
+ if (auto LinkageName =
+ dwarf::toString(Die.findRecursively({dwarf::DW_AT_MIPS_linkage_name,
+ dwarf::DW_AT_linkage_name}),
+ nullptr))
+ return Gsym.insertString(LinkageName, /* Copy */ false);
+
+ StringRef ShortName(Die.getName(DINameKind::ShortName));
+ if (ShortName.empty())
+ return llvm::None;
+
+ // For C++ and ObjC, prepend names of all parent declaration contexts
+ if (!(Language == dwarf::DW_LANG_C_plus_plus ||
+ Language == dwarf::DW_LANG_C_plus_plus_03 ||
+ Language == dwarf::DW_LANG_C_plus_plus_11 ||
+ Language == dwarf::DW_LANG_C_plus_plus_14 ||
+ Language == dwarf::DW_LANG_ObjC_plus_plus ||
+ // This should not be needed for C, but we see C++ code marked as C
+ // in some binaries. This should hurt, so let's do it for C as well
+ Language == dwarf::DW_LANG_C))
+ return Gsym.insertString(ShortName, /* Copy */ false);
+
+ // Some GCC optimizations create functions with names ending with .isra.<num>
+ // or .part.<num> and those names are just DW_AT_name, not DW_AT_linkage_name
+ // If it looks like it could be the case, don't add any prefix
+ if (ShortName.startswith("_Z") &&
+ (ShortName.contains(".isra.") || ShortName.contains(".part.")))
+ return Gsym.insertString(ShortName, /* Copy */ false);
+
+ DWARFDie ParentDeclCtxDie = GetParentDeclContextDIE(Die);
+ if (ParentDeclCtxDie) {
+ std::string Name = ShortName.str();
+ while (ParentDeclCtxDie) {
+ StringRef ParentName(ParentDeclCtxDie.getName(DINameKind::ShortName));
+ if (!ParentName.empty()) {
+ // "lambda" names are wrapped in < >. Replace with { }
+ // to be consistent with demangled names and not to confuse with
+ // templates
+ if (ParentName.front() == '<' && ParentName.back() == '>')
+ Name = "{" + ParentName.substr(1, ParentName.size() - 2).str() + "}" +
+ "::" + Name;
+ else
+ Name = ParentName.str() + "::" + Name;
+ }
+ ParentDeclCtxDie = GetParentDeclContextDIE(ParentDeclCtxDie);
+ }
+ // Copy the name since we created a new name in a std::string.
+ return Gsym.insertString(Name, /* Copy */ true);
+ }
+ // Don't copy the name since it exists in the DWARF object file.
+ return Gsym.insertString(ShortName, /* Copy */ false);
+}
+
+static bool hasInlineInfo(DWARFDie Die, uint32_t Depth) {
+ bool CheckChildren = true;
+ switch (Die.getTag()) {
+ case dwarf::DW_TAG_subprogram:
+ // Don't look into functions within functions.
+ CheckChildren = Depth == 0;
+ break;
+ case dwarf::DW_TAG_inlined_subroutine:
+ return true;
+ default:
+ break;
+ }
+ if (!CheckChildren)
+ return false;
+ for (DWARFDie ChildDie : Die.children()) {
+ if (hasInlineInfo(ChildDie, Depth + 1))
+ return true;
+ }
+ return false;
+}
+
+static void parseInlineInfo(GsymCreator &Gsym, CUInfo &CUI, DWARFDie Die,
+ uint32_t Depth, FunctionInfo &FI,
+ InlineInfo &parent) {
+ if (!hasInlineInfo(Die, Depth))
+ return;
+
+ dwarf::Tag Tag = Die.getTag();
+ if (Tag == dwarf::DW_TAG_inlined_subroutine) {
+ // create new InlineInfo and append to parent.children
+ InlineInfo II;
+ DWARFAddressRange FuncRange =
+ DWARFAddressRange(FI.startAddress(), FI.endAddress());
+ Expected<DWARFAddressRangesVector> RangesOrError = Die.getAddressRanges();
+ if (RangesOrError) {
+ for (const DWARFAddressRange &Range : RangesOrError.get()) {
+ // Check that the inlined function is within the range of the function
+ // info, it might not be in case of split functions
+ if (FuncRange.LowPC <= Range.LowPC && Range.HighPC <= FuncRange.HighPC)
+ II.Ranges.insert(AddressRange(Range.LowPC, Range.HighPC));
+ }
+ }
+ if (II.Ranges.empty())
+ return;
+
+ if (auto NameIndex = getQualifiedNameIndex(Die, CUI.Language, Gsym))
+ II.Name = *NameIndex;
+ II.CallFile = CUI.DWARFToGSYMFileIndex(
+ Gsym, dwarf::toUnsigned(Die.find(dwarf::DW_AT_call_file), 0));
+ II.CallLine = dwarf::toUnsigned(Die.find(dwarf::DW_AT_call_line), 0);
+ // parse all children and append to parent
+ for (DWARFDie ChildDie : Die.children())
+ parseInlineInfo(Gsym, CUI, ChildDie, Depth + 1, FI, II);
+ parent.Children.emplace_back(std::move(II));
+ return;
+ }
+ if (Tag == dwarf::DW_TAG_subprogram || Tag == dwarf::DW_TAG_lexical_block) {
+ // skip this Die and just recurse down
+ for (DWARFDie ChildDie : Die.children())
+ parseInlineInfo(Gsym, CUI, ChildDie, Depth + 1, FI, parent);
+ }
+}
+
+static void convertFunctionLineTable(raw_ostream &Log, CUInfo &CUI,
+ DWARFDie Die, GsymCreator &Gsym,
+ FunctionInfo &FI) {
+ std::vector<uint32_t> RowVector;
+ const uint64_t StartAddress = FI.startAddress();
+ const uint64_t EndAddress = FI.endAddress();
+ const uint64_t RangeSize = EndAddress - StartAddress;
+ const object::SectionedAddress SecAddress{
+ StartAddress, object::SectionedAddress::UndefSection};
+
+
+ if (!CUI.LineTable->lookupAddressRange(SecAddress, RangeSize, RowVector)) {
+ // If we have a DW_TAG_subprogram but no line entries, fall back to using
+ // the DW_AT_decl_file an d DW_AT_decl_line if we have both attributes.
+ std::string FilePath = Die.getDeclFile(
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath);
+ if (FilePath.empty())
+ return;
+ if (auto Line =
+ dwarf::toUnsigned(Die.findRecursively({dwarf::DW_AT_decl_line}))) {
+ LineEntry LE(StartAddress, Gsym.insertFile(FilePath), *Line);
+ FI.OptLineTable = LineTable();
+ FI.OptLineTable->push(LE);
+ }
+ return;
+ }
+
+ FI.OptLineTable = LineTable();
+ DWARFDebugLine::Row PrevRow;
+ for (uint32_t RowIndex : RowVector) {
+ // Take file number and line/column from the row.
+ const DWARFDebugLine::Row &Row = CUI.LineTable->Rows[RowIndex];
+ const uint32_t FileIdx = CUI.DWARFToGSYMFileIndex(Gsym, Row.File);
+ uint64_t RowAddress = Row.Address.Address;
+ // Watch out for a RowAddress that is in the middle of a line table entry
+ // in the DWARF. If we pass an address in between two line table entries
+ // we will get a RowIndex for the previous valid line table row which won't
+ // be contained in our function. This is usually a bug in the DWARF due to
+ // linker problems or LTO or other DWARF re-linking so it is worth emitting
+ // an error, but not worth stopping the creation of the GSYM.
+ if (!FI.Range.contains(RowAddress)) {
+ if (RowAddress < FI.Range.Start) {
+ Log << "error: DIE has a start address whose LowPC is between the "
+ "line table Row[" << RowIndex << "] with address "
+ << HEX64(RowAddress) << " and the next one.\n";
+ Die.dump(Log, 0, DIDumpOptions::getForSingleDIE());
+ RowAddress = FI.Range.Start;
+ } else {
+ continue;
+ }
+ }
+
+ LineEntry LE(RowAddress, FileIdx, Row.Line);
+ if (RowIndex != RowVector[0] && Row.Address < PrevRow.Address) {
+ // We have seen full duplicate line tables for functions in some
+ // DWARF files. Watch for those here by checking the the last
+ // row was the function's end address (HighPC) and that the
+ // current line table entry's address is the same as the first
+ // line entry we already have in our "function_info.Lines". If
+ // so break out after printing a warning.
+ auto FirstLE = FI.OptLineTable->first();
+ if (FirstLE && *FirstLE == LE) {
+ if (!Gsym.isQuiet()) {
+ Log << "warning: duplicate line table detected for DIE:\n";
+ Die.dump(Log, 0, DIDumpOptions::getForSingleDIE());
+ }
+ } else {
+ // Print out (ignore if os == nulls as this is expensive)
+ Log << "error: line table has addresses that do not "
+ << "monotonically increase:\n";
+ for (uint32_t RowIndex2 : RowVector) {
+ CUI.LineTable->Rows[RowIndex2].dump(Log);
+ }
+ Die.dump(Log, 0, DIDumpOptions::getForSingleDIE());
+ }
+ break;
+ }
+
+ // Skip multiple line entries for the same file and line.
+ auto LastLE = FI.OptLineTable->last();
+ if (LastLE && LastLE->File == FileIdx && LastLE->Line == Row.Line)
+ continue;
+ // Only push a row if it isn't an end sequence. End sequence markers are
+ // included for the last address in a function or the last contiguous
+ // address in a sequence.
+ if (Row.EndSequence) {
+ // End sequence means that the next line entry could have a lower address
+ // that the previous entries. So we clear the previous row so we don't
+ // trigger the line table error about address that do not monotonically
+ // increase.
+ PrevRow = DWARFDebugLine::Row();
+ } else {
+ FI.OptLineTable->push(LE);
+ PrevRow = Row;
+ }
+ }
+ // If not line table rows were added, clear the line table so we don't encode
+ // on in the GSYM file.
+ if (FI.OptLineTable->empty())
+ FI.OptLineTable = llvm::None;
+}
+
+void DwarfTransformer::handleDie(raw_ostream &OS, CUInfo &CUI, DWARFDie Die) {
+ switch (Die.getTag()) {
+ case dwarf::DW_TAG_subprogram: {
+ Expected<DWARFAddressRangesVector> RangesOrError = Die.getAddressRanges();
+ if (!RangesOrError) {
+ consumeError(RangesOrError.takeError());
+ break;
+ }
+ const DWARFAddressRangesVector &Ranges = RangesOrError.get();
+ if (Ranges.empty())
+ break;
+ auto NameIndex = getQualifiedNameIndex(Die, CUI.Language, Gsym);
+ if (!NameIndex) {
+ OS << "error: function at " << HEX64(Die.getOffset())
+ << " has no name\n ";
+ Die.dump(OS, 0, DIDumpOptions::getForSingleDIE());
+ break;
+ }
+
+ // Create a function_info for each range
+ for (const DWARFAddressRange &Range : Ranges) {
+ // The low PC must be less than the high PC. Many linkers don't remove
+ // DWARF for functions that don't get linked into the final executable.
+ // If both the high and low pc have relocations, linkers will often set
+ // the address values for both to the same value to indicate the function
+ // has been remove. Other linkers have been known to set the one or both
+ // PC values to a UINT32_MAX for 4 byte addresses and UINT64_MAX for 8
+ // byte addresses to indicate the function isn't valid. The check below
+ // tries to watch for these cases and abort if it runs into them.
+ if (Range.LowPC >= Range.HighPC || CUI.isHighestAddress(Range.LowPC))
+ break;
+
+ // Many linkers can't remove DWARF and might set the LowPC to zero. Since
+ // high PC can be an offset from the low PC in more recent DWARF versions
+ // we need to watch for a zero'ed low pc which we do using
+ // ValidTextRanges below.
+ if (!Gsym.IsValidTextAddress(Range.LowPC)) {
+ // We expect zero and -1 to be invalid addresses in DWARF depending
+ // on the linker of the DWARF. This indicates a function was stripped
+ // and the debug info wasn't able to be stripped from the DWARF. If
+ // the LowPC isn't zero or -1, then we should emit an error.
+ if (Range.LowPC != 0) {
+ if (!Gsym.isQuiet()) {
+ // Unexpected invalid address, emit a warning
+ OS << "warning: DIE has an address range whose start address is "
+ "not in any executable sections ("
+ << *Gsym.GetValidTextRanges()
+ << ") and will not be processed:\n";
+ Die.dump(OS, 0, DIDumpOptions::getForSingleDIE());
+ }
+ }
+ break;
+ }
+
+ FunctionInfo FI;
+ FI.setStartAddress(Range.LowPC);
+ FI.setEndAddress(Range.HighPC);
+ FI.Name = *NameIndex;
+ if (CUI.LineTable) {
+ convertFunctionLineTable(OS, CUI, Die, Gsym, FI);
+ }
+ if (hasInlineInfo(Die, 0)) {
+ FI.Inline = InlineInfo();
+ FI.Inline->Name = *NameIndex;
+ FI.Inline->Ranges.insert(FI.Range);
+ parseInlineInfo(Gsym, CUI, Die, 0, FI, *FI.Inline);
+ }
+ Gsym.addFunctionInfo(std::move(FI));
+ }
+ } break;
+ default:
+ break;
+ }
+ for (DWARFDie ChildDie : Die.children())
+ handleDie(OS, CUI, ChildDie);
+}
+
+Error DwarfTransformer::convert(uint32_t NumThreads) {
+ size_t NumBefore = Gsym.getNumFunctionInfos();
+ if (NumThreads == 1) {
+ // Parse all DWARF data from this thread, use the same string/file table
+ // for everything
+ for (const auto &CU : DICtx.compile_units()) {
+ DWARFDie Die = CU->getUnitDIE(false);
+ CUInfo CUI(DICtx, dyn_cast<DWARFCompileUnit>(CU.get()));
+ handleDie(Log, CUI, Die);
+ }
+ } else {
+ // LLVM Dwarf parser is not thread-safe and we need to parse all DWARF up
+ // front before we start accessing any DIEs since there might be
+ // cross compile unit references in the DWARF. If we don't do this we can
+ // end up crashing.
+
+ // We need to call getAbbreviations sequentially first so that getUnitDIE()
+ // only works with its local data.
+ for (const auto &CU : DICtx.compile_units())
+ CU->getAbbreviations();
+
+ // Now parse all DIEs in case we have cross compile unit references in a
+ // thread pool.
+ ThreadPool pool(hardware_concurrency(NumThreads));
+ for (const auto &CU : DICtx.compile_units())
+ pool.async([&CU]() { CU->getUnitDIE(false /*CUDieOnly*/); });
+ pool.wait();
+
+ // Now convert all DWARF to GSYM in a thread pool.
+ std::mutex LogMutex;
+ for (const auto &CU : DICtx.compile_units()) {
+ DWARFDie Die = CU->getUnitDIE(false /*CUDieOnly*/);
+ if (Die) {
+ CUInfo CUI(DICtx, dyn_cast<DWARFCompileUnit>(CU.get()));
+ pool.async([this, CUI, &LogMutex, Die]() mutable {
+ std::string ThreadLogStorage;
+ raw_string_ostream ThreadOS(ThreadLogStorage);
+ handleDie(ThreadOS, CUI, Die);
+ ThreadOS.flush();
+ if (!ThreadLogStorage.empty()) {
+ // Print ThreadLogStorage lines into an actual stream under a lock
+ std::lock_guard<std::mutex> guard(LogMutex);
+ Log << ThreadLogStorage;
+ }
+ });
+ }
+ }
+ pool.wait();
+ }
+ size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
+ Log << "Loaded " << FunctionsAddedCount << " functions from DWARF.\n";
+ return Error::success();
+}
+
+llvm::Error DwarfTransformer::verify(StringRef GsymPath) {
+ Log << "Verifying GSYM file \"" << GsymPath << "\":\n";
+
+ auto Gsym = GsymReader::openFile(GsymPath);
+ if (!Gsym)
+ return Gsym.takeError();
+
+ auto NumAddrs = Gsym->getNumAddresses();
+ DILineInfoSpecifier DLIS(
+ DILineInfoSpecifier::FileLineInfoKind::AbsoluteFilePath,
+ DILineInfoSpecifier::FunctionNameKind::LinkageName);
+ std::string gsymFilename;
+ for (uint32_t I = 0; I < NumAddrs; ++I) {
+ auto FuncAddr = Gsym->getAddress(I);
+ if (!FuncAddr)
+ return createStringError(std::errc::invalid_argument,
+ "failed to extract address[%i]", I);
+
+ auto FI = Gsym->getFunctionInfo(*FuncAddr);
+ if (!FI)
+ return createStringError(std::errc::invalid_argument,
+ "failed to extract function info for address 0x%"
+ PRIu64, *FuncAddr);
+
+ for (auto Addr = *FuncAddr; Addr < *FuncAddr + FI->size(); ++Addr) {
+ const object::SectionedAddress SectAddr{
+ Addr, object::SectionedAddress::UndefSection};
+ auto LR = Gsym->lookup(Addr);
+ if (!LR)
+ return LR.takeError();
+
+ auto DwarfInlineInfos =
+ DICtx.getInliningInfoForAddress(SectAddr, DLIS);
+ uint32_t NumDwarfInlineInfos = DwarfInlineInfos.getNumberOfFrames();
+ if (NumDwarfInlineInfos == 0) {
+ DwarfInlineInfos.addFrame(
+ DICtx.getLineInfoForAddress(SectAddr, DLIS));
+ }
+
+ // Check for 1 entry that has no file and line info
+ if (NumDwarfInlineInfos == 1 &&
+ DwarfInlineInfos.getFrame(0).FileName == "<invalid>") {
+ DwarfInlineInfos = DIInliningInfo();
+ NumDwarfInlineInfos = 0;
+ }
+ if (NumDwarfInlineInfos > 0 &&
+ NumDwarfInlineInfos != LR->Locations.size()) {
+ Log << "error: address " << HEX64(Addr) << " has "
+ << NumDwarfInlineInfos << " DWARF inline frames and GSYM has "
+ << LR->Locations.size() << "\n";
+ Log << " " << NumDwarfInlineInfos << " DWARF frames:\n";
+ for (size_t Idx = 0; Idx < NumDwarfInlineInfos; ++Idx) {
+ const auto &dii = DwarfInlineInfos.getFrame(Idx);
+ Log << " [" << Idx << "]: " << dii.FunctionName << " @ "
+ << dii.FileName << ':' << dii.Line << '\n';
+ }
+ Log << " " << LR->Locations.size() << " GSYM frames:\n";
+ for (size_t Idx = 0, count = LR->Locations.size();
+ Idx < count; ++Idx) {
+ const auto &gii = LR->Locations[Idx];
+ Log << " [" << Idx << "]: " << gii.Name << " @ " << gii.Dir
+ << '/' << gii.Base << ':' << gii.Line << '\n';
+ }
+ DwarfInlineInfos = DICtx.getInliningInfoForAddress(SectAddr, DLIS);
+ Gsym->dump(Log, *FI);
+ continue;
+ }
+
+ for (size_t Idx = 0, count = LR->Locations.size(); Idx < count;
+ ++Idx) {
+ const auto &gii = LR->Locations[Idx];
+ if (Idx < NumDwarfInlineInfos) {
+ const auto &dii = DwarfInlineInfos.getFrame(Idx);
+ gsymFilename = LR->getSourceFile(Idx);
+ // Verify function name
+ if (dii.FunctionName.find(gii.Name.str()) != 0)
+ Log << "error: address " << HEX64(Addr) << " DWARF function \""
+ << dii.FunctionName.c_str()
+ << "\" doesn't match GSYM function \"" << gii.Name << "\"\n";
+ // Verify source file path
+ if (dii.FileName != gsymFilename)
+ Log << "error: address " << HEX64(Addr) << " DWARF path \""
+ << dii.FileName.c_str() << "\" doesn't match GSYM path \""
+ << gsymFilename.c_str() << "\"\n";
+ // Verify source file line
+ if (dii.Line != gii.Line)
+ Log << "error: address " << HEX64(Addr) << " DWARF line "
+ << dii.Line << " != GSYM line " << gii.Line << "\n";
+ }
+ }
+ }
+ }
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/GSYM/FileWriter.cpp b/contrib/libs/llvm14/lib/DebugInfo/GSYM/FileWriter.cpp
new file mode 100644
index 0000000000..b725f3ac74
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/GSYM/FileWriter.cpp
@@ -0,0 +1,77 @@
+//===- FileWriter.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/GSYM/FileWriter.h"
+#include "llvm/Support/LEB128.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cassert>
+
+using namespace llvm;
+using namespace gsym;
+
+FileWriter::~FileWriter() { OS.flush(); }
+
+void FileWriter::writeSLEB(int64_t S) {
+ uint8_t Bytes[32];
+ auto Length = encodeSLEB128(S, Bytes);
+ assert(Length < sizeof(Bytes));
+ OS.write(reinterpret_cast<const char *>(Bytes), Length);
+}
+
+void FileWriter::writeULEB(uint64_t U) {
+ uint8_t Bytes[32];
+ auto Length = encodeULEB128(U, Bytes);
+ assert(Length < sizeof(Bytes));
+ OS.write(reinterpret_cast<const char *>(Bytes), Length);
+}
+
+void FileWriter::writeU8(uint8_t U) {
+ OS.write(reinterpret_cast<const char *>(&U), sizeof(U));
+}
+
+void FileWriter::writeU16(uint16_t U) {
+ const uint16_t Swapped = support::endian::byte_swap(U, ByteOrder);
+ OS.write(reinterpret_cast<const char *>(&Swapped), sizeof(Swapped));
+}
+
+void FileWriter::writeU32(uint32_t U) {
+ const uint32_t Swapped = support::endian::byte_swap(U, ByteOrder);
+ OS.write(reinterpret_cast<const char *>(&Swapped), sizeof(Swapped));
+}
+
+void FileWriter::writeU64(uint64_t U) {
+ const uint64_t Swapped = support::endian::byte_swap(U, ByteOrder);
+ OS.write(reinterpret_cast<const char *>(&Swapped), sizeof(Swapped));
+}
+
+void FileWriter::fixup32(uint32_t U, uint64_t Offset) {
+ const uint32_t Swapped = support::endian::byte_swap(U, ByteOrder);
+ OS.pwrite(reinterpret_cast<const char *>(&Swapped), sizeof(Swapped),
+ Offset);
+}
+
+void FileWriter::writeData(llvm::ArrayRef<uint8_t> Data) {
+ OS.write(reinterpret_cast<const char *>(Data.data()), Data.size());
+}
+
+void FileWriter::writeNullTerminated(llvm::StringRef Str) {
+ OS << Str << '\0';
+}
+
+uint64_t FileWriter::tell() {
+ return OS.tell();
+}
+
+void FileWriter::alignTo(size_t Align) {
+ off_t Offset = OS.tell();
+ off_t AlignedOffset = (Offset + Align - 1) / Align * Align;
+ if (AlignedOffset == Offset)
+ return;
+ off_t PadCount = AlignedOffset - Offset;
+ OS.write_zeros(PadCount);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/GSYM/FunctionInfo.cpp b/contrib/libs/llvm14/lib/DebugInfo/GSYM/FunctionInfo.cpp
new file mode 100644
index 0000000000..cef1b9498c
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/GSYM/FunctionInfo.cpp
@@ -0,0 +1,254 @@
+//===- FunctionInfo.cpp ---------------------------------------------------===//
+//
+// 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/GSYM/FunctionInfo.h"
+#include "llvm/DebugInfo/GSYM/FileWriter.h"
+#include "llvm/DebugInfo/GSYM/GsymReader.h"
+#include "llvm/DebugInfo/GSYM/LineTable.h"
+#include "llvm/DebugInfo/GSYM/InlineInfo.h"
+#include "llvm/Support/DataExtractor.h"
+
+using namespace llvm;
+using namespace gsym;
+
+/// FunctionInfo information type that is used to encode the optional data
+/// that is associated with a FunctionInfo object.
+enum InfoType : uint32_t {
+ EndOfList = 0u,
+ LineTableInfo = 1u,
+ InlineInfo = 2u
+};
+
+raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const FunctionInfo &FI) {
+ OS << FI.Range << ": " << "Name=" << HEX32(FI.Name) << '\n';
+ if (FI.OptLineTable)
+ OS << FI.OptLineTable << '\n';
+ if (FI.Inline)
+ OS << FI.Inline << '\n';
+ return OS;
+}
+
+llvm::Expected<FunctionInfo> FunctionInfo::decode(DataExtractor &Data,
+ uint64_t BaseAddr) {
+ FunctionInfo FI;
+ FI.Range.Start = BaseAddr;
+ uint64_t Offset = 0;
+ if (!Data.isValidOffsetForDataOfSize(Offset, 4))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": missing FunctionInfo Size", Offset);
+ FI.Range.End = FI.Range.Start + Data.getU32(&Offset);
+ if (!Data.isValidOffsetForDataOfSize(Offset, 4))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": missing FunctionInfo Name", Offset);
+ FI.Name = Data.getU32(&Offset);
+ if (FI.Name == 0)
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": invalid FunctionInfo Name value 0x%8.8x",
+ Offset - 4, FI.Name);
+ bool Done = false;
+ while (!Done) {
+ if (!Data.isValidOffsetForDataOfSize(Offset, 4))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": missing FunctionInfo InfoType value", Offset);
+ const uint32_t IT = Data.getU32(&Offset);
+ if (!Data.isValidOffsetForDataOfSize(Offset, 4))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": missing FunctionInfo InfoType length", Offset);
+ const uint32_t InfoLength = Data.getU32(&Offset);
+ if (!Data.isValidOffsetForDataOfSize(Offset, InfoLength))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": missing FunctionInfo data for InfoType %u",
+ Offset, IT);
+ DataExtractor InfoData(Data.getData().substr(Offset, InfoLength),
+ Data.isLittleEndian(),
+ Data.getAddressSize());
+ switch (IT) {
+ case InfoType::EndOfList:
+ Done = true;
+ break;
+
+ case InfoType::LineTableInfo:
+ if (Expected<LineTable> LT = LineTable::decode(InfoData, BaseAddr))
+ FI.OptLineTable = std::move(LT.get());
+ else
+ return LT.takeError();
+ break;
+
+ case InfoType::InlineInfo:
+ if (Expected<InlineInfo> II = InlineInfo::decode(InfoData, BaseAddr))
+ FI.Inline = std::move(II.get());
+ else
+ return II.takeError();
+ break;
+
+ default:
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": unsupported InfoType %u",
+ Offset-8, IT);
+ }
+ Offset += InfoLength;
+ }
+ return std::move(FI);
+}
+
+llvm::Expected<uint64_t> FunctionInfo::encode(FileWriter &O) const {
+ if (!isValid())
+ return createStringError(std::errc::invalid_argument,
+ "attempted to encode invalid FunctionInfo object");
+ // Align FunctionInfo data to a 4 byte alignment.
+ O.alignTo(4);
+ const uint64_t FuncInfoOffset = O.tell();
+ // Write the size in bytes of this function as a uint32_t. This can be zero
+ // if we just have a symbol from a symbol table and that symbol has no size.
+ O.writeU32(size());
+ // Write the name of this function as a uint32_t string table offset.
+ O.writeU32(Name);
+
+ if (OptLineTable.hasValue()) {
+ O.writeU32(InfoType::LineTableInfo);
+ // Write a uint32_t length as zero for now, we will fix this up after
+ // writing the LineTable out with the number of bytes that were written.
+ O.writeU32(0);
+ const auto StartOffset = O.tell();
+ llvm::Error err = OptLineTable->encode(O, Range.Start);
+ if (err)
+ return std::move(err);
+ const auto Length = O.tell() - StartOffset;
+ if (Length > UINT32_MAX)
+ return createStringError(std::errc::invalid_argument,
+ "LineTable length is greater than UINT32_MAX");
+ // Fixup the size of the LineTable data with the correct size.
+ O.fixup32(static_cast<uint32_t>(Length), StartOffset - 4);
+ }
+
+ // Write out the inline function info if we have any and if it is valid.
+ if (Inline.hasValue()) {
+ O.writeU32(InfoType::InlineInfo);
+ // Write a uint32_t length as zero for now, we will fix this up after
+ // writing the LineTable out with the number of bytes that were written.
+ O.writeU32(0);
+ const auto StartOffset = O.tell();
+ llvm::Error err = Inline->encode(O, Range.Start);
+ if (err)
+ return std::move(err);
+ const auto Length = O.tell() - StartOffset;
+ if (Length > UINT32_MAX)
+ return createStringError(std::errc::invalid_argument,
+ "InlineInfo length is greater than UINT32_MAX");
+ // Fixup the size of the InlineInfo data with the correct size.
+ O.fixup32(static_cast<uint32_t>(Length), StartOffset - 4);
+ }
+
+ // Terminate the data chunks with and end of list with zero size
+ O.writeU32(InfoType::EndOfList);
+ O.writeU32(0);
+ return FuncInfoOffset;
+}
+
+
+llvm::Expected<LookupResult> FunctionInfo::lookup(DataExtractor &Data,
+ const GsymReader &GR,
+ uint64_t FuncAddr,
+ uint64_t Addr) {
+ LookupResult LR;
+ LR.LookupAddr = Addr;
+ LR.FuncRange.Start = FuncAddr;
+ uint64_t Offset = 0;
+ LR.FuncRange.End = FuncAddr + Data.getU32(&Offset);
+ uint32_t NameOffset = Data.getU32(&Offset);
+ // The "lookup" functions doesn't report errors as accurately as the "decode"
+ // function as it is meant to be fast. For more accurage errors we could call
+ // "decode".
+ if (!Data.isValidOffset(Offset))
+ return createStringError(std::errc::io_error,
+ "FunctionInfo data is truncated");
+ // This function will be called with the result of a binary search of the
+ // address table, we must still make sure the address does not fall into a
+ // gap between functions are after the last function.
+ if (LR.FuncRange.size() > 0 && !LR.FuncRange.contains(Addr))
+ return createStringError(std::errc::io_error,
+ "address 0x%" PRIx64 " is not in GSYM", Addr);
+
+ if (NameOffset == 0)
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": invalid FunctionInfo Name value 0x00000000",
+ Offset - 4);
+ LR.FuncName = GR.getString(NameOffset);
+ bool Done = false;
+ Optional<LineEntry> LineEntry;
+ Optional<DataExtractor> InlineInfoData;
+ while (!Done) {
+ if (!Data.isValidOffsetForDataOfSize(Offset, 8))
+ return createStringError(std::errc::io_error,
+ "FunctionInfo data is truncated");
+ const uint32_t IT = Data.getU32(&Offset);
+ const uint32_t InfoLength = Data.getU32(&Offset);
+ const StringRef InfoBytes = Data.getData().substr(Offset, InfoLength);
+ if (InfoLength != InfoBytes.size())
+ return createStringError(std::errc::io_error,
+ "FunctionInfo data is truncated");
+ DataExtractor InfoData(InfoBytes, Data.isLittleEndian(),
+ Data.getAddressSize());
+ switch (IT) {
+ case InfoType::EndOfList:
+ Done = true;
+ break;
+
+ case InfoType::LineTableInfo:
+ if (auto ExpectedLE = LineTable::lookup(InfoData, FuncAddr, Addr))
+ LineEntry = ExpectedLE.get();
+ else
+ return ExpectedLE.takeError();
+ break;
+
+ case InfoType::InlineInfo:
+ // We will parse the inline info after our line table, but only if
+ // we have a line entry.
+ InlineInfoData = InfoData;
+ break;
+
+ default:
+ break;
+ }
+ Offset += InfoLength;
+ }
+
+ if (!LineEntry) {
+ // We don't have a valid line entry for our address, fill in our source
+ // location as best we can and return.
+ SourceLocation SrcLoc;
+ SrcLoc.Name = LR.FuncName;
+ SrcLoc.Offset = Addr - FuncAddr;
+ LR.Locations.push_back(SrcLoc);
+ return LR;
+ }
+
+ Optional<FileEntry> LineEntryFile = GR.getFile(LineEntry->File);
+ if (!LineEntryFile)
+ return createStringError(std::errc::invalid_argument,
+ "failed to extract file[%" PRIu32 "]",
+ LineEntry->File);
+
+ SourceLocation SrcLoc;
+ SrcLoc.Name = LR.FuncName;
+ SrcLoc.Offset = Addr - FuncAddr;
+ SrcLoc.Dir = GR.getString(LineEntryFile->Dir);
+ SrcLoc.Base = GR.getString(LineEntryFile->Base);
+ SrcLoc.Line = LineEntry->Line;
+ LR.Locations.push_back(SrcLoc);
+ // If we don't have inline information, we are done.
+ if (!InlineInfoData)
+ return LR;
+ // We have inline information. Try to augment the lookup result with this
+ // data.
+ llvm::Error Err = InlineInfo::lookup(GR, *InlineInfoData, FuncAddr, Addr,
+ LR.Locations);
+ if (Err)
+ return std::move(Err);
+ return LR;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/GSYM/GsymCreator.cpp b/contrib/libs/llvm14/lib/DebugInfo/GSYM/GsymCreator.cpp
new file mode 100644
index 0000000000..1c20a59469
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/GSYM/GsymCreator.cpp
@@ -0,0 +1,362 @@
+//===- GsymCreator.cpp ----------------------------------------------------===//
+//
+// 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/GSYM/GsymCreator.h"
+#include "llvm/DebugInfo/GSYM/FileWriter.h"
+#include "llvm/DebugInfo/GSYM/Header.h"
+#include "llvm/DebugInfo/GSYM/LineTable.h"
+#include "llvm/MC/StringTableBuilder.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include <algorithm>
+#include <cassert>
+#include <functional>
+#include <vector>
+
+using namespace llvm;
+using namespace gsym;
+
+GsymCreator::GsymCreator(bool Quiet)
+ : StrTab(StringTableBuilder::ELF), Quiet(Quiet) {
+ insertFile(StringRef());
+}
+
+uint32_t GsymCreator::insertFile(StringRef Path, llvm::sys::path::Style Style) {
+ llvm::StringRef directory = llvm::sys::path::parent_path(Path, Style);
+ llvm::StringRef filename = llvm::sys::path::filename(Path, Style);
+ // We must insert the strings first, then call the FileEntry constructor.
+ // If we inline the insertString() function call into the constructor, the
+ // call order is undefined due to parameter lists not having any ordering
+ // requirements.
+ const uint32_t Dir = insertString(directory);
+ const uint32_t Base = insertString(filename);
+ FileEntry FE(Dir, Base);
+
+ std::lock_guard<std::mutex> Guard(Mutex);
+ const auto NextIndex = Files.size();
+ // Find FE in hash map and insert if not present.
+ auto R = FileEntryToIndex.insert(std::make_pair(FE, NextIndex));
+ if (R.second)
+ Files.emplace_back(FE);
+ return R.first->second;
+}
+
+llvm::Error GsymCreator::save(StringRef Path,
+ llvm::support::endianness ByteOrder) const {
+ std::error_code EC;
+ raw_fd_ostream OutStrm(Path, EC);
+ if (EC)
+ return llvm::errorCodeToError(EC);
+ FileWriter O(OutStrm, ByteOrder);
+ return encode(O);
+}
+
+llvm::Error GsymCreator::encode(FileWriter &O) const {
+ std::lock_guard<std::mutex> Guard(Mutex);
+ if (Funcs.empty())
+ return createStringError(std::errc::invalid_argument,
+ "no functions to encode");
+ if (!Finalized)
+ return createStringError(std::errc::invalid_argument,
+ "GsymCreator wasn't finalized prior to encoding");
+
+ if (Funcs.size() > UINT32_MAX)
+ return createStringError(std::errc::invalid_argument,
+ "too many FunctionInfos");
+
+ const uint64_t MinAddr =
+ BaseAddress ? *BaseAddress : Funcs.front().startAddress();
+ const uint64_t MaxAddr = Funcs.back().startAddress();
+ const uint64_t AddrDelta = MaxAddr - MinAddr;
+ Header Hdr;
+ Hdr.Magic = GSYM_MAGIC;
+ Hdr.Version = GSYM_VERSION;
+ Hdr.AddrOffSize = 0;
+ Hdr.UUIDSize = static_cast<uint8_t>(UUID.size());
+ Hdr.BaseAddress = MinAddr;
+ Hdr.NumAddresses = static_cast<uint32_t>(Funcs.size());
+ Hdr.StrtabOffset = 0; // We will fix this up later.
+ Hdr.StrtabSize = 0; // We will fix this up later.
+ memset(Hdr.UUID, 0, sizeof(Hdr.UUID));
+ if (UUID.size() > sizeof(Hdr.UUID))
+ return createStringError(std::errc::invalid_argument,
+ "invalid UUID size %u", (uint32_t)UUID.size());
+ // Set the address offset size correctly in the GSYM header.
+ if (AddrDelta <= UINT8_MAX)
+ Hdr.AddrOffSize = 1;
+ else if (AddrDelta <= UINT16_MAX)
+ Hdr.AddrOffSize = 2;
+ else if (AddrDelta <= UINT32_MAX)
+ Hdr.AddrOffSize = 4;
+ else
+ Hdr.AddrOffSize = 8;
+ // Copy the UUID value if we have one.
+ if (UUID.size() > 0)
+ memcpy(Hdr.UUID, UUID.data(), UUID.size());
+ // Write out the header.
+ llvm::Error Err = Hdr.encode(O);
+ if (Err)
+ return Err;
+
+ // Write out the address offsets.
+ O.alignTo(Hdr.AddrOffSize);
+ for (const auto &FuncInfo : Funcs) {
+ uint64_t AddrOffset = FuncInfo.startAddress() - Hdr.BaseAddress;
+ switch (Hdr.AddrOffSize) {
+ case 1:
+ O.writeU8(static_cast<uint8_t>(AddrOffset));
+ break;
+ case 2:
+ O.writeU16(static_cast<uint16_t>(AddrOffset));
+ break;
+ case 4:
+ O.writeU32(static_cast<uint32_t>(AddrOffset));
+ break;
+ case 8:
+ O.writeU64(AddrOffset);
+ break;
+ }
+ }
+
+ // Write out all zeros for the AddrInfoOffsets.
+ O.alignTo(4);
+ const off_t AddrInfoOffsetsOffset = O.tell();
+ for (size_t i = 0, n = Funcs.size(); i < n; ++i)
+ O.writeU32(0);
+
+ // Write out the file table
+ O.alignTo(4);
+ assert(!Files.empty());
+ assert(Files[0].Dir == 0);
+ assert(Files[0].Base == 0);
+ size_t NumFiles = Files.size();
+ if (NumFiles > UINT32_MAX)
+ return createStringError(std::errc::invalid_argument, "too many files");
+ O.writeU32(static_cast<uint32_t>(NumFiles));
+ for (auto File : Files) {
+ O.writeU32(File.Dir);
+ O.writeU32(File.Base);
+ }
+
+ // Write out the sting table.
+ const off_t StrtabOffset = O.tell();
+ StrTab.write(O.get_stream());
+ const off_t StrtabSize = O.tell() - StrtabOffset;
+ std::vector<uint32_t> AddrInfoOffsets;
+
+ // Write out the address infos for each function info.
+ for (const auto &FuncInfo : Funcs) {
+ if (Expected<uint64_t> OffsetOrErr = FuncInfo.encode(O))
+ AddrInfoOffsets.push_back(OffsetOrErr.get());
+ else
+ return OffsetOrErr.takeError();
+ }
+ // Fixup the string table offset and size in the header
+ O.fixup32((uint32_t)StrtabOffset, offsetof(Header, StrtabOffset));
+ O.fixup32((uint32_t)StrtabSize, offsetof(Header, StrtabSize));
+
+ // Fixup all address info offsets
+ uint64_t Offset = 0;
+ for (auto AddrInfoOffset : AddrInfoOffsets) {
+ O.fixup32(AddrInfoOffset, AddrInfoOffsetsOffset + Offset);
+ Offset += 4;
+ }
+ return ErrorSuccess();
+}
+
+// Similar to std::remove_if, but the predicate is binary and it is passed both
+// the previous and the current element.
+template <class ForwardIt, class BinaryPredicate>
+static ForwardIt removeIfBinary(ForwardIt FirstIt, ForwardIt LastIt,
+ BinaryPredicate Pred) {
+ if (FirstIt != LastIt) {
+ auto PrevIt = FirstIt++;
+ FirstIt = std::find_if(FirstIt, LastIt, [&](const auto &Curr) {
+ return Pred(*PrevIt++, Curr);
+ });
+ if (FirstIt != LastIt)
+ for (ForwardIt CurrIt = FirstIt; ++CurrIt != LastIt;)
+ if (!Pred(*PrevIt, *CurrIt)) {
+ PrevIt = FirstIt;
+ *FirstIt++ = std::move(*CurrIt);
+ }
+ }
+ return FirstIt;
+}
+
+llvm::Error GsymCreator::finalize(llvm::raw_ostream &OS) {
+ std::lock_guard<std::mutex> Guard(Mutex);
+ if (Finalized)
+ return createStringError(std::errc::invalid_argument, "already finalized");
+ Finalized = true;
+
+ // Sort function infos so we can emit sorted functions.
+ llvm::sort(Funcs);
+
+ // Don't let the string table indexes change by finalizing in order.
+ StrTab.finalizeInOrder();
+
+ // Remove duplicates function infos that have both entries from debug info
+ // (DWARF or Breakpad) and entries from the SymbolTable.
+ //
+ // Also handle overlapping function. Usually there shouldn't be any, but they
+ // can and do happen in some rare cases.
+ //
+ // (a) (b) (c)
+ // ^ ^ ^ ^
+ // |X |Y |X ^ |X
+ // | | | |Y | ^
+ // | | | v v |Y
+ // v v v v
+ //
+ // In (a) and (b), Y is ignored and X will be reported for the full range.
+ // In (c), both functions will be included in the result and lookups for an
+ // address in the intersection will return Y because of binary search.
+ //
+ // Note that in case of (b), we cannot include Y in the result because then
+ // we wouldn't find any function for range (end of Y, end of X)
+ // with binary search
+ auto NumBefore = Funcs.size();
+ Funcs.erase(
+ removeIfBinary(Funcs.begin(), Funcs.end(),
+ [&](const auto &Prev, const auto &Curr) {
+ // Empty ranges won't intersect, but we still need to
+ // catch the case where we have multiple symbols at the
+ // same address and coalesce them.
+ const bool ranges_equal = Prev.Range == Curr.Range;
+ if (ranges_equal || Prev.Range.intersects(Curr.Range)) {
+ // Overlapping ranges or empty identical ranges.
+ if (ranges_equal) {
+ // Same address range. Check if one is from debug
+ // info and the other is from a symbol table. If
+ // so, then keep the one with debug info. Our
+ // sorting guarantees that entries with matching
+ // address ranges that have debug info are last in
+ // the sort.
+ if (Prev == Curr) {
+ // FunctionInfo entries match exactly (range,
+ // lines, inlines)
+
+ // We used to output a warning here, but this was
+ // so frequent on some binaries, in particular
+ // when those were built with GCC, that it slowed
+ // down processing extremely.
+ return true;
+ } else {
+ if (!Prev.hasRichInfo() && Curr.hasRichInfo()) {
+ // Same address range, one with no debug info
+ // (symbol) and the next with debug info. Keep
+ // the latter.
+ return true;
+ } else {
+ if (!Quiet) {
+ OS << "warning: same address range contains "
+ "different debug "
+ << "info. Removing:\n"
+ << Prev << "\nIn favor of this one:\n"
+ << Curr << "\n";
+ }
+ return true;
+ }
+ }
+ } else {
+ if (!Quiet) { // print warnings about overlaps
+ OS << "warning: function ranges overlap:\n"
+ << Prev << "\n"
+ << Curr << "\n";
+ }
+ }
+ } else if (Prev.Range.size() == 0 &&
+ Curr.Range.contains(Prev.Range.Start)) {
+ if (!Quiet) {
+ OS << "warning: removing symbol:\n"
+ << Prev << "\nKeeping:\n"
+ << Curr << "\n";
+ }
+ return true;
+ }
+
+ return false;
+ }),
+ Funcs.end());
+
+ // If our last function info entry doesn't have a size and if we have valid
+ // text ranges, we should set the size of the last entry since any search for
+ // a high address might match our last entry. By fixing up this size, we can
+ // help ensure we don't cause lookups to always return the last symbol that
+ // has no size when doing lookups.
+ if (!Funcs.empty() && Funcs.back().Range.size() == 0 && ValidTextRanges) {
+ if (auto Range =
+ ValidTextRanges->getRangeThatContains(Funcs.back().Range.Start)) {
+ Funcs.back().Range.End = Range->End;
+ }
+ }
+ OS << "Pruned " << NumBefore - Funcs.size() << " functions, ended with "
+ << Funcs.size() << " total\n";
+ return Error::success();
+}
+
+uint32_t GsymCreator::insertString(StringRef S, bool Copy) {
+ if (S.empty())
+ return 0;
+
+ // The hash can be calculated outside the lock.
+ CachedHashStringRef CHStr(S);
+ std::lock_guard<std::mutex> Guard(Mutex);
+ if (Copy) {
+ // We need to provide backing storage for the string if requested
+ // since StringTableBuilder stores references to strings. Any string
+ // that comes from a section in an object file doesn't need to be
+ // copied, but any string created by code will need to be copied.
+ // This allows GsymCreator to be really fast when parsing DWARF and
+ // other object files as most strings don't need to be copied.
+ if (!StrTab.contains(CHStr))
+ CHStr = CachedHashStringRef{StringStorage.insert(S).first->getKey(),
+ CHStr.hash()};
+ }
+ return StrTab.add(CHStr);
+}
+
+void GsymCreator::addFunctionInfo(FunctionInfo &&FI) {
+ std::lock_guard<std::mutex> Guard(Mutex);
+ Ranges.insert(FI.Range);
+ Funcs.emplace_back(std::move(FI));
+}
+
+void GsymCreator::forEachFunctionInfo(
+ std::function<bool(FunctionInfo &)> const &Callback) {
+ std::lock_guard<std::mutex> Guard(Mutex);
+ for (auto &FI : Funcs) {
+ if (!Callback(FI))
+ break;
+ }
+}
+
+void GsymCreator::forEachFunctionInfo(
+ std::function<bool(const FunctionInfo &)> const &Callback) const {
+ std::lock_guard<std::mutex> Guard(Mutex);
+ for (const auto &FI : Funcs) {
+ if (!Callback(FI))
+ break;
+ }
+}
+
+size_t GsymCreator::getNumFunctionInfos() const {
+ std::lock_guard<std::mutex> Guard(Mutex);
+ return Funcs.size();
+}
+
+bool GsymCreator::IsValidTextAddress(uint64_t Addr) const {
+ if (ValidTextRanges)
+ return ValidTextRanges->contains(Addr);
+ return true; // No valid text ranges has been set, so accept all ranges.
+}
+
+bool GsymCreator::hasFunctionInfoForAddress(uint64_t Addr) const {
+ std::lock_guard<std::mutex> Guard(Mutex);
+ return Ranges.contains(Addr);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/GSYM/GsymReader.cpp b/contrib/libs/llvm14/lib/DebugInfo/GSYM/GsymReader.cpp
new file mode 100644
index 0000000000..2ad18bf63d
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/GSYM/GsymReader.cpp
@@ -0,0 +1,406 @@
+//===- GsymReader.cpp -----------------------------------------------------===//
+//
+// 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/GSYM/GsymReader.h"
+
+#include <assert.h>
+#include <inttypes.h>
+#include <stdio.h>
+#include <stdlib.h>
+
+#include "llvm/DebugInfo/GSYM/GsymCreator.h"
+#include "llvm/DebugInfo/GSYM/InlineInfo.h"
+#include "llvm/DebugInfo/GSYM/LineTable.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+using namespace gsym;
+
+GsymReader::GsymReader(std::unique_ptr<MemoryBuffer> Buffer) :
+ MemBuffer(std::move(Buffer)),
+ Endian(support::endian::system_endianness()) {}
+
+ GsymReader::GsymReader(GsymReader &&RHS) = default;
+
+GsymReader::~GsymReader() = default;
+
+llvm::Expected<GsymReader> GsymReader::openFile(StringRef Filename) {
+ // Open the input file and return an appropriate error if needed.
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BuffOrErr =
+ MemoryBuffer::getFileOrSTDIN(Filename);
+ auto Err = BuffOrErr.getError();
+ if (Err)
+ return llvm::errorCodeToError(Err);
+ return create(BuffOrErr.get());
+}
+
+llvm::Expected<GsymReader> GsymReader::copyBuffer(StringRef Bytes) {
+ auto MemBuffer = MemoryBuffer::getMemBufferCopy(Bytes, "GSYM bytes");
+ return create(MemBuffer);
+}
+
+llvm::Expected<llvm::gsym::GsymReader>
+GsymReader::create(std::unique_ptr<MemoryBuffer> &MemBuffer) {
+ if (!MemBuffer.get())
+ return createStringError(std::errc::invalid_argument,
+ "invalid memory buffer");
+ GsymReader GR(std::move(MemBuffer));
+ llvm::Error Err = GR.parse();
+ if (Err)
+ return std::move(Err);
+ return std::move(GR);
+}
+
+llvm::Error
+GsymReader::parse() {
+ BinaryStreamReader FileData(MemBuffer->getBuffer(),
+ support::endian::system_endianness());
+ // Check for the magic bytes. This file format is designed to be mmap'ed
+ // into a process and accessed as read only. This is done for performance
+ // and efficiency for symbolicating and parsing GSYM data.
+ if (FileData.readObject(Hdr))
+ return createStringError(std::errc::invalid_argument,
+ "not enough data for a GSYM header");
+
+ const auto HostByteOrder = support::endian::system_endianness();
+ switch (Hdr->Magic) {
+ case GSYM_MAGIC:
+ Endian = HostByteOrder;
+ break;
+ case GSYM_CIGAM:
+ // This is a GSYM file, but not native endianness.
+ Endian = sys::IsBigEndianHost ? support::little : support::big;
+ Swap.reset(new SwappedData);
+ break;
+ default:
+ return createStringError(std::errc::invalid_argument,
+ "not a GSYM file");
+ }
+
+ bool DataIsLittleEndian = HostByteOrder != support::little;
+ // Read a correctly byte swapped header if we need to.
+ if (Swap) {
+ DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
+ if (auto ExpectedHdr = Header::decode(Data))
+ Swap->Hdr = ExpectedHdr.get();
+ else
+ return ExpectedHdr.takeError();
+ Hdr = &Swap->Hdr;
+ }
+
+ // Detect errors in the header and report any that are found. If we make it
+ // past this without errors, we know we have a good magic value, a supported
+ // version number, verified address offset size and a valid UUID size.
+ if (Error Err = Hdr->checkForError())
+ return Err;
+
+ if (!Swap) {
+ // This is the native endianness case that is most common and optimized for
+ // efficient lookups. Here we just grab pointers to the native data and
+ // use ArrayRef objects to allow efficient read only access.
+
+ // Read the address offsets.
+ if (FileData.padToAlignment(Hdr->AddrOffSize) ||
+ FileData.readArray(AddrOffsets,
+ Hdr->NumAddresses * Hdr->AddrOffSize))
+ return createStringError(std::errc::invalid_argument,
+ "failed to read address table");
+
+ // Read the address info offsets.
+ if (FileData.padToAlignment(4) ||
+ FileData.readArray(AddrInfoOffsets, Hdr->NumAddresses))
+ return createStringError(std::errc::invalid_argument,
+ "failed to read address info offsets table");
+
+ // Read the file table.
+ uint32_t NumFiles = 0;
+ if (FileData.readInteger(NumFiles) || FileData.readArray(Files, NumFiles))
+ return createStringError(std::errc::invalid_argument,
+ "failed to read file table");
+
+ // Get the string table.
+ FileData.setOffset(Hdr->StrtabOffset);
+ if (FileData.readFixedString(StrTab.Data, Hdr->StrtabSize))
+ return createStringError(std::errc::invalid_argument,
+ "failed to read string table");
+} else {
+ // This is the non native endianness case that is not common and not
+ // optimized for lookups. Here we decode the important tables into local
+ // storage and then set the ArrayRef objects to point to these swapped
+ // copies of the read only data so lookups can be as efficient as possible.
+ DataExtractor Data(MemBuffer->getBuffer(), DataIsLittleEndian, 4);
+
+ // Read the address offsets.
+ uint64_t Offset = alignTo(sizeof(Header), Hdr->AddrOffSize);
+ Swap->AddrOffsets.resize(Hdr->NumAddresses * Hdr->AddrOffSize);
+ switch (Hdr->AddrOffSize) {
+ case 1:
+ if (!Data.getU8(&Offset, Swap->AddrOffsets.data(), Hdr->NumAddresses))
+ return createStringError(std::errc::invalid_argument,
+ "failed to read address table");
+ break;
+ case 2:
+ if (!Data.getU16(&Offset,
+ reinterpret_cast<uint16_t *>(Swap->AddrOffsets.data()),
+ Hdr->NumAddresses))
+ return createStringError(std::errc::invalid_argument,
+ "failed to read address table");
+ break;
+ case 4:
+ if (!Data.getU32(&Offset,
+ reinterpret_cast<uint32_t *>(Swap->AddrOffsets.data()),
+ Hdr->NumAddresses))
+ return createStringError(std::errc::invalid_argument,
+ "failed to read address table");
+ break;
+ case 8:
+ if (!Data.getU64(&Offset,
+ reinterpret_cast<uint64_t *>(Swap->AddrOffsets.data()),
+ Hdr->NumAddresses))
+ return createStringError(std::errc::invalid_argument,
+ "failed to read address table");
+ }
+ AddrOffsets = ArrayRef<uint8_t>(Swap->AddrOffsets);
+
+ // Read the address info offsets.
+ Offset = alignTo(Offset, 4);
+ Swap->AddrInfoOffsets.resize(Hdr->NumAddresses);
+ if (Data.getU32(&Offset, Swap->AddrInfoOffsets.data(), Hdr->NumAddresses))
+ AddrInfoOffsets = ArrayRef<uint32_t>(Swap->AddrInfoOffsets);
+ else
+ return createStringError(std::errc::invalid_argument,
+ "failed to read address table");
+ // Read the file table.
+ const uint32_t NumFiles = Data.getU32(&Offset);
+ if (NumFiles > 0) {
+ Swap->Files.resize(NumFiles);
+ if (Data.getU32(&Offset, &Swap->Files[0].Dir, NumFiles*2))
+ Files = ArrayRef<FileEntry>(Swap->Files);
+ else
+ return createStringError(std::errc::invalid_argument,
+ "failed to read file table");
+ }
+ // Get the string table.
+ StrTab.Data = MemBuffer->getBuffer().substr(Hdr->StrtabOffset,
+ Hdr->StrtabSize);
+ if (StrTab.Data.empty())
+ return createStringError(std::errc::invalid_argument,
+ "failed to read string table");
+ }
+ return Error::success();
+
+}
+
+const Header &GsymReader::getHeader() const {
+ // The only way to get a GsymReader is from GsymReader::openFile(...) or
+ // GsymReader::copyBuffer() and the header must be valid and initialized to
+ // a valid pointer value, so the assert below should not trigger.
+ assert(Hdr);
+ return *Hdr;
+}
+
+Optional<uint64_t> GsymReader::getAddress(size_t Index) const {
+ switch (Hdr->AddrOffSize) {
+ case 1: return addressForIndex<uint8_t>(Index);
+ case 2: return addressForIndex<uint16_t>(Index);
+ case 4: return addressForIndex<uint32_t>(Index);
+ case 8: return addressForIndex<uint64_t>(Index);
+ }
+ return llvm::None;
+}
+
+Optional<uint64_t> GsymReader::getAddressInfoOffset(size_t Index) const {
+ const auto NumAddrInfoOffsets = AddrInfoOffsets.size();
+ if (Index < NumAddrInfoOffsets)
+ return AddrInfoOffsets[Index];
+ return llvm::None;
+}
+
+Expected<uint64_t>
+GsymReader::getAddressIndex(const uint64_t Addr) const {
+ if (Addr >= Hdr->BaseAddress) {
+ const uint64_t AddrOffset = Addr - Hdr->BaseAddress;
+ Optional<uint64_t> AddrOffsetIndex;
+ switch (Hdr->AddrOffSize) {
+ case 1:
+ AddrOffsetIndex = getAddressOffsetIndex<uint8_t>(AddrOffset);
+ break;
+ case 2:
+ AddrOffsetIndex = getAddressOffsetIndex<uint16_t>(AddrOffset);
+ break;
+ case 4:
+ AddrOffsetIndex = getAddressOffsetIndex<uint32_t>(AddrOffset);
+ break;
+ case 8:
+ AddrOffsetIndex = getAddressOffsetIndex<uint64_t>(AddrOffset);
+ break;
+ default:
+ return createStringError(std::errc::invalid_argument,
+ "unsupported address offset size %u",
+ Hdr->AddrOffSize);
+ }
+ if (AddrOffsetIndex)
+ return *AddrOffsetIndex;
+ }
+ return createStringError(std::errc::invalid_argument,
+ "address 0x%" PRIx64 " is not in GSYM", Addr);
+
+}
+
+llvm::Expected<FunctionInfo> GsymReader::getFunctionInfo(uint64_t Addr) const {
+ Expected<uint64_t> AddressIndex = getAddressIndex(Addr);
+ if (!AddressIndex)
+ return AddressIndex.takeError();
+ // Address info offsets size should have been checked in parse().
+ assert(*AddressIndex < AddrInfoOffsets.size());
+ auto AddrInfoOffset = AddrInfoOffsets[*AddressIndex];
+ DataExtractor Data(MemBuffer->getBuffer().substr(AddrInfoOffset), Endian, 4);
+ if (Optional<uint64_t> OptAddr = getAddress(*AddressIndex)) {
+ auto ExpectedFI = FunctionInfo::decode(Data, *OptAddr);
+ if (ExpectedFI) {
+ if (ExpectedFI->Range.contains(Addr) || ExpectedFI->Range.size() == 0)
+ return ExpectedFI;
+ return createStringError(std::errc::invalid_argument,
+ "address 0x%" PRIx64 " is not in GSYM", Addr);
+ }
+ }
+ return createStringError(std::errc::invalid_argument,
+ "failed to extract address[%" PRIu64 "]",
+ *AddressIndex);
+}
+
+llvm::Expected<LookupResult> GsymReader::lookup(uint64_t Addr) const {
+ Expected<uint64_t> AddressIndex = getAddressIndex(Addr);
+ if (!AddressIndex)
+ return AddressIndex.takeError();
+ // Address info offsets size should have been checked in parse().
+ assert(*AddressIndex < AddrInfoOffsets.size());
+ auto AddrInfoOffset = AddrInfoOffsets[*AddressIndex];
+ DataExtractor Data(MemBuffer->getBuffer().substr(AddrInfoOffset), Endian, 4);
+ if (Optional<uint64_t> OptAddr = getAddress(*AddressIndex))
+ return FunctionInfo::lookup(Data, *this, *OptAddr, Addr);
+ return createStringError(std::errc::invalid_argument,
+ "failed to extract address[%" PRIu64 "]",
+ *AddressIndex);
+}
+
+void GsymReader::dump(raw_ostream &OS) {
+ const auto &Header = getHeader();
+ // Dump the GSYM header.
+ OS << Header << "\n";
+ // Dump the address table.
+ OS << "Address Table:\n";
+ OS << "INDEX OFFSET";
+
+ switch (Hdr->AddrOffSize) {
+ case 1: OS << "8 "; break;
+ case 2: OS << "16"; break;
+ case 4: OS << "32"; break;
+ case 8: OS << "64"; break;
+ default: OS << "??"; break;
+ }
+ OS << " (ADDRESS)\n";
+ OS << "====== =============================== \n";
+ for (uint32_t I = 0; I < Header.NumAddresses; ++I) {
+ OS << format("[%4u] ", I);
+ switch (Hdr->AddrOffSize) {
+ case 1: OS << HEX8(getAddrOffsets<uint8_t>()[I]); break;
+ case 2: OS << HEX16(getAddrOffsets<uint16_t>()[I]); break;
+ case 4: OS << HEX32(getAddrOffsets<uint32_t>()[I]); break;
+ case 8: OS << HEX32(getAddrOffsets<uint64_t>()[I]); break;
+ default: break;
+ }
+ OS << " (" << HEX64(*getAddress(I)) << ")\n";
+ }
+ // Dump the address info offsets table.
+ OS << "\nAddress Info Offsets:\n";
+ OS << "INDEX Offset\n";
+ OS << "====== ==========\n";
+ for (uint32_t I = 0; I < Header.NumAddresses; ++I)
+ OS << format("[%4u] ", I) << HEX32(AddrInfoOffsets[I]) << "\n";
+ // Dump the file table.
+ OS << "\nFiles:\n";
+ OS << "INDEX DIRECTORY BASENAME PATH\n";
+ OS << "====== ========== ========== ==============================\n";
+ for (uint32_t I = 0; I < Files.size(); ++I) {
+ OS << format("[%4u] ", I) << HEX32(Files[I].Dir) << ' '
+ << HEX32(Files[I].Base) << ' ';
+ dump(OS, getFile(I));
+ OS << "\n";
+ }
+ OS << "\n" << StrTab << "\n";
+
+ for (uint32_t I = 0; I < Header.NumAddresses; ++I) {
+ OS << "FunctionInfo @ " << HEX32(AddrInfoOffsets[I]) << ": ";
+ if (auto FI = getFunctionInfo(*getAddress(I)))
+ dump(OS, *FI);
+ else
+ logAllUnhandledErrors(FI.takeError(), OS, "FunctionInfo:");
+ }
+}
+
+void GsymReader::dump(raw_ostream &OS, const FunctionInfo &FI) {
+ OS << FI.Range << " \"" << getString(FI.Name) << "\"\n";
+ if (FI.OptLineTable)
+ dump(OS, *FI.OptLineTable);
+ if (FI.Inline)
+ dump(OS, *FI.Inline);
+}
+
+void GsymReader::dump(raw_ostream &OS, const LineTable &LT) {
+ OS << "LineTable:\n";
+ for (auto &LE: LT) {
+ OS << " " << HEX64(LE.Addr) << ' ';
+ if (LE.File)
+ dump(OS, getFile(LE.File));
+ OS << ':' << LE.Line << '\n';
+ }
+}
+
+void GsymReader::dump(raw_ostream &OS, const InlineInfo &II, uint32_t Indent) {
+ if (Indent == 0)
+ OS << "InlineInfo:\n";
+ else
+ OS.indent(Indent);
+ OS << II.Ranges << ' ' << getString(II.Name);
+ if (II.CallFile != 0) {
+ if (auto File = getFile(II.CallFile)) {
+ OS << " called from ";
+ dump(OS, File);
+ OS << ':' << II.CallLine;
+ }
+ }
+ OS << '\n';
+ for (const auto &ChildII: II.Children)
+ dump(OS, ChildII, Indent + 2);
+}
+
+void GsymReader::dump(raw_ostream &OS, Optional<FileEntry> FE) {
+ if (FE) {
+ // IF we have the file from index 0, then don't print anything
+ if (FE->Dir == 0 && FE->Base == 0)
+ return;
+ StringRef Dir = getString(FE->Dir);
+ StringRef Base = getString(FE->Base);
+ if (!Dir.empty()) {
+ OS << Dir;
+ if (Dir.contains('\\') && !Dir.contains('/'))
+ OS << '\\';
+ else
+ OS << '/';
+ }
+ if (!Base.empty()) {
+ OS << Base;
+ }
+ if (!Dir.empty() || !Base.empty())
+ return;
+ }
+ OS << "<invalid-file>";
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/GSYM/Header.cpp b/contrib/libs/llvm14/lib/DebugInfo/GSYM/Header.cpp
new file mode 100644
index 0000000000..0b3fb9c498
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/GSYM/Header.cpp
@@ -0,0 +1,109 @@
+//===- Header.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/GSYM/Header.h"
+#include "llvm/DebugInfo/GSYM/FileWriter.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+
+#define HEX8(v) llvm::format_hex(v, 4)
+#define HEX16(v) llvm::format_hex(v, 6)
+#define HEX32(v) llvm::format_hex(v, 10)
+#define HEX64(v) llvm::format_hex(v, 18)
+
+using namespace llvm;
+using namespace gsym;
+
+raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const Header &H) {
+ OS << "Header:\n";
+ OS << " Magic = " << HEX32(H.Magic) << "\n";
+ OS << " Version = " << HEX16(H.Version) << '\n';
+ OS << " AddrOffSize = " << HEX8(H.AddrOffSize) << '\n';
+ OS << " UUIDSize = " << HEX8(H.UUIDSize) << '\n';
+ OS << " BaseAddress = " << HEX64(H.BaseAddress) << '\n';
+ OS << " NumAddresses = " << HEX32(H.NumAddresses) << '\n';
+ OS << " StrtabOffset = " << HEX32(H.StrtabOffset) << '\n';
+ OS << " StrtabSize = " << HEX32(H.StrtabSize) << '\n';
+ OS << " UUID = ";
+ for (uint8_t I = 0; I < H.UUIDSize; ++I)
+ OS << format_hex_no_prefix(H.UUID[I], 2);
+ OS << '\n';
+ return OS;
+}
+
+/// Check the header and detect any errors.
+llvm::Error Header::checkForError() const {
+ if (Magic != GSYM_MAGIC)
+ return createStringError(std::errc::invalid_argument,
+ "invalid GSYM magic 0x%8.8x", Magic);
+ if (Version != GSYM_VERSION)
+ return createStringError(std::errc::invalid_argument,
+ "unsupported GSYM version %u", Version);
+ switch (AddrOffSize) {
+ case 1: break;
+ case 2: break;
+ case 4: break;
+ case 8: break;
+ default:
+ return createStringError(std::errc::invalid_argument,
+ "invalid address offset size %u",
+ AddrOffSize);
+ }
+ if (UUIDSize > GSYM_MAX_UUID_SIZE)
+ return createStringError(std::errc::invalid_argument,
+ "invalid UUID size %u", UUIDSize);
+ return Error::success();
+}
+
+llvm::Expected<Header> Header::decode(DataExtractor &Data) {
+ uint64_t Offset = 0;
+ // The header is stored as a single blob of data that has a fixed byte size.
+ if (!Data.isValidOffsetForDataOfSize(Offset, sizeof(Header)))
+ return createStringError(std::errc::invalid_argument,
+ "not enough data for a gsym::Header");
+ Header H;
+ H.Magic = Data.getU32(&Offset);
+ H.Version = Data.getU16(&Offset);
+ H.AddrOffSize = Data.getU8(&Offset);
+ H.UUIDSize = Data.getU8(&Offset);
+ H.BaseAddress = Data.getU64(&Offset);
+ H.NumAddresses = Data.getU32(&Offset);
+ H.StrtabOffset = Data.getU32(&Offset);
+ H.StrtabSize = Data.getU32(&Offset);
+ Data.getU8(&Offset, H.UUID, GSYM_MAX_UUID_SIZE);
+ if (llvm::Error Err = H.checkForError())
+ return std::move(Err);
+ return H;
+}
+
+llvm::Error Header::encode(FileWriter &O) const {
+ // Users must verify the Header is valid prior to calling this funtion.
+ if (llvm::Error Err = checkForError())
+ return Err;
+ O.writeU32(Magic);
+ O.writeU16(Version);
+ O.writeU8(AddrOffSize);
+ O.writeU8(UUIDSize);
+ O.writeU64(BaseAddress);
+ O.writeU32(NumAddresses);
+ O.writeU32(StrtabOffset);
+ O.writeU32(StrtabSize);
+ O.writeData(llvm::ArrayRef<uint8_t>(UUID));
+ return Error::success();
+}
+
+bool llvm::gsym::operator==(const Header &LHS, const Header &RHS) {
+ return LHS.Magic == RHS.Magic && LHS.Version == RHS.Version &&
+ LHS.AddrOffSize == RHS.AddrOffSize && LHS.UUIDSize == RHS.UUIDSize &&
+ LHS.BaseAddress == RHS.BaseAddress &&
+ LHS.NumAddresses == RHS.NumAddresses &&
+ LHS.StrtabOffset == RHS.StrtabOffset &&
+ LHS.StrtabSize == RHS.StrtabSize &&
+ memcmp(LHS.UUID, RHS.UUID, LHS.UUIDSize) == 0;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/GSYM/InlineInfo.cpp b/contrib/libs/llvm14/lib/DebugInfo/GSYM/InlineInfo.cpp
new file mode 100644
index 0000000000..21679b1b78
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/GSYM/InlineInfo.cpp
@@ -0,0 +1,265 @@
+//===- InlineInfo.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/GSYM/FileEntry.h"
+#include "llvm/DebugInfo/GSYM/FileWriter.h"
+#include "llvm/DebugInfo/GSYM/GsymReader.h"
+#include "llvm/DebugInfo/GSYM/InlineInfo.h"
+#include "llvm/Support/DataExtractor.h"
+#include <algorithm>
+#include <inttypes.h>
+
+using namespace llvm;
+using namespace gsym;
+
+
+raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const InlineInfo &II) {
+ if (!II.isValid())
+ return OS;
+ bool First = true;
+ for (auto Range : II.Ranges) {
+ if (First)
+ First = false;
+ else
+ OS << ' ';
+ OS << Range;
+ }
+ OS << " Name = " << HEX32(II.Name) << ", CallFile = " << II.CallFile
+ << ", CallLine = " << II.CallFile << '\n';
+ for (const auto &Child : II.Children)
+ OS << Child;
+ return OS;
+}
+
+static bool getInlineStackHelper(const InlineInfo &II, uint64_t Addr,
+ std::vector<const InlineInfo *> &InlineStack) {
+ if (II.Ranges.contains(Addr)) {
+ // If this is the top level that represents the concrete function,
+ // there will be no name and we shoud clear the inline stack. Otherwise
+ // we have found an inline call stack that we need to insert.
+ if (II.Name != 0)
+ InlineStack.insert(InlineStack.begin(), &II);
+ for (const auto &Child : II.Children) {
+ if (::getInlineStackHelper(Child, Addr, InlineStack))
+ break;
+ }
+ return !InlineStack.empty();
+ }
+ return false;
+}
+
+llvm::Optional<InlineInfo::InlineArray> InlineInfo::getInlineStack(uint64_t Addr) const {
+ InlineArray Result;
+ if (getInlineStackHelper(*this, Addr, Result))
+ return Result;
+ return llvm::None;
+}
+
+/// Skip an InlineInfo object in the specified data at the specified offset.
+///
+/// Used during the InlineInfo::lookup() call to quickly skip child InlineInfo
+/// objects where the addres ranges isn't contained in the InlineInfo object
+/// or its children. This avoids allocations by not appending child InlineInfo
+/// objects to the InlineInfo::Children array.
+///
+/// \param Data The binary stream to read the data from.
+///
+/// \param Offset The byte offset within \a Data.
+///
+/// \param SkippedRanges If true, address ranges have already been skipped.
+
+static bool skip(DataExtractor &Data, uint64_t &Offset, bool SkippedRanges) {
+ if (!SkippedRanges) {
+ if (AddressRanges::skip(Data, Offset) == 0)
+ return false;
+ }
+ bool HasChildren = Data.getU8(&Offset) != 0;
+ Data.getU32(&Offset); // Skip Inline.Name.
+ Data.getULEB128(&Offset); // Skip Inline.CallFile.
+ Data.getULEB128(&Offset); // Skip Inline.CallLine.
+ if (HasChildren) {
+ while (skip(Data, Offset, false /* SkippedRanges */))
+ /* Do nothing */;
+ }
+ // We skipped a valid InlineInfo.
+ return true;
+}
+
+/// A Lookup helper functions.
+///
+/// Used during the InlineInfo::lookup() call to quickly only parse an
+/// InlineInfo object if the address falls within this object. This avoids
+/// allocations by not appending child InlineInfo objects to the
+/// InlineInfo::Children array and also skips any InlineInfo objects that do
+/// not contain the address we are looking up.
+///
+/// \param Data The binary stream to read the data from.
+///
+/// \param Offset The byte offset within \a Data.
+///
+/// \param BaseAddr The address that the relative address range offsets are
+/// relative to.
+
+static bool lookup(const GsymReader &GR, DataExtractor &Data, uint64_t &Offset,
+ uint64_t BaseAddr, uint64_t Addr, SourceLocations &SrcLocs,
+ llvm::Error &Err) {
+ InlineInfo Inline;
+ Inline.Ranges.decode(Data, BaseAddr, Offset);
+ if (Inline.Ranges.empty())
+ return true;
+ // Check if the address is contained within the inline information, and if
+ // not, quickly skip this InlineInfo object and all its children.
+ if (!Inline.Ranges.contains(Addr)) {
+ skip(Data, Offset, true /* SkippedRanges */);
+ return false;
+ }
+
+ // The address range is contained within this InlineInfo, add the source
+ // location for this InlineInfo and any children that contain the address.
+ bool HasChildren = Data.getU8(&Offset) != 0;
+ Inline.Name = Data.getU32(&Offset);
+ Inline.CallFile = (uint32_t)Data.getULEB128(&Offset);
+ Inline.CallLine = (uint32_t)Data.getULEB128(&Offset);
+ if (HasChildren) {
+ // Child address ranges are encoded relative to the first address in the
+ // parent InlineInfo object.
+ const auto ChildBaseAddr = Inline.Ranges[0].Start;
+ bool Done = false;
+ while (!Done)
+ Done = lookup(GR, Data, Offset, ChildBaseAddr, Addr, SrcLocs, Err);
+ }
+
+ Optional<FileEntry> CallFile = GR.getFile(Inline.CallFile);
+ if (!CallFile) {
+ Err = createStringError(std::errc::invalid_argument,
+ "failed to extract file[%" PRIu32 "]",
+ Inline.CallFile);
+ return false;
+ }
+
+ if (CallFile->Dir || CallFile->Base) {
+ SourceLocation SrcLoc;
+ SrcLoc.Name = SrcLocs.back().Name;
+ SrcLoc.Offset = SrcLocs.back().Offset;
+ SrcLoc.Dir = GR.getString(CallFile->Dir);
+ SrcLoc.Base = GR.getString(CallFile->Base);
+ SrcLoc.Line = Inline.CallLine;
+ SrcLocs.back().Name = GR.getString(Inline.Name);
+ SrcLocs.back().Offset = Addr - Inline.Ranges[0].Start;
+ SrcLocs.push_back(SrcLoc);
+ }
+ return true;
+}
+
+llvm::Error InlineInfo::lookup(const GsymReader &GR, DataExtractor &Data,
+ uint64_t BaseAddr, uint64_t Addr,
+ SourceLocations &SrcLocs) {
+ // Call our recursive helper function starting at offset zero.
+ uint64_t Offset = 0;
+ llvm::Error Err = Error::success();
+ ::lookup(GR, Data, Offset, BaseAddr, Addr, SrcLocs, Err);
+ return Err;
+}
+
+/// Decode an InlineInfo in Data at the specified offset.
+///
+/// A local helper function to decode InlineInfo objects. This function is
+/// called recursively when parsing child InlineInfo objects.
+///
+/// \param Data The data extractor to decode from.
+/// \param Offset The offset within \a Data to decode from.
+/// \param BaseAddr The base address to use when decoding address ranges.
+/// \returns An InlineInfo or an error describing the issue that was
+/// encountered during decoding.
+static llvm::Expected<InlineInfo> decode(DataExtractor &Data, uint64_t &Offset,
+ uint64_t BaseAddr) {
+ InlineInfo Inline;
+ if (!Data.isValidOffset(Offset))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": missing InlineInfo address ranges data", Offset);
+ Inline.Ranges.decode(Data, BaseAddr, Offset);
+ if (Inline.Ranges.empty())
+ return Inline;
+ if (!Data.isValidOffsetForDataOfSize(Offset, 1))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": missing InlineInfo uint8_t indicating children",
+ Offset);
+ bool HasChildren = Data.getU8(&Offset) != 0;
+ if (!Data.isValidOffsetForDataOfSize(Offset, 4))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": missing InlineInfo uint32_t for name", Offset);
+ Inline.Name = Data.getU32(&Offset);
+ if (!Data.isValidOffset(Offset))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": missing ULEB128 for InlineInfo call file", Offset);
+ Inline.CallFile = (uint32_t)Data.getULEB128(&Offset);
+ if (!Data.isValidOffset(Offset))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": missing ULEB128 for InlineInfo call line", Offset);
+ Inline.CallLine = (uint32_t)Data.getULEB128(&Offset);
+ if (HasChildren) {
+ // Child address ranges are encoded relative to the first address in the
+ // parent InlineInfo object.
+ const auto ChildBaseAddr = Inline.Ranges[0].Start;
+ while (true) {
+ llvm::Expected<InlineInfo> Child = decode(Data, Offset, ChildBaseAddr);
+ if (!Child)
+ return Child.takeError();
+ // InlineInfo with empty Ranges termintes a child sibling chain.
+ if (Child.get().Ranges.empty())
+ break;
+ Inline.Children.emplace_back(std::move(*Child));
+ }
+ }
+ return Inline;
+}
+
+llvm::Expected<InlineInfo> InlineInfo::decode(DataExtractor &Data,
+ uint64_t BaseAddr) {
+ uint64_t Offset = 0;
+ return ::decode(Data, Offset, BaseAddr);
+}
+
+llvm::Error InlineInfo::encode(FileWriter &O, uint64_t BaseAddr) const {
+ // Users must verify the InlineInfo is valid prior to calling this funtion.
+ // We don't want to emit any InlineInfo objects if they are not valid since
+ // it will waste space in the GSYM file.
+ if (!isValid())
+ return createStringError(std::errc::invalid_argument,
+ "attempted to encode invalid InlineInfo object");
+ Ranges.encode(O, BaseAddr);
+ bool HasChildren = !Children.empty();
+ O.writeU8(HasChildren);
+ O.writeU32(Name);
+ O.writeULEB(CallFile);
+ O.writeULEB(CallLine);
+ if (HasChildren) {
+ // Child address ranges are encoded as relative to the first
+ // address in the Ranges for this object. This keeps the offsets
+ // small and allows for efficient encoding using ULEB offsets.
+ const uint64_t ChildBaseAddr = Ranges[0].Start;
+ for (const auto &Child : Children) {
+ // Make sure all child address ranges are contained in the parent address
+ // ranges.
+ for (const auto &ChildRange: Child.Ranges) {
+ if (!Ranges.contains(ChildRange))
+ return createStringError(std::errc::invalid_argument,
+ "child range not contained in parent");
+ }
+ llvm::Error Err = Child.encode(O, ChildBaseAddr);
+ if (Err)
+ return Err;
+ }
+
+ // Terminate child sibling chain by emitting a zero. This zero will cause
+ // the decodeAll() function above to return false and stop the decoding
+ // of child InlineInfo objects that are siblings.
+ O.writeULEB(0);
+ }
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/GSYM/LineTable.cpp b/contrib/libs/llvm14/lib/DebugInfo/GSYM/LineTable.cpp
new file mode 100644
index 0000000000..a49a3ba9bf
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/GSYM/LineTable.cpp
@@ -0,0 +1,293 @@
+//===- LineTable.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/GSYM/LineTable.h"
+#include "llvm/DebugInfo/GSYM/FileWriter.h"
+#include "llvm/Support/DataExtractor.h"
+
+using namespace llvm;
+using namespace gsym;
+
+enum LineTableOpCode {
+ EndSequence = 0x00, ///< End of the line table.
+ SetFile = 0x01, ///< Set LineTableRow.file_idx, don't push a row.
+ AdvancePC = 0x02, ///< Increment LineTableRow.address, and push a row.
+ AdvanceLine = 0x03, ///< Set LineTableRow.file_line, don't push a row.
+ FirstSpecial = 0x04, ///< All special opcodes push a row.
+};
+
+struct DeltaInfo {
+ int64_t Delta;
+ uint32_t Count;
+ DeltaInfo(int64_t D, uint32_t C) : Delta(D), Count(C) {}
+};
+
+inline bool operator<(const DeltaInfo &LHS, int64_t Delta) {
+ return LHS.Delta < Delta;
+}
+
+static bool encodeSpecial(int64_t MinLineDelta, int64_t MaxLineDelta,
+ int64_t LineDelta, uint64_t AddrDelta,
+ uint8_t &SpecialOp) {
+ if (LineDelta < MinLineDelta)
+ return false;
+ if (LineDelta > MaxLineDelta)
+ return false;
+ int64_t LineRange = MaxLineDelta - MinLineDelta + 1;
+ int64_t AdjustedOp = ((LineDelta - MinLineDelta) + AddrDelta * LineRange);
+ int64_t Op = AdjustedOp + FirstSpecial;
+ if (Op < 0)
+ return false;
+ if (Op > 255)
+ return false;
+ SpecialOp = (uint8_t)Op;
+ return true;
+}
+
+typedef std::function<bool(const LineEntry &Row)> LineEntryCallback;
+
+static llvm::Error parse(DataExtractor &Data, uint64_t BaseAddr,
+ LineEntryCallback const &Callback) {
+ uint64_t Offset = 0;
+ if (!Data.isValidOffset(Offset))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": missing LineTable MinDelta", Offset);
+ int64_t MinDelta = Data.getSLEB128(&Offset);
+ if (!Data.isValidOffset(Offset))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": missing LineTable MaxDelta", Offset);
+ int64_t MaxDelta = Data.getSLEB128(&Offset);
+ int64_t LineRange = MaxDelta - MinDelta + 1;
+ if (!Data.isValidOffset(Offset))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": missing LineTable FirstLine", Offset);
+ const uint32_t FirstLine = (uint32_t)Data.getULEB128(&Offset);
+ LineEntry Row(BaseAddr, 1, FirstLine);
+ bool Done = false;
+ while (!Done) {
+ if (!Data.isValidOffset(Offset))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": EOF found before EndSequence", Offset);
+ uint8_t Op = Data.getU8(&Offset);
+ switch (Op) {
+ case EndSequence:
+ Done = true;
+ break;
+ case SetFile:
+ if (!Data.isValidOffset(Offset))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": EOF found before SetFile value",
+ Offset);
+ Row.File = (uint32_t)Data.getULEB128(&Offset);
+ break;
+ case AdvancePC:
+ if (!Data.isValidOffset(Offset))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": EOF found before AdvancePC value",
+ Offset);
+ Row.Addr += Data.getULEB128(&Offset);
+ // If the function callback returns false, we stop parsing.
+ if (Callback(Row) == false)
+ return Error::success();
+ break;
+ case AdvanceLine:
+ if (!Data.isValidOffset(Offset))
+ return createStringError(std::errc::io_error,
+ "0x%8.8" PRIx64 ": EOF found before AdvanceLine value",
+ Offset);
+ Row.Line += Data.getSLEB128(&Offset);
+ break;
+ default: {
+ // A byte that contains both address and line increment.
+ uint8_t AdjustedOp = Op - FirstSpecial;
+ int64_t LineDelta = MinDelta + (AdjustedOp % LineRange);
+ uint64_t AddrDelta = (AdjustedOp / LineRange);
+ Row.Line += LineDelta;
+ Row.Addr += AddrDelta;
+ // If the function callback returns false, we stop parsing.
+ if (Callback(Row) == false)
+ return Error::success();
+ break;
+ }
+ }
+ }
+ return Error::success();
+}
+
+llvm::Error LineTable::encode(FileWriter &Out, uint64_t BaseAddr) const {
+ // Users must verify the LineTable is valid prior to calling this funtion.
+ // We don't want to emit any LineTable objects if they are not valid since
+ // it will waste space in the GSYM file.
+ if (!isValid())
+ return createStringError(std::errc::invalid_argument,
+ "attempted to encode invalid LineTable object");
+
+ int64_t MinLineDelta = INT64_MAX;
+ int64_t MaxLineDelta = INT64_MIN;
+ std::vector<DeltaInfo> DeltaInfos;
+ if (Lines.size() == 1) {
+ MinLineDelta = 0;
+ MaxLineDelta = 0;
+ } else {
+ int64_t PrevLine = 1;
+ bool First = true;
+ for (const auto &line_entry : Lines) {
+ if (First)
+ First = false;
+ else {
+ int64_t LineDelta = (int64_t)line_entry.Line - PrevLine;
+ auto End = DeltaInfos.end();
+ auto Pos = std::lower_bound(DeltaInfos.begin(), End, LineDelta);
+ if (Pos != End && Pos->Delta == LineDelta)
+ ++Pos->Count;
+ else
+ DeltaInfos.insert(Pos, DeltaInfo(LineDelta, 1));
+ if (LineDelta < MinLineDelta)
+ MinLineDelta = LineDelta;
+ if (LineDelta > MaxLineDelta)
+ MaxLineDelta = LineDelta;
+ }
+ PrevLine = (int64_t)line_entry.Line;
+ }
+ assert(MinLineDelta <= MaxLineDelta);
+ }
+ // Set the min and max line delta intelligently based on the counts of
+ // the line deltas. if our range is too large.
+ const int64_t MaxLineRange = 14;
+ if (MaxLineDelta - MinLineDelta > MaxLineRange) {
+ uint32_t BestIndex = 0;
+ uint32_t BestEndIndex = 0;
+ uint32_t BestCount = 0;
+ const size_t NumDeltaInfos = DeltaInfos.size();
+ for (uint32_t I = 0; I < NumDeltaInfos; ++I) {
+ const int64_t FirstDelta = DeltaInfos[I].Delta;
+ uint32_t CurrCount = 0;
+ uint32_t J;
+ for (J = I; J < NumDeltaInfos; ++J) {
+ auto LineRange = DeltaInfos[J].Delta - FirstDelta;
+ if (LineRange > MaxLineRange)
+ break;
+ CurrCount += DeltaInfos[J].Count;
+ }
+ if (CurrCount > BestCount) {
+ BestIndex = I;
+ BestEndIndex = J - 1;
+ BestCount = CurrCount;
+ }
+ }
+ MinLineDelta = DeltaInfos[BestIndex].Delta;
+ MaxLineDelta = DeltaInfos[BestEndIndex].Delta;
+ }
+ if (MinLineDelta == MaxLineDelta && MinLineDelta > 0 &&
+ MinLineDelta < MaxLineRange)
+ MinLineDelta = 0;
+ assert(MinLineDelta <= MaxLineDelta);
+
+ // Initialize the line entry state as a starting point. All line entries
+ // will be deltas from this.
+ LineEntry Prev(BaseAddr, 1, Lines.front().Line);
+
+ // Write out the min and max line delta as signed LEB128.
+ Out.writeSLEB(MinLineDelta);
+ Out.writeSLEB(MaxLineDelta);
+ // Write out the starting line number as a unsigned LEB128.
+ Out.writeULEB(Prev.Line);
+
+ for (const auto &Curr : Lines) {
+ if (Curr.Addr < BaseAddr)
+ return createStringError(std::errc::invalid_argument,
+ "LineEntry has address 0x%" PRIx64 " which is "
+ "less than the function start address 0x%"
+ PRIx64, Curr.Addr, BaseAddr);
+ if (Curr.Addr < Prev.Addr)
+ return createStringError(std::errc::invalid_argument,
+ "LineEntry in LineTable not in ascending order");
+ const uint64_t AddrDelta = Curr.Addr - Prev.Addr;
+ int64_t LineDelta = 0;
+ if (Curr.Line > Prev.Line)
+ LineDelta = Curr.Line - Prev.Line;
+ else if (Prev.Line > Curr.Line)
+ LineDelta = -((int32_t)(Prev.Line - Curr.Line));
+
+ // Set the file if it doesn't match the current one.
+ if (Curr.File != Prev.File) {
+ Out.writeU8(SetFile);
+ Out.writeULEB(Curr.File);
+ }
+
+ uint8_t SpecialOp;
+ if (encodeSpecial(MinLineDelta, MaxLineDelta, LineDelta, AddrDelta,
+ SpecialOp)) {
+ // Advance the PC and line and push a row.
+ Out.writeU8(SpecialOp);
+ } else {
+ // We can't encode the address delta and line delta into
+ // a single special opcode, we must do them separately.
+
+ // Advance the line.
+ if (LineDelta != 0) {
+ Out.writeU8(AdvanceLine);
+ Out.writeSLEB(LineDelta);
+ }
+
+ // Advance the PC and push a row.
+ Out.writeU8(AdvancePC);
+ Out.writeULEB(AddrDelta);
+ }
+ Prev = Curr;
+ }
+ Out.writeU8(EndSequence);
+ return Error::success();
+}
+
+// Parse all line table entries into the "LineTable" vector. We can
+// cache the results of this if needed, or we can call LineTable::lookup()
+// below.
+llvm::Expected<LineTable> LineTable::decode(DataExtractor &Data,
+ uint64_t BaseAddr) {
+ LineTable LT;
+ llvm::Error Err = parse(Data, BaseAddr, [&](const LineEntry &Row) -> bool {
+ LT.Lines.push_back(Row);
+ return true; // Keep parsing by returning true.
+ });
+ if (Err)
+ return std::move(Err);
+ return LT;
+}
+// Parse the line table on the fly and find the row we are looking for.
+// We will need to determine if we need to cache the line table by calling
+// LineTable::parseAllEntries(...) or just call this function each time.
+// There is a CPU vs memory tradeoff we will need to determined.
+Expected<LineEntry> LineTable::lookup(DataExtractor &Data, uint64_t BaseAddr, uint64_t Addr) {
+ LineEntry Result;
+ llvm::Error Err = parse(Data, BaseAddr,
+ [Addr, &Result](const LineEntry &Row) -> bool {
+ if (Addr < Row.Addr)
+ return false; // Stop parsing, result contains the line table row!
+ Result = Row;
+ if (Addr == Row.Addr) {
+ // Stop parsing, this is the row we are looking for since the address
+ // matches.
+ return false;
+ }
+ return true; // Keep parsing till we find the right row.
+ });
+ if (Err)
+ return std::move(Err);
+ if (Result.isValid())
+ return Result;
+ return createStringError(std::errc::invalid_argument,
+ "address 0x%" PRIx64 " is not in the line table",
+ Addr);
+}
+
+raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const LineTable &LT) {
+ for (const auto &LineEntry : LT)
+ OS << LineEntry << '\n';
+ return OS;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/GSYM/LookupResult.cpp b/contrib/libs/llvm14/lib/DebugInfo/GSYM/LookupResult.cpp
new file mode 100644
index 0000000000..8a624226b1
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/GSYM/LookupResult.cpp
@@ -0,0 +1,74 @@
+//===- LookupResult.cpp -------------------------------------------------*-===//
+//
+// 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/GSYM/LookupResult.h"
+#include "llvm/ADT/SmallString.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <ciso646>
+
+using namespace llvm;
+using namespace gsym;
+
+std::string LookupResult::getSourceFile(uint32_t Index) const {
+ std::string Fullpath;
+ if (Index < Locations.size()) {
+ if (!Locations[Index].Dir.empty()) {
+ if (Locations[Index].Base.empty()) {
+ Fullpath = std::string(Locations[Index].Dir);
+ } else {
+ llvm::SmallString<64> Storage;
+ llvm::sys::path::append(Storage, Locations[Index].Dir,
+ Locations[Index].Base);
+ Fullpath.assign(Storage.begin(), Storage.end());
+ }
+ } else if (!Locations[Index].Base.empty())
+ Fullpath = std::string(Locations[Index].Base);
+ }
+ return Fullpath;
+}
+
+raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const SourceLocation &SL) {
+ OS << SL.Name;
+ if (SL.Offset > 0)
+ OS << " + " << SL.Offset;
+ if (SL.Dir.size() || SL.Base.size()) {
+ OS << " @ ";
+ if (!SL.Dir.empty()) {
+ OS << SL.Dir;
+ if (SL.Dir.contains('\\') and not SL.Dir.contains('/'))
+ OS << '\\';
+ else
+ OS << '/';
+ }
+ if (SL.Base.empty())
+ OS << "<invalid-file>";
+ else
+ OS << SL.Base;
+ OS << ':' << SL.Line;
+ }
+ return OS;
+}
+
+raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const LookupResult &LR) {
+ OS << HEX64(LR.LookupAddr) << ": ";
+ auto NumLocations = LR.Locations.size();
+ for (size_t I = 0; I < NumLocations; ++I) {
+ if (I > 0) {
+ OS << '\n';
+ OS.indent(20);
+ }
+ const bool IsInlined = I + 1 != NumLocations;
+ OS << LR.Locations[I];
+ if (IsInlined)
+ OS << " [inlined]";
+ }
+ OS << '\n';
+ return OS;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp b/contrib/libs/llvm14/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp
new file mode 100644
index 0000000000..ad35aefe77
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/GSYM/ObjectFileTransformer.cpp
@@ -0,0 +1,116 @@
+//===- ObjectFileTransformer.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 <unordered_set>
+
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/MachOUniversal.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/raw_ostream.h"
+
+#include "llvm/DebugInfo/GSYM/ObjectFileTransformer.h"
+#include "llvm/DebugInfo/GSYM/GsymCreator.h"
+
+using namespace llvm;
+using namespace gsym;
+
+constexpr uint32_t NT_GNU_BUILD_ID_TAG = 0x03;
+
+static std::vector<uint8_t> getUUID(const object::ObjectFile &Obj) {
+ // Extract the UUID from the object file
+ std::vector<uint8_t> UUID;
+ if (auto *MachO = dyn_cast<object::MachOObjectFile>(&Obj)) {
+ const ArrayRef<uint8_t> MachUUID = MachO->getUuid();
+ if (!MachUUID.empty())
+ UUID.assign(MachUUID.data(), MachUUID.data() + MachUUID.size());
+ } else if (isa<object::ELFObjectFileBase>(&Obj)) {
+ const StringRef GNUBuildID(".note.gnu.build-id");
+ for (const object::SectionRef &Sect : Obj.sections()) {
+ Expected<StringRef> SectNameOrErr = Sect.getName();
+ if (!SectNameOrErr) {
+ consumeError(SectNameOrErr.takeError());
+ continue;
+ }
+ StringRef SectName(*SectNameOrErr);
+ if (SectName != GNUBuildID)
+ continue;
+ StringRef BuildIDData;
+ Expected<StringRef> E = Sect.getContents();
+ if (E)
+ BuildIDData = *E;
+ else {
+ consumeError(E.takeError());
+ continue;
+ }
+ DataExtractor Decoder(BuildIDData, Obj.makeTriple().isLittleEndian(), 8);
+ uint64_t Offset = 0;
+ const uint32_t NameSize = Decoder.getU32(&Offset);
+ const uint32_t PayloadSize = Decoder.getU32(&Offset);
+ const uint32_t PayloadType = Decoder.getU32(&Offset);
+ StringRef Name(Decoder.getFixedLengthString(&Offset, NameSize));
+ if (Name == "GNU" && PayloadType == NT_GNU_BUILD_ID_TAG) {
+ Offset = alignTo(Offset, 4);
+ StringRef UUIDBytes(Decoder.getBytes(&Offset, PayloadSize));
+ if (!UUIDBytes.empty()) {
+ auto Ptr = reinterpret_cast<const uint8_t *>(UUIDBytes.data());
+ UUID.assign(Ptr, Ptr + UUIDBytes.size());
+ }
+ }
+ }
+ }
+ return UUID;
+}
+
+llvm::Error ObjectFileTransformer::convert(const object::ObjectFile &Obj,
+ raw_ostream &Log,
+ GsymCreator &Gsym) {
+ using namespace llvm::object;
+
+ const bool IsMachO = isa<MachOObjectFile>(&Obj);
+ const bool IsELF = isa<ELFObjectFileBase>(&Obj);
+
+ // Read build ID.
+ Gsym.setUUID(getUUID(Obj));
+
+ // Parse the symbol table.
+ size_t NumBefore = Gsym.getNumFunctionInfos();
+ for (const object::SymbolRef &Sym : Obj.symbols()) {
+ Expected<SymbolRef::Type> SymType = Sym.getType();
+ if (!SymType) {
+ consumeError(SymType.takeError());
+ continue;
+ }
+ Expected<uint64_t> AddrOrErr = Sym.getValue();
+ if (!AddrOrErr)
+ // TODO: Test this error.
+ return AddrOrErr.takeError();
+
+ if (SymType.get() != SymbolRef::Type::ST_Function ||
+ !Gsym.IsValidTextAddress(*AddrOrErr) ||
+ Gsym.hasFunctionInfoForAddress(*AddrOrErr))
+ continue;
+ // Function size for MachO files will be 0
+ constexpr bool NoCopy = false;
+ const uint64_t size = IsELF ? ELFSymbolRef(Sym).getSize() : 0;
+ Expected<StringRef> Name = Sym.getName();
+ if (!Name) {
+ logAllUnhandledErrors(Name.takeError(), Log, "ObjectFileTransformer: ");
+ continue;
+ }
+ // Remove the leading '_' character in any symbol names if there is one
+ // for mach-o files.
+ if (IsMachO)
+ Name->consume_front("_");
+ Gsym.addFunctionInfo(
+ FunctionInfo(*AddrOrErr, size, Gsym.insertString(*Name, NoCopy)));
+ }
+ size_t FunctionsAddedCount = Gsym.getNumFunctionInfos() - NumBefore;
+ Log << "Loaded " << FunctionsAddedCount << " functions from symbol table.\n";
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/GSYM/Range.cpp b/contrib/libs/llvm14/lib/DebugInfo/GSYM/Range.cpp
new file mode 100644
index 0000000000..c1e8eccd0d
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/GSYM/Range.cpp
@@ -0,0 +1,123 @@
+//===- Range.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/GSYM/Range.h"
+#include "llvm/DebugInfo/GSYM/FileWriter.h"
+#include "llvm/Support/DataExtractor.h"
+#include <algorithm>
+#include <inttypes.h>
+
+using namespace llvm;
+using namespace gsym;
+
+
+void AddressRanges::insert(AddressRange Range) {
+ if (Range.size() == 0)
+ return;
+
+ auto It = llvm::upper_bound(Ranges, Range);
+ auto It2 = It;
+ while (It2 != Ranges.end() && It2->Start < Range.End)
+ ++It2;
+ if (It != It2) {
+ Range.End = std::max(Range.End, It2[-1].End);
+ It = Ranges.erase(It, It2);
+ }
+ if (It != Ranges.begin() && Range.Start < It[-1].End)
+ It[-1].End = std::max(It[-1].End, Range.End);
+ else
+ Ranges.insert(It, Range);
+}
+
+bool AddressRanges::contains(uint64_t Addr) const {
+ auto It = std::partition_point(
+ Ranges.begin(), Ranges.end(),
+ [=](const AddressRange &R) { return R.Start <= Addr; });
+ return It != Ranges.begin() && Addr < It[-1].End;
+}
+
+bool AddressRanges::contains(AddressRange Range) const {
+ if (Range.size() == 0)
+ return false;
+ auto It = std::partition_point(
+ Ranges.begin(), Ranges.end(),
+ [=](const AddressRange &R) { return R.Start <= Range.Start; });
+ if (It == Ranges.begin())
+ return false;
+ return Range.End <= It[-1].End;
+}
+
+Optional<AddressRange>
+AddressRanges::getRangeThatContains(uint64_t Addr) const {
+ auto It = std::partition_point(
+ Ranges.begin(), Ranges.end(),
+ [=](const AddressRange &R) { return R.Start <= Addr; });
+ if (It != Ranges.begin() && Addr < It[-1].End)
+ return It[-1];
+ return llvm::None;
+}
+
+raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const AddressRange &R) {
+ return OS << '[' << HEX64(R.Start) << " - " << HEX64(R.End) << ")";
+}
+
+raw_ostream &llvm::gsym::operator<<(raw_ostream &OS, const AddressRanges &AR) {
+ size_t Size = AR.size();
+ for (size_t I = 0; I < Size; ++I) {
+ if (I)
+ OS << ' ';
+ OS << AR[I];
+ }
+ return OS;
+}
+
+void AddressRange::encode(FileWriter &O, uint64_t BaseAddr) const {
+ assert(Start >= BaseAddr);
+ O.writeULEB(Start - BaseAddr);
+ O.writeULEB(size());
+}
+
+void AddressRange::decode(DataExtractor &Data, uint64_t BaseAddr,
+ uint64_t &Offset) {
+ const uint64_t AddrOffset = Data.getULEB128(&Offset);
+ const uint64_t Size = Data.getULEB128(&Offset);
+ const uint64_t StartAddr = BaseAddr + AddrOffset;
+ Start = StartAddr;
+ End = StartAddr + Size;
+}
+
+void AddressRanges::encode(FileWriter &O, uint64_t BaseAddr) const {
+ O.writeULEB(Ranges.size());
+ if (Ranges.empty())
+ return;
+ for (auto Range : Ranges)
+ Range.encode(O, BaseAddr);
+}
+
+void AddressRanges::decode(DataExtractor &Data, uint64_t BaseAddr,
+ uint64_t &Offset) {
+ clear();
+ uint64_t NumRanges = Data.getULEB128(&Offset);
+ if (NumRanges == 0)
+ return;
+ Ranges.resize(NumRanges);
+ for (auto &Range : Ranges)
+ Range.decode(Data, BaseAddr, Offset);
+}
+
+void AddressRange::skip(DataExtractor &Data, uint64_t &Offset) {
+ Data.getULEB128(&Offset);
+ Data.getULEB128(&Offset);
+}
+
+uint64_t AddressRanges::skip(DataExtractor &Data, uint64_t &Offset) {
+ uint64_t NumRanges = Data.getULEB128(&Offset);
+ for (uint64_t I=0; I<NumRanges; ++I)
+ AddressRange::skip(Data, Offset);
+ return NumRanges;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/GSYM/ya.make b/contrib/libs/llvm14/lib/DebugInfo/GSYM/ya.make
new file mode 100644
index 0000000000..33ce427711
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/GSYM/ya.make
@@ -0,0 +1,39 @@
+# Generated by devtools/yamaker.
+
+LIBRARY()
+
+LICENSE(Apache-2.0 WITH LLVM-exception)
+
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
+PEERDIR(
+ contrib/libs/llvm14
+ contrib/libs/llvm14/lib/DebugInfo/DWARF
+ contrib/libs/llvm14/lib/MC
+ contrib/libs/llvm14/lib/Object
+ contrib/libs/llvm14/lib/Support
+)
+
+ADDINCL(
+ contrib/libs/llvm14/lib/DebugInfo/GSYM
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ DwarfTransformer.cpp
+ FileWriter.cpp
+ FunctionInfo.cpp
+ GsymCreator.cpp
+ GsymReader.cpp
+ Header.cpp
+ InlineInfo.cpp
+ LineTable.cpp
+ LookupResult.cpp
+ ObjectFileTransformer.cpp
+ Range.cpp
+)
+
+END()
diff --git a/contrib/libs/llvm14/lib/DebugInfo/MSF/MSFBuilder.cpp b/contrib/libs/llvm14/lib/DebugInfo/MSF/MSFBuilder.cpp
new file mode 100644
index 0000000000..f9a763d724
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/MSF/MSFBuilder.cpp
@@ -0,0 +1,401 @@
+//===- MSFBuilder.cpp -----------------------------------------------------===//
+//
+// 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/MSF/MSFBuilder.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/MSF/MSFError.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/FileOutputBuffer.h"
+#include "llvm/Support/FormatVariadic.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <memory>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::msf;
+using namespace llvm::support;
+
+static const uint32_t kSuperBlockBlock = 0;
+static const uint32_t kFreePageMap0Block = 1;
+static const uint32_t kFreePageMap1Block = 2;
+static const uint32_t kNumReservedPages = 3;
+
+static const uint32_t kDefaultFreePageMap = kFreePageMap1Block;
+static const uint32_t kDefaultBlockMapAddr = kNumReservedPages;
+
+MSFBuilder::MSFBuilder(uint32_t BlockSize, uint32_t MinBlockCount, bool CanGrow,
+ BumpPtrAllocator &Allocator)
+ : Allocator(Allocator), IsGrowable(CanGrow),
+ FreePageMap(kDefaultFreePageMap), BlockSize(BlockSize),
+ BlockMapAddr(kDefaultBlockMapAddr), FreeBlocks(MinBlockCount, true) {
+ FreeBlocks[kSuperBlockBlock] = false;
+ FreeBlocks[kFreePageMap0Block] = false;
+ FreeBlocks[kFreePageMap1Block] = false;
+ FreeBlocks[BlockMapAddr] = false;
+}
+
+Expected<MSFBuilder> MSFBuilder::create(BumpPtrAllocator &Allocator,
+ uint32_t BlockSize,
+ uint32_t MinBlockCount, bool CanGrow) {
+ if (!isValidBlockSize(BlockSize))
+ return make_error<MSFError>(msf_error_code::invalid_format,
+ "The requested block size is unsupported");
+
+ return MSFBuilder(BlockSize,
+ std::max(MinBlockCount, msf::getMinimumBlockCount()),
+ CanGrow, Allocator);
+}
+
+Error MSFBuilder::setBlockMapAddr(uint32_t Addr) {
+ if (Addr == BlockMapAddr)
+ return Error::success();
+
+ if (Addr >= FreeBlocks.size()) {
+ if (!IsGrowable)
+ return make_error<MSFError>(msf_error_code::insufficient_buffer,
+ "Cannot grow the number of blocks");
+ FreeBlocks.resize(Addr + 1, true);
+ }
+
+ if (!isBlockFree(Addr))
+ return make_error<MSFError>(
+ msf_error_code::block_in_use,
+ "Requested block map address is already in use");
+ FreeBlocks[BlockMapAddr] = true;
+ FreeBlocks[Addr] = false;
+ BlockMapAddr = Addr;
+ return Error::success();
+}
+
+void MSFBuilder::setFreePageMap(uint32_t Fpm) { FreePageMap = Fpm; }
+
+void MSFBuilder::setUnknown1(uint32_t Unk1) { Unknown1 = Unk1; }
+
+Error MSFBuilder::setDirectoryBlocksHint(ArrayRef<uint32_t> DirBlocks) {
+ for (auto B : DirectoryBlocks)
+ FreeBlocks[B] = true;
+ for (auto B : DirBlocks) {
+ if (!isBlockFree(B)) {
+ return make_error<MSFError>(msf_error_code::unspecified,
+ "Attempt to reuse an allocated block");
+ }
+ FreeBlocks[B] = false;
+ }
+
+ DirectoryBlocks = DirBlocks;
+ return Error::success();
+}
+
+Error MSFBuilder::allocateBlocks(uint32_t NumBlocks,
+ MutableArrayRef<uint32_t> Blocks) {
+ if (NumBlocks == 0)
+ return Error::success();
+
+ uint32_t NumFreeBlocks = FreeBlocks.count();
+ if (NumFreeBlocks < NumBlocks) {
+ if (!IsGrowable)
+ return make_error<MSFError>(msf_error_code::insufficient_buffer,
+ "There are no free Blocks in the file");
+ uint32_t AllocBlocks = NumBlocks - NumFreeBlocks;
+ uint32_t OldBlockCount = FreeBlocks.size();
+ uint32_t NewBlockCount = AllocBlocks + OldBlockCount;
+ uint32_t NextFpmBlock = alignTo(OldBlockCount, BlockSize) + 1;
+ FreeBlocks.resize(NewBlockCount, true);
+ // If we crossed over an fpm page, we actually need to allocate 2 extra
+ // blocks for each FPM group crossed and mark both blocks from the group as
+ // used. FPM blocks are marked as allocated regardless of whether or not
+ // they ultimately describe the status of blocks in the file. This means
+ // that not only are extraneous blocks at the end of the main FPM marked as
+ // allocated, but also blocks from the alternate FPM are always marked as
+ // allocated.
+ while (NextFpmBlock < NewBlockCount) {
+ NewBlockCount += 2;
+ FreeBlocks.resize(NewBlockCount, true);
+ FreeBlocks.reset(NextFpmBlock, NextFpmBlock + 2);
+ NextFpmBlock += BlockSize;
+ }
+ }
+
+ int I = 0;
+ int Block = FreeBlocks.find_first();
+ do {
+ assert(Block != -1 && "We ran out of Blocks!");
+
+ uint32_t NextBlock = static_cast<uint32_t>(Block);
+ Blocks[I++] = NextBlock;
+ FreeBlocks.reset(NextBlock);
+ Block = FreeBlocks.find_next(Block);
+ } while (--NumBlocks > 0);
+ return Error::success();
+}
+
+uint32_t MSFBuilder::getNumUsedBlocks() const {
+ return getTotalBlockCount() - getNumFreeBlocks();
+}
+
+uint32_t MSFBuilder::getNumFreeBlocks() const { return FreeBlocks.count(); }
+
+uint32_t MSFBuilder::getTotalBlockCount() const { return FreeBlocks.size(); }
+
+bool MSFBuilder::isBlockFree(uint32_t Idx) const { return FreeBlocks[Idx]; }
+
+Expected<uint32_t> MSFBuilder::addStream(uint32_t Size,
+ ArrayRef<uint32_t> Blocks) {
+ // Add a new stream mapped to the specified blocks. Verify that the specified
+ // blocks are both necessary and sufficient for holding the requested number
+ // of bytes, and verify that all requested blocks are free.
+ uint32_t ReqBlocks = bytesToBlocks(Size, BlockSize);
+ if (ReqBlocks != Blocks.size())
+ return make_error<MSFError>(
+ msf_error_code::invalid_format,
+ "Incorrect number of blocks for requested stream size");
+ for (auto Block : Blocks) {
+ if (Block >= FreeBlocks.size())
+ FreeBlocks.resize(Block + 1, true);
+
+ if (!FreeBlocks.test(Block))
+ return make_error<MSFError>(
+ msf_error_code::unspecified,
+ "Attempt to re-use an already allocated block");
+ }
+ // Mark all the blocks occupied by the new stream as not free.
+ for (auto Block : Blocks) {
+ FreeBlocks.reset(Block);
+ }
+ StreamData.push_back(std::make_pair(Size, Blocks));
+ return StreamData.size() - 1;
+}
+
+Expected<uint32_t> MSFBuilder::addStream(uint32_t Size) {
+ uint32_t ReqBlocks = bytesToBlocks(Size, BlockSize);
+ std::vector<uint32_t> NewBlocks;
+ NewBlocks.resize(ReqBlocks);
+ if (auto EC = allocateBlocks(ReqBlocks, NewBlocks))
+ return std::move(EC);
+ StreamData.push_back(std::make_pair(Size, NewBlocks));
+ return StreamData.size() - 1;
+}
+
+Error MSFBuilder::setStreamSize(uint32_t Idx, uint32_t Size) {
+ uint32_t OldSize = getStreamSize(Idx);
+ if (OldSize == Size)
+ return Error::success();
+
+ uint32_t NewBlocks = bytesToBlocks(Size, BlockSize);
+ uint32_t OldBlocks = bytesToBlocks(OldSize, BlockSize);
+
+ if (NewBlocks > OldBlocks) {
+ uint32_t AddedBlocks = NewBlocks - OldBlocks;
+ // If we're growing, we have to allocate new Blocks.
+ std::vector<uint32_t> AddedBlockList;
+ AddedBlockList.resize(AddedBlocks);
+ if (auto EC = allocateBlocks(AddedBlocks, AddedBlockList))
+ return EC;
+ auto &CurrentBlocks = StreamData[Idx].second;
+ llvm::append_range(CurrentBlocks, AddedBlockList);
+ } else if (OldBlocks > NewBlocks) {
+ // For shrinking, free all the Blocks in the Block map, update the stream
+ // data, then shrink the directory.
+ uint32_t RemovedBlocks = OldBlocks - NewBlocks;
+ auto CurrentBlocks = ArrayRef<uint32_t>(StreamData[Idx].second);
+ auto RemovedBlockList = CurrentBlocks.drop_front(NewBlocks);
+ for (auto P : RemovedBlockList)
+ FreeBlocks[P] = true;
+ StreamData[Idx].second = CurrentBlocks.drop_back(RemovedBlocks);
+ }
+
+ StreamData[Idx].first = Size;
+ return Error::success();
+}
+
+uint32_t MSFBuilder::getNumStreams() const { return StreamData.size(); }
+
+uint32_t MSFBuilder::getStreamSize(uint32_t StreamIdx) const {
+ return StreamData[StreamIdx].first;
+}
+
+ArrayRef<uint32_t> MSFBuilder::getStreamBlocks(uint32_t StreamIdx) const {
+ return StreamData[StreamIdx].second;
+}
+
+uint32_t MSFBuilder::computeDirectoryByteSize() const {
+ // The directory has the following layout, where each item is a ulittle32_t:
+ // NumStreams
+ // StreamSizes[NumStreams]
+ // StreamBlocks[NumStreams][]
+ uint32_t Size = sizeof(ulittle32_t); // NumStreams
+ Size += StreamData.size() * sizeof(ulittle32_t); // StreamSizes
+ for (const auto &D : StreamData) {
+ uint32_t ExpectedNumBlocks = bytesToBlocks(D.first, BlockSize);
+ assert(ExpectedNumBlocks == D.second.size() &&
+ "Unexpected number of blocks");
+ Size += ExpectedNumBlocks * sizeof(ulittle32_t);
+ }
+ return Size;
+}
+
+Expected<MSFLayout> MSFBuilder::generateLayout() {
+ SuperBlock *SB = Allocator.Allocate<SuperBlock>();
+ MSFLayout L;
+ L.SB = SB;
+
+ std::memcpy(SB->MagicBytes, Magic, sizeof(Magic));
+ SB->BlockMapAddr = BlockMapAddr;
+ SB->BlockSize = BlockSize;
+ SB->NumDirectoryBytes = computeDirectoryByteSize();
+ SB->FreeBlockMapBlock = FreePageMap;
+ SB->Unknown1 = Unknown1;
+
+ uint32_t NumDirectoryBlocks = bytesToBlocks(SB->NumDirectoryBytes, BlockSize);
+ if (NumDirectoryBlocks > DirectoryBlocks.size()) {
+ // Our hint wasn't enough to satisfy the entire directory. Allocate
+ // remaining pages.
+ std::vector<uint32_t> ExtraBlocks;
+ uint32_t NumExtraBlocks = NumDirectoryBlocks - DirectoryBlocks.size();
+ ExtraBlocks.resize(NumExtraBlocks);
+ if (auto EC = allocateBlocks(NumExtraBlocks, ExtraBlocks))
+ return std::move(EC);
+ llvm::append_range(DirectoryBlocks, ExtraBlocks);
+ } else if (NumDirectoryBlocks < DirectoryBlocks.size()) {
+ uint32_t NumUnnecessaryBlocks = DirectoryBlocks.size() - NumDirectoryBlocks;
+ for (auto B :
+ ArrayRef<uint32_t>(DirectoryBlocks).drop_back(NumUnnecessaryBlocks))
+ FreeBlocks[B] = true;
+ DirectoryBlocks.resize(NumDirectoryBlocks);
+ }
+
+ // Don't set the number of blocks in the file until after allocating Blocks
+ // for the directory, since the allocation might cause the file to need to
+ // grow.
+ SB->NumBlocks = FreeBlocks.size();
+
+ ulittle32_t *DirBlocks = Allocator.Allocate<ulittle32_t>(NumDirectoryBlocks);
+ std::uninitialized_copy_n(DirectoryBlocks.begin(), NumDirectoryBlocks,
+ DirBlocks);
+ L.DirectoryBlocks = ArrayRef<ulittle32_t>(DirBlocks, NumDirectoryBlocks);
+
+ // The stream sizes should be re-allocated as a stable pointer and the stream
+ // map should have each of its entries allocated as a separate stable pointer.
+ if (!StreamData.empty()) {
+ ulittle32_t *Sizes = Allocator.Allocate<ulittle32_t>(StreamData.size());
+ L.StreamSizes = ArrayRef<ulittle32_t>(Sizes, StreamData.size());
+ L.StreamMap.resize(StreamData.size());
+ for (uint32_t I = 0; I < StreamData.size(); ++I) {
+ Sizes[I] = StreamData[I].first;
+ ulittle32_t *BlockList =
+ Allocator.Allocate<ulittle32_t>(StreamData[I].second.size());
+ std::uninitialized_copy_n(StreamData[I].second.begin(),
+ StreamData[I].second.size(), BlockList);
+ L.StreamMap[I] =
+ ArrayRef<ulittle32_t>(BlockList, StreamData[I].second.size());
+ }
+ }
+
+ L.FreePageMap = FreeBlocks;
+
+ return L;
+}
+
+static void commitFpm(WritableBinaryStream &MsfBuffer, const MSFLayout &Layout,
+ BumpPtrAllocator &Allocator) {
+ auto FpmStream =
+ WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator);
+
+ // We only need to create the alt fpm stream so that it gets initialized.
+ WritableMappedBlockStream::createFpmStream(Layout, MsfBuffer, Allocator,
+ true);
+
+ uint32_t BI = 0;
+ BinaryStreamWriter FpmWriter(*FpmStream);
+ while (BI < Layout.SB->NumBlocks) {
+ uint8_t ThisByte = 0;
+ for (uint32_t I = 0; I < 8; ++I) {
+ bool IsFree =
+ (BI < Layout.SB->NumBlocks) ? Layout.FreePageMap.test(BI) : true;
+ uint8_t Mask = uint8_t(IsFree) << I;
+ ThisByte |= Mask;
+ ++BI;
+ }
+ cantFail(FpmWriter.writeObject(ThisByte));
+ }
+ assert(FpmWriter.bytesRemaining() == 0);
+}
+
+Expected<FileBufferByteStream> MSFBuilder::commit(StringRef Path,
+ MSFLayout &Layout) {
+ Expected<MSFLayout> L = generateLayout();
+ if (!L)
+ return L.takeError();
+
+ Layout = std::move(*L);
+
+ uint64_t FileSize = uint64_t(Layout.SB->BlockSize) * Layout.SB->NumBlocks;
+ // Ensure that the file size is under the limit for the specified block size.
+ if (FileSize > getMaxFileSizeFromBlockSize(Layout.SB->BlockSize)) {
+ msf_error_code error_code = [](uint32_t BlockSize) {
+ switch (BlockSize) {
+ case 8192:
+ return msf_error_code::size_overflow_8192;
+ case 16384:
+ return msf_error_code::size_overflow_16384;
+ case 32768:
+ return msf_error_code::size_overflow_32768;
+ default:
+ return msf_error_code::size_overflow_4096;
+ }
+ }(Layout.SB->BlockSize);
+
+ return make_error<MSFError>(
+ error_code,
+ formatv("File size {0,1:N} too large for current PDB page size {1}",
+ FileSize, Layout.SB->BlockSize));
+ }
+
+ auto OutFileOrError = FileOutputBuffer::create(Path, FileSize);
+ if (auto EC = OutFileOrError.takeError())
+ return std::move(EC);
+
+ FileBufferByteStream Buffer(std::move(*OutFileOrError),
+ llvm::support::little);
+ BinaryStreamWriter Writer(Buffer);
+
+ if (auto EC = Writer.writeObject(*Layout.SB))
+ return std::move(EC);
+
+ commitFpm(Buffer, Layout, Allocator);
+
+ uint32_t BlockMapOffset =
+ msf::blockToOffset(Layout.SB->BlockMapAddr, Layout.SB->BlockSize);
+ Writer.setOffset(BlockMapOffset);
+ if (auto EC = Writer.writeArray(Layout.DirectoryBlocks))
+ return std::move(EC);
+
+ auto DirStream = WritableMappedBlockStream::createDirectoryStream(
+ Layout, Buffer, Allocator);
+ BinaryStreamWriter DW(*DirStream);
+ if (auto EC = DW.writeInteger<uint32_t>(Layout.StreamSizes.size()))
+ return std::move(EC);
+
+ if (auto EC = DW.writeArray(Layout.StreamSizes))
+ return std::move(EC);
+
+ for (const auto &Blocks : Layout.StreamMap) {
+ if (auto EC = DW.writeArray(Blocks))
+ return std::move(EC);
+ }
+
+ return std::move(Buffer);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/MSF/MSFCommon.cpp b/contrib/libs/llvm14/lib/DebugInfo/MSF/MSFCommon.cpp
new file mode 100644
index 0000000000..fb4f070005
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/MSF/MSFCommon.cpp
@@ -0,0 +1,82 @@
+//===- MSFCommon.cpp - Common types and functions for MSF files -----------===//
+//
+// 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/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/MSF/MSFError.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+#include <cstring>
+
+using namespace llvm;
+using namespace llvm::msf;
+
+Error llvm::msf::validateSuperBlock(const SuperBlock &SB) {
+ // Check the magic bytes.
+ if (std::memcmp(SB.MagicBytes, Magic, sizeof(Magic)) != 0)
+ return make_error<MSFError>(msf_error_code::invalid_format,
+ "MSF magic header doesn't match");
+
+ if (!isValidBlockSize(SB.BlockSize))
+ return make_error<MSFError>(msf_error_code::invalid_format,
+ "Unsupported block size.");
+
+ // We don't support directories whose sizes aren't a multiple of four bytes.
+ if (SB.NumDirectoryBytes % sizeof(support::ulittle32_t) != 0)
+ return make_error<MSFError>(msf_error_code::invalid_format,
+ "Directory size is not multiple of 4.");
+
+ // The number of blocks which comprise the directory is a simple function of
+ // the number of bytes it contains.
+ uint64_t NumDirectoryBlocks =
+ bytesToBlocks(SB.NumDirectoryBytes, SB.BlockSize);
+
+ // The directory, as we understand it, is a block which consists of a list of
+ // block numbers. It is unclear what would happen if the number of blocks
+ // couldn't fit on a single block.
+ if (NumDirectoryBlocks > SB.BlockSize / sizeof(support::ulittle32_t))
+ return make_error<MSFError>(msf_error_code::invalid_format,
+ "Too many directory blocks.");
+
+ if (SB.BlockMapAddr == 0)
+ return make_error<MSFError>(msf_error_code::invalid_format,
+ "Block 0 is reserved");
+
+ if (SB.BlockMapAddr >= SB.NumBlocks)
+ return make_error<MSFError>(msf_error_code::invalid_format,
+ "Block map address is invalid.");
+
+ if (SB.FreeBlockMapBlock != 1 && SB.FreeBlockMapBlock != 2)
+ return make_error<MSFError>(
+ msf_error_code::invalid_format,
+ "The free block map isn't at block 1 or block 2.");
+
+ return Error::success();
+}
+
+MSFStreamLayout llvm::msf::getFpmStreamLayout(const MSFLayout &Msf,
+ bool IncludeUnusedFpmData,
+ bool AltFpm) {
+ MSFStreamLayout FL;
+ uint32_t NumFpmIntervals =
+ getNumFpmIntervals(Msf, IncludeUnusedFpmData, AltFpm);
+
+ uint32_t FpmBlock = AltFpm ? Msf.alternateFpmBlock() : Msf.mainFpmBlock();
+
+ for (uint32_t I = 0; I < NumFpmIntervals; ++I) {
+ FL.Blocks.push_back(support::ulittle32_t(FpmBlock));
+ FpmBlock += msf::getFpmIntervalLength(Msf);
+ }
+
+ if (IncludeUnusedFpmData)
+ FL.Length = NumFpmIntervals * Msf.SB->BlockSize;
+ else
+ FL.Length = divideCeil(Msf.SB->NumBlocks, 8);
+
+ return FL;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/MSF/MSFError.cpp b/contrib/libs/llvm14/lib/DebugInfo/MSF/MSFError.cpp
new file mode 100644
index 0000000000..9df2158423
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/MSF/MSFError.cpp
@@ -0,0 +1,56 @@
+//===- MSFError.cpp - Error extensions for MSF files ------------*- 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/MSF/MSFError.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+#include <string>
+
+using namespace llvm;
+using namespace llvm::msf;
+
+namespace {
+// FIXME: This class is only here to support the transition to llvm::Error. It
+// will be removed once this transition is complete. Clients should prefer to
+// deal with the Error value directly, rather than converting to error_code.
+class MSFErrorCategory : public std::error_category {
+public:
+ const char *name() const noexcept override { return "llvm.msf"; }
+ std::string message(int Condition) const override {
+ switch (static_cast<msf_error_code>(Condition)) {
+ case msf_error_code::unspecified:
+ return "An unknown error has occurred.";
+ case msf_error_code::insufficient_buffer:
+ return "The buffer is not large enough to read the requested number of "
+ "bytes.";
+ case msf_error_code::size_overflow_4096:
+ return "Output data is larger than 4 GiB.";
+ case msf_error_code::size_overflow_8192:
+ return "Output data is larger than 8 GiB.";
+ case msf_error_code::size_overflow_16384:
+ return "Output data is larger than 16 GiB.";
+ case msf_error_code::size_overflow_32768:
+ return "Output data is larger than 32 GiB.";
+ case msf_error_code::not_writable:
+ return "The specified stream is not writable.";
+ case msf_error_code::no_stream:
+ return "The specified stream does not exist.";
+ case msf_error_code::invalid_format:
+ return "The data is in an unexpected format.";
+ case msf_error_code::block_in_use:
+ return "The block is already in use.";
+ }
+ llvm_unreachable("Unrecognized msf_error_code");
+ }
+};
+} // namespace
+
+static llvm::ManagedStatic<MSFErrorCategory> MSFCategory;
+const std::error_category &llvm::msf::MSFErrCategory() { return *MSFCategory; }
+
+char MSFError::ID;
diff --git a/contrib/libs/llvm14/lib/DebugInfo/MSF/MappedBlockStream.cpp b/contrib/libs/llvm14/lib/DebugInfo/MSF/MappedBlockStream.cpp
new file mode 100644
index 0000000000..00fc70ca5a
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/MSF/MappedBlockStream.cpp
@@ -0,0 +1,421 @@
+//===- MappedBlockStream.cpp - Reads stream data from an MSF file ---------===//
+//
+// 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/MSF/MappedBlockStream.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MathExtras.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <cstring>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::msf;
+
+namespace {
+
+template <typename Base> class MappedBlockStreamImpl : public Base {
+public:
+ template <typename... Args>
+ MappedBlockStreamImpl(Args &&... Params)
+ : Base(std::forward<Args>(Params)...) {}
+};
+
+} // end anonymous namespace
+
+using Interval = std::pair<uint64_t, uint64_t>;
+
+static Interval intersect(const Interval &I1, const Interval &I2) {
+ return std::make_pair(std::max(I1.first, I2.first),
+ std::min(I1.second, I2.second));
+}
+
+MappedBlockStream::MappedBlockStream(uint32_t BlockSize,
+ const MSFStreamLayout &Layout,
+ BinaryStreamRef MsfData,
+ BumpPtrAllocator &Allocator)
+ : BlockSize(BlockSize), StreamLayout(Layout), MsfData(MsfData),
+ Allocator(Allocator) {}
+
+std::unique_ptr<MappedBlockStream> MappedBlockStream::createStream(
+ uint32_t BlockSize, const MSFStreamLayout &Layout, BinaryStreamRef MsfData,
+ BumpPtrAllocator &Allocator) {
+ return std::make_unique<MappedBlockStreamImpl<MappedBlockStream>>(
+ BlockSize, Layout, MsfData, Allocator);
+}
+
+std::unique_ptr<MappedBlockStream> MappedBlockStream::createIndexedStream(
+ const MSFLayout &Layout, BinaryStreamRef MsfData, uint32_t StreamIndex,
+ BumpPtrAllocator &Allocator) {
+ assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index");
+ MSFStreamLayout SL;
+ SL.Blocks = Layout.StreamMap[StreamIndex];
+ SL.Length = Layout.StreamSizes[StreamIndex];
+ return std::make_unique<MappedBlockStreamImpl<MappedBlockStream>>(
+ Layout.SB->BlockSize, SL, MsfData, Allocator);
+}
+
+std::unique_ptr<MappedBlockStream>
+MappedBlockStream::createDirectoryStream(const MSFLayout &Layout,
+ BinaryStreamRef MsfData,
+ BumpPtrAllocator &Allocator) {
+ MSFStreamLayout SL;
+ SL.Blocks = Layout.DirectoryBlocks;
+ SL.Length = Layout.SB->NumDirectoryBytes;
+ return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator);
+}
+
+std::unique_ptr<MappedBlockStream>
+MappedBlockStream::createFpmStream(const MSFLayout &Layout,
+ BinaryStreamRef MsfData,
+ BumpPtrAllocator &Allocator) {
+ MSFStreamLayout SL(getFpmStreamLayout(Layout));
+ return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator);
+}
+
+Error MappedBlockStream::readBytes(uint64_t Offset, uint64_t Size,
+ ArrayRef<uint8_t> &Buffer) {
+ // Make sure we aren't trying to read beyond the end of the stream.
+ if (auto EC = checkOffsetForRead(Offset, Size))
+ return EC;
+
+ if (tryReadContiguously(Offset, Size, Buffer))
+ return Error::success();
+
+ auto CacheIter = CacheMap.find(Offset);
+ if (CacheIter != CacheMap.end()) {
+ // Try to find an alloc that was large enough for this request.
+ for (auto &Entry : CacheIter->second) {
+ if (Entry.size() >= Size) {
+ Buffer = Entry.slice(0, Size);
+ return Error::success();
+ }
+ }
+ }
+
+ // We couldn't find a buffer that started at the correct offset (the most
+ // common scenario). Try to see if there is a buffer that starts at some
+ // other offset but overlaps the desired range.
+ for (auto &CacheItem : CacheMap) {
+ Interval RequestExtent = std::make_pair(Offset, Offset + Size);
+
+ // We already checked this one on the fast path above.
+ if (CacheItem.first == Offset)
+ continue;
+ // If the initial extent of the cached item is beyond the ending extent
+ // of the request, there is no overlap.
+ if (CacheItem.first >= Offset + Size)
+ continue;
+
+ // We really only have to check the last item in the list, since we append
+ // in order of increasing length.
+ if (CacheItem.second.empty())
+ continue;
+
+ auto CachedAlloc = CacheItem.second.back();
+ // If the initial extent of the request is beyond the ending extent of
+ // the cached item, there is no overlap.
+ Interval CachedExtent =
+ std::make_pair(CacheItem.first, CacheItem.first + CachedAlloc.size());
+ if (RequestExtent.first >= CachedExtent.first + CachedExtent.second)
+ continue;
+
+ Interval Intersection = intersect(CachedExtent, RequestExtent);
+ // Only use this if the entire request extent is contained in the cached
+ // extent.
+ if (Intersection != RequestExtent)
+ continue;
+
+ uint64_t CacheRangeOffset =
+ AbsoluteDifference(CachedExtent.first, Intersection.first);
+ Buffer = CachedAlloc.slice(CacheRangeOffset, Size);
+ return Error::success();
+ }
+
+ // Otherwise allocate a large enough buffer in the pool, memcpy the data
+ // into it, and return an ArrayRef to that. Do not touch existing pool
+ // allocations, as existing clients may be holding a pointer which must
+ // not be invalidated.
+ uint8_t *WriteBuffer = static_cast<uint8_t *>(Allocator.Allocate(Size, 8));
+ if (auto EC = readBytes(Offset, MutableArrayRef<uint8_t>(WriteBuffer, Size)))
+ return EC;
+
+ if (CacheIter != CacheMap.end()) {
+ CacheIter->second.emplace_back(WriteBuffer, Size);
+ } else {
+ std::vector<CacheEntry> List;
+ List.emplace_back(WriteBuffer, Size);
+ CacheMap.insert(std::make_pair(Offset, List));
+ }
+ Buffer = ArrayRef<uint8_t>(WriteBuffer, Size);
+ return Error::success();
+}
+
+Error MappedBlockStream::readLongestContiguousChunk(uint64_t Offset,
+ ArrayRef<uint8_t> &Buffer) {
+ // Make sure we aren't trying to read beyond the end of the stream.
+ if (auto EC = checkOffsetForRead(Offset, 1))
+ return EC;
+
+ uint64_t First = Offset / BlockSize;
+ uint64_t Last = First;
+
+ while (Last < getNumBlocks() - 1) {
+ if (StreamLayout.Blocks[Last] != StreamLayout.Blocks[Last + 1] - 1)
+ break;
+ ++Last;
+ }
+
+ uint64_t OffsetInFirstBlock = Offset % BlockSize;
+ uint64_t BytesFromFirstBlock = BlockSize - OffsetInFirstBlock;
+ uint64_t BlockSpan = Last - First + 1;
+ uint64_t ByteSpan = BytesFromFirstBlock + (BlockSpan - 1) * BlockSize;
+
+ ArrayRef<uint8_t> BlockData;
+ uint64_t MsfOffset = blockToOffset(StreamLayout.Blocks[First], BlockSize);
+ if (auto EC = MsfData.readBytes(MsfOffset, BlockSize, BlockData))
+ return EC;
+
+ BlockData = BlockData.drop_front(OffsetInFirstBlock);
+ Buffer = ArrayRef<uint8_t>(BlockData.data(), ByteSpan);
+ return Error::success();
+}
+
+uint64_t MappedBlockStream::getLength() { return StreamLayout.Length; }
+
+bool MappedBlockStream::tryReadContiguously(uint64_t Offset, uint64_t Size,
+ ArrayRef<uint8_t> &Buffer) {
+ if (Size == 0) {
+ Buffer = ArrayRef<uint8_t>();
+ return true;
+ }
+ // Attempt to fulfill the request with a reference directly into the stream.
+ // This can work even if the request crosses a block boundary, provided that
+ // all subsequent blocks are contiguous. For example, a 10k read with a 4k
+ // block size can be filled with a reference if, from the starting offset,
+ // 3 blocks in a row are contiguous.
+ uint64_t BlockNum = Offset / BlockSize;
+ uint64_t OffsetInBlock = Offset % BlockSize;
+ uint64_t BytesFromFirstBlock = std::min(Size, BlockSize - OffsetInBlock);
+ uint64_t NumAdditionalBlocks =
+ alignTo(Size - BytesFromFirstBlock, BlockSize) / BlockSize;
+
+ uint64_t RequiredContiguousBlocks = NumAdditionalBlocks + 1;
+ uint64_t E = StreamLayout.Blocks[BlockNum];
+ for (uint64_t I = 0; I < RequiredContiguousBlocks; ++I, ++E) {
+ if (StreamLayout.Blocks[I + BlockNum] != E)
+ return false;
+ }
+
+ // Read out the entire block where the requested offset starts. Then drop
+ // bytes from the beginning so that the actual starting byte lines up with
+ // the requested starting byte. Then, since we know this is a contiguous
+ // cross-block span, explicitly resize the ArrayRef to cover the entire
+ // request length.
+ ArrayRef<uint8_t> BlockData;
+ uint64_t FirstBlockAddr = StreamLayout.Blocks[BlockNum];
+ uint64_t MsfOffset = blockToOffset(FirstBlockAddr, BlockSize);
+ if (auto EC = MsfData.readBytes(MsfOffset, BlockSize, BlockData)) {
+ consumeError(std::move(EC));
+ return false;
+ }
+ BlockData = BlockData.drop_front(OffsetInBlock);
+ Buffer = ArrayRef<uint8_t>(BlockData.data(), Size);
+ return true;
+}
+
+Error MappedBlockStream::readBytes(uint64_t Offset,
+ MutableArrayRef<uint8_t> Buffer) {
+ uint64_t BlockNum = Offset / BlockSize;
+ uint64_t OffsetInBlock = Offset % BlockSize;
+
+ // Make sure we aren't trying to read beyond the end of the stream.
+ if (auto EC = checkOffsetForRead(Offset, Buffer.size()))
+ return EC;
+
+ uint64_t BytesLeft = Buffer.size();
+ uint64_t BytesWritten = 0;
+ uint8_t *WriteBuffer = Buffer.data();
+ while (BytesLeft > 0) {
+ uint64_t StreamBlockAddr = StreamLayout.Blocks[BlockNum];
+
+ ArrayRef<uint8_t> BlockData;
+ uint64_t Offset = blockToOffset(StreamBlockAddr, BlockSize);
+ if (auto EC = MsfData.readBytes(Offset, BlockSize, BlockData))
+ return EC;
+
+ const uint8_t *ChunkStart = BlockData.data() + OffsetInBlock;
+ uint64_t BytesInChunk = std::min(BytesLeft, BlockSize - OffsetInBlock);
+ ::memcpy(WriteBuffer + BytesWritten, ChunkStart, BytesInChunk);
+
+ BytesWritten += BytesInChunk;
+ BytesLeft -= BytesInChunk;
+ ++BlockNum;
+ OffsetInBlock = 0;
+ }
+
+ return Error::success();
+}
+
+void MappedBlockStream::invalidateCache() { CacheMap.shrink_and_clear(); }
+
+void MappedBlockStream::fixCacheAfterWrite(uint64_t Offset,
+ ArrayRef<uint8_t> Data) const {
+ // If this write overlapped a read which previously came from the pool,
+ // someone may still be holding a pointer to that alloc which is now invalid.
+ // Compute the overlapping range and update the cache entry, so any
+ // outstanding buffers are automatically updated.
+ for (const auto &MapEntry : CacheMap) {
+ // If the end of the written extent precedes the beginning of the cached
+ // extent, ignore this map entry.
+ if (Offset + Data.size() < MapEntry.first)
+ continue;
+ for (const auto &Alloc : MapEntry.second) {
+ // If the end of the cached extent precedes the beginning of the written
+ // extent, ignore this alloc.
+ if (MapEntry.first + Alloc.size() < Offset)
+ continue;
+
+ // If we get here, they are guaranteed to overlap.
+ Interval WriteInterval = std::make_pair(Offset, Offset + Data.size());
+ Interval CachedInterval =
+ std::make_pair(MapEntry.first, MapEntry.first + Alloc.size());
+ // If they overlap, we need to write the new data into the overlapping
+ // range.
+ auto Intersection = intersect(WriteInterval, CachedInterval);
+ assert(Intersection.first <= Intersection.second);
+
+ uint64_t Length = Intersection.second - Intersection.first;
+ uint64_t SrcOffset =
+ AbsoluteDifference(WriteInterval.first, Intersection.first);
+ uint64_t DestOffset =
+ AbsoluteDifference(CachedInterval.first, Intersection.first);
+ ::memcpy(Alloc.data() + DestOffset, Data.data() + SrcOffset, Length);
+ }
+ }
+}
+
+WritableMappedBlockStream::WritableMappedBlockStream(
+ uint32_t BlockSize, const MSFStreamLayout &Layout,
+ WritableBinaryStreamRef MsfData, BumpPtrAllocator &Allocator)
+ : ReadInterface(BlockSize, Layout, MsfData, Allocator),
+ WriteInterface(MsfData) {}
+
+std::unique_ptr<WritableMappedBlockStream>
+WritableMappedBlockStream::createStream(uint32_t BlockSize,
+ const MSFStreamLayout &Layout,
+ WritableBinaryStreamRef MsfData,
+ BumpPtrAllocator &Allocator) {
+ return std::make_unique<MappedBlockStreamImpl<WritableMappedBlockStream>>(
+ BlockSize, Layout, MsfData, Allocator);
+}
+
+std::unique_ptr<WritableMappedBlockStream>
+WritableMappedBlockStream::createIndexedStream(const MSFLayout &Layout,
+ WritableBinaryStreamRef MsfData,
+ uint32_t StreamIndex,
+ BumpPtrAllocator &Allocator) {
+ assert(StreamIndex < Layout.StreamMap.size() && "Invalid stream index");
+ MSFStreamLayout SL;
+ SL.Blocks = Layout.StreamMap[StreamIndex];
+ SL.Length = Layout.StreamSizes[StreamIndex];
+ return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator);
+}
+
+std::unique_ptr<WritableMappedBlockStream>
+WritableMappedBlockStream::createDirectoryStream(
+ const MSFLayout &Layout, WritableBinaryStreamRef MsfData,
+ BumpPtrAllocator &Allocator) {
+ MSFStreamLayout SL;
+ SL.Blocks = Layout.DirectoryBlocks;
+ SL.Length = Layout.SB->NumDirectoryBytes;
+ return createStream(Layout.SB->BlockSize, SL, MsfData, Allocator);
+}
+
+std::unique_ptr<WritableMappedBlockStream>
+WritableMappedBlockStream::createFpmStream(const MSFLayout &Layout,
+ WritableBinaryStreamRef MsfData,
+ BumpPtrAllocator &Allocator,
+ bool AltFpm) {
+ // We only want to give the user a stream containing the bytes of the FPM that
+ // are actually valid, but we want to initialize all of the bytes, even those
+ // that come from reserved FPM blocks where the entire block is unused. To do
+ // this, we first create the full layout, which gives us a stream with all
+ // bytes and all blocks, and initialize everything to 0xFF (all blocks in the
+ // file are unused). Then we create the minimal layout (which contains only a
+ // subset of the bytes previously initialized), and return that to the user.
+ MSFStreamLayout MinLayout(getFpmStreamLayout(Layout, false, AltFpm));
+
+ MSFStreamLayout FullLayout(getFpmStreamLayout(Layout, true, AltFpm));
+ auto Result =
+ createStream(Layout.SB->BlockSize, FullLayout, MsfData, Allocator);
+ if (!Result)
+ return Result;
+ std::vector<uint8_t> InitData(Layout.SB->BlockSize, 0xFF);
+ BinaryStreamWriter Initializer(*Result);
+ while (Initializer.bytesRemaining() > 0)
+ cantFail(Initializer.writeBytes(InitData));
+ return createStream(Layout.SB->BlockSize, MinLayout, MsfData, Allocator);
+}
+
+Error WritableMappedBlockStream::readBytes(uint64_t Offset, uint64_t Size,
+ ArrayRef<uint8_t> &Buffer) {
+ return ReadInterface.readBytes(Offset, Size, Buffer);
+}
+
+Error WritableMappedBlockStream::readLongestContiguousChunk(
+ uint64_t Offset, ArrayRef<uint8_t> &Buffer) {
+ return ReadInterface.readLongestContiguousChunk(Offset, Buffer);
+}
+
+uint64_t WritableMappedBlockStream::getLength() {
+ return ReadInterface.getLength();
+}
+
+Error WritableMappedBlockStream::writeBytes(uint64_t Offset,
+ ArrayRef<uint8_t> Buffer) {
+ // Make sure we aren't trying to write beyond the end of the stream.
+ if (auto EC = checkOffsetForWrite(Offset, Buffer.size()))
+ return EC;
+
+ uint64_t BlockNum = Offset / getBlockSize();
+ uint64_t OffsetInBlock = Offset % getBlockSize();
+
+ uint64_t BytesLeft = Buffer.size();
+ uint64_t BytesWritten = 0;
+ while (BytesLeft > 0) {
+ uint64_t StreamBlockAddr = getStreamLayout().Blocks[BlockNum];
+ uint64_t BytesToWriteInChunk =
+ std::min(BytesLeft, getBlockSize() - OffsetInBlock);
+
+ const uint8_t *Chunk = Buffer.data() + BytesWritten;
+ ArrayRef<uint8_t> ChunkData(Chunk, BytesToWriteInChunk);
+ uint64_t MsfOffset = blockToOffset(StreamBlockAddr, getBlockSize());
+ MsfOffset += OffsetInBlock;
+ if (auto EC = WriteInterface.writeBytes(MsfOffset, ChunkData))
+ return EC;
+
+ BytesLeft -= BytesToWriteInChunk;
+ BytesWritten += BytesToWriteInChunk;
+ ++BlockNum;
+ OffsetInBlock = 0;
+ }
+
+ ReadInterface.fixCacheAfterWrite(Offset, Buffer);
+
+ return Error::success();
+}
+
+Error WritableMappedBlockStream::commit() { return WriteInterface.commit(); }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/MSF/ya.make b/contrib/libs/llvm14/lib/DebugInfo/MSF/ya.make
new file mode 100644
index 0000000000..bb504bb453
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/MSF/ya.make
@@ -0,0 +1,29 @@
+# Generated by devtools/yamaker.
+
+LIBRARY()
+
+LICENSE(Apache-2.0 WITH LLVM-exception)
+
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
+PEERDIR(
+ contrib/libs/llvm14
+ contrib/libs/llvm14/lib/Support
+)
+
+ADDINCL(
+ contrib/libs/llvm14/lib/DebugInfo/MSF
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ MSFBuilder.cpp
+ MSFCommon.cpp
+ MSFError.cpp
+ MappedBlockStream.cpp
+)
+
+END()
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/GenericError.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/GenericError.cpp
new file mode 100644
index 0000000000..0e4cba3174
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/GenericError.cpp
@@ -0,0 +1,48 @@
+//===- Error.cpp - system_error extensions for PDB --------------*- 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/PDB/GenericError.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+namespace {
+// FIXME: This class is only here to support the transition to llvm::Error. It
+// will be removed once this transition is complete. Clients should prefer to
+// deal with the Error value directly, rather than converting to error_code.
+class PDBErrorCategory : public std::error_category {
+public:
+ const char *name() const noexcept override { return "llvm.pdb"; }
+ std::string message(int Condition) const override {
+ switch (static_cast<pdb_error_code>(Condition)) {
+ case pdb_error_code::unspecified:
+ return "An unknown error has occurred.";
+ case pdb_error_code::dia_sdk_not_present:
+ return "LLVM was not compiled with support for DIA. This usually means "
+ "that you are not using MSVC, or your Visual Studio "
+ "installation is corrupt.";
+ case pdb_error_code::dia_failed_loading:
+ return "DIA is only supported when using MSVC.";
+ case pdb_error_code::invalid_utf8_path:
+ return "The PDB file path is an invalid UTF8 sequence.";
+ case pdb_error_code::signature_out_of_date:
+ return "The signature does not match; the file(s) might be out of date.";
+ case pdb_error_code::no_matching_pch:
+ return "No matching precompiled header could be located.";
+ }
+ llvm_unreachable("Unrecognized generic_error_code");
+ }
+};
+} // namespace
+
+static llvm::ManagedStatic<PDBErrorCategory> PDBCategory;
+const std::error_category &llvm::pdb::PDBErrCategory() { return *PDBCategory; }
+
+char PDBError::ID;
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/IPDBSourceFile.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/IPDBSourceFile.cpp
new file mode 100644
index 0000000000..113ee04bab
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/IPDBSourceFile.cpp
@@ -0,0 +1,34 @@
+//===- IPDBSourceFile.cpp - base interface for a PDB source file ----------===//
+//
+// 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/PDB/IPDBSourceFile.h"
+#include "llvm/DebugInfo/PDB/PDBExtras.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/raw_ostream.h"
+#include <cstdint>
+#include <string>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+IPDBSourceFile::~IPDBSourceFile() = default;
+
+void IPDBSourceFile::dump(raw_ostream &OS, int Indent) const {
+ OS.indent(Indent);
+ PDB_Checksum ChecksumType = getChecksumType();
+ OS << "[";
+ if (ChecksumType != PDB_Checksum::None) {
+ OS << ChecksumType << ": ";
+ std::string Checksum = getChecksum();
+ for (uint8_t c : Checksum)
+ OS << format_hex_no_prefix(c, 2, true);
+ } else
+ OS << "No checksum";
+ OS << "] " << getFileName() << "\n";
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp
new file mode 100644
index 0000000000..9755f2ca3b
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiModuleDescriptor.cpp
@@ -0,0 +1,86 @@
+//===- DbiModuleDescriptor.cpp - PDB module information -------------------===//
+//
+// 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/PDB/Native/DbiModuleDescriptor.h"
+#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MathExtras.h"
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::pdb;
+using namespace llvm::support;
+
+Error DbiModuleDescriptor::initialize(BinaryStreamRef Stream,
+ DbiModuleDescriptor &Info) {
+ BinaryStreamReader Reader(Stream);
+ if (auto EC = Reader.readObject(Info.Layout))
+ return EC;
+
+ if (auto EC = Reader.readCString(Info.ModuleName))
+ return EC;
+
+ if (auto EC = Reader.readCString(Info.ObjFileName))
+ return EC;
+ return Error::success();
+}
+
+bool DbiModuleDescriptor::hasECInfo() const {
+ return (Layout->Flags & ModInfoFlags::HasECFlagMask) != 0;
+}
+
+uint16_t DbiModuleDescriptor::getTypeServerIndex() const {
+ return (Layout->Flags & ModInfoFlags::TypeServerIndexMask) >>
+ ModInfoFlags::TypeServerIndexShift;
+}
+
+const SectionContrib &DbiModuleDescriptor::getSectionContrib() const {
+ return Layout->SC;
+}
+
+uint16_t DbiModuleDescriptor::getModuleStreamIndex() const {
+ return Layout->ModDiStream;
+}
+
+uint32_t DbiModuleDescriptor::getSymbolDebugInfoByteSize() const {
+ return Layout->SymBytes;
+}
+
+uint32_t DbiModuleDescriptor::getC11LineInfoByteSize() const {
+ return Layout->C11Bytes;
+}
+
+uint32_t DbiModuleDescriptor::getC13LineInfoByteSize() const {
+ return Layout->C13Bytes;
+}
+
+uint32_t DbiModuleDescriptor::getNumberOfFiles() const {
+ return Layout->NumFiles;
+}
+
+uint32_t DbiModuleDescriptor::getSourceFileNameIndex() const {
+ return Layout->SrcFileNameNI;
+}
+
+uint32_t DbiModuleDescriptor::getPdbFilePathNameIndex() const {
+ return Layout->PdbFilePathNI;
+}
+
+StringRef DbiModuleDescriptor::getModuleName() const { return ModuleName; }
+
+StringRef DbiModuleDescriptor::getObjFileName() const { return ObjFileName; }
+
+uint32_t DbiModuleDescriptor::getRecordLength() const {
+ uint32_t M = ModuleName.str().size() + 1;
+ uint32_t O = ObjFileName.str().size() + 1;
+ uint32_t Size = sizeof(ModuleInfoHeader) + M + O;
+ Size = alignTo(Size, 4);
+ return Size;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp
new file mode 100644
index 0000000000..b6f11a942a
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.cpp
@@ -0,0 +1,218 @@
+//===- DbiModuleDescriptorBuilder.cpp - PDB Mod Info Creation ---*- 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/PDB/Native/DbiModuleDescriptorBuilder.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+#include "llvm/DebugInfo/MSF/MSFBuilder.h"
+#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
+#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+static uint32_t calculateDiSymbolStreamSize(uint32_t SymbolByteSize,
+ uint32_t C13Size) {
+ uint32_t Size = sizeof(uint32_t); // Signature
+ Size += alignTo(SymbolByteSize, 4); // Symbol Data
+ Size += 0; // TODO: Layout.C11Bytes
+ Size += C13Size; // C13 Debug Info Size
+ Size += sizeof(uint32_t); // GlobalRefs substream size (always 0)
+ Size += 0; // GlobalRefs substream bytes
+ return Size;
+}
+
+DbiModuleDescriptorBuilder::DbiModuleDescriptorBuilder(StringRef ModuleName,
+ uint32_t ModIndex,
+ msf::MSFBuilder &Msf)
+ : MSF(Msf), ModuleName(std::string(ModuleName)) {
+ ::memset(&Layout, 0, sizeof(Layout));
+ Layout.Mod = ModIndex;
+}
+
+DbiModuleDescriptorBuilder::~DbiModuleDescriptorBuilder() {}
+
+uint16_t DbiModuleDescriptorBuilder::getStreamIndex() const {
+ return Layout.ModDiStream;
+}
+
+void DbiModuleDescriptorBuilder::setObjFileName(StringRef Name) {
+ ObjFileName = std::string(Name);
+}
+
+void DbiModuleDescriptorBuilder::setPdbFilePathNI(uint32_t NI) {
+ PdbFilePathNI = NI;
+}
+
+void DbiModuleDescriptorBuilder::setFirstSectionContrib(
+ const SectionContrib &SC) {
+ Layout.SC = SC;
+}
+
+void DbiModuleDescriptorBuilder::addSymbol(CVSymbol Symbol) {
+ // Defer to the bulk API. It does the same thing.
+ addSymbolsInBulk(Symbol.data());
+}
+
+void DbiModuleDescriptorBuilder::addSymbolsInBulk(
+ ArrayRef<uint8_t> BulkSymbols) {
+ // Do nothing for empty runs of symbols.
+ if (BulkSymbols.empty())
+ return;
+
+ Symbols.push_back(SymbolListWrapper(BulkSymbols));
+ // Symbols written to a PDB file are required to be 4 byte aligned. The same
+ // is not true of object files.
+ assert(BulkSymbols.size() % alignOf(CodeViewContainer::Pdb) == 0 &&
+ "Invalid Symbol alignment!");
+ SymbolByteSize += BulkSymbols.size();
+}
+
+void DbiModuleDescriptorBuilder::addUnmergedSymbols(void *SymSrc,
+ uint32_t SymLength) {
+ assert(SymLength > 0);
+ Symbols.push_back(SymbolListWrapper(SymSrc, SymLength));
+
+ // Symbols written to a PDB file are required to be 4 byte aligned. The same
+ // is not true of object files.
+ assert(SymLength % alignOf(CodeViewContainer::Pdb) == 0 &&
+ "Invalid Symbol alignment!");
+ SymbolByteSize += SymLength;
+}
+
+void DbiModuleDescriptorBuilder::addSourceFile(StringRef Path) {
+ SourceFiles.push_back(std::string(Path));
+}
+
+uint32_t DbiModuleDescriptorBuilder::calculateC13DebugInfoSize() const {
+ uint32_t Result = 0;
+ for (const auto &Builder : C13Builders) {
+ Result += Builder.calculateSerializedLength();
+ }
+ return Result;
+}
+
+uint32_t DbiModuleDescriptorBuilder::calculateSerializedLength() const {
+ uint32_t L = sizeof(Layout);
+ uint32_t M = ModuleName.size() + 1;
+ uint32_t O = ObjFileName.size() + 1;
+ return alignTo(L + M + O, sizeof(uint32_t));
+}
+
+void DbiModuleDescriptorBuilder::finalize() {
+ Layout.FileNameOffs = 0; // TODO: Fix this
+ Layout.Flags = 0; // TODO: Fix this
+ Layout.C11Bytes = 0;
+ Layout.C13Bytes = calculateC13DebugInfoSize();
+ (void)Layout.Mod; // Set in constructor
+ (void)Layout.ModDiStream; // Set in finalizeMsfLayout
+ Layout.NumFiles = SourceFiles.size();
+ Layout.PdbFilePathNI = PdbFilePathNI;
+ Layout.SrcFileNameNI = 0;
+
+ // This value includes both the signature field as well as the record bytes
+ // from the symbol stream.
+ Layout.SymBytes =
+ Layout.ModDiStream == kInvalidStreamIndex ? 0 : getNextSymbolOffset();
+}
+
+Error DbiModuleDescriptorBuilder::finalizeMsfLayout() {
+ this->Layout.ModDiStream = kInvalidStreamIndex;
+ uint32_t C13Size = calculateC13DebugInfoSize();
+ if (!C13Size && !SymbolByteSize)
+ return Error::success();
+ auto ExpectedSN =
+ MSF.addStream(calculateDiSymbolStreamSize(SymbolByteSize, C13Size));
+ if (!ExpectedSN)
+ return ExpectedSN.takeError();
+ Layout.ModDiStream = *ExpectedSN;
+ return Error::success();
+}
+
+Error DbiModuleDescriptorBuilder::commit(BinaryStreamWriter &ModiWriter) {
+ // We write the Modi record to the `ModiWriter`, but we additionally write its
+ // symbol stream to a brand new stream.
+ if (auto EC = ModiWriter.writeObject(Layout))
+ return EC;
+ if (auto EC = ModiWriter.writeCString(ModuleName))
+ return EC;
+ if (auto EC = ModiWriter.writeCString(ObjFileName))
+ return EC;
+ if (auto EC = ModiWriter.padToAlignment(sizeof(uint32_t)))
+ return EC;
+ return Error::success();
+}
+
+Error DbiModuleDescriptorBuilder::commitSymbolStream(
+ const msf::MSFLayout &MsfLayout, WritableBinaryStreamRef MsfBuffer) {
+ if (Layout.ModDiStream == kInvalidStreamIndex)
+ return Error::success();
+
+ auto NS = WritableMappedBlockStream::createIndexedStream(
+ MsfLayout, MsfBuffer, Layout.ModDiStream, MSF.getAllocator());
+ WritableBinaryStreamRef Ref(*NS);
+ BinaryStreamWriter SymbolWriter(Ref);
+ // Write the symbols.
+ if (auto EC = SymbolWriter.writeInteger<uint32_t>(COFF::DEBUG_SECTION_MAGIC))
+ return EC;
+ for (const SymbolListWrapper &Sym : Symbols) {
+ if (Sym.NeedsToBeMerged) {
+ assert(MergeSymsCallback);
+ if (auto EC = MergeSymsCallback(MergeSymsCtx, Sym.SymPtr, SymbolWriter))
+ return EC;
+ } else {
+ if (auto EC = SymbolWriter.writeBytes(Sym.asArray()))
+ return EC;
+ }
+ }
+
+ // Apply the string table fixups.
+ auto SavedOffset = SymbolWriter.getOffset();
+ for (const StringTableFixup &Fixup : StringTableFixups) {
+ SymbolWriter.setOffset(Fixup.SymOffsetOfReference);
+ if (auto E = SymbolWriter.writeInteger<uint32_t>(Fixup.StrTabOffset))
+ return E;
+ }
+ SymbolWriter.setOffset(SavedOffset);
+
+ assert(SymbolWriter.getOffset() % alignOf(CodeViewContainer::Pdb) == 0 &&
+ "Invalid debug section alignment!");
+ // TODO: Write C11 Line data
+ for (const auto &Builder : C13Builders) {
+ if (auto EC = Builder.commit(SymbolWriter, CodeViewContainer::Pdb))
+ return EC;
+ }
+
+ // TODO: Figure out what GlobalRefs substream actually is and populate it.
+ if (auto EC = SymbolWriter.writeInteger<uint32_t>(0))
+ return EC;
+ if (SymbolWriter.bytesRemaining() > 0)
+ return make_error<RawError>(raw_error_code::stream_too_long);
+
+ return Error::success();
+}
+
+void DbiModuleDescriptorBuilder::addDebugSubsection(
+ std::shared_ptr<DebugSubsection> Subsection) {
+ assert(Subsection);
+ C13Builders.push_back(DebugSubsectionRecordBuilder(std::move(Subsection)));
+}
+
+void DbiModuleDescriptorBuilder::addDebugSubsection(
+ const DebugSubsectionRecord &SubsectionContents) {
+ C13Builders.push_back(DebugSubsectionRecordBuilder(SubsectionContents));
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiModuleList.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiModuleList.cpp
new file mode 100644
index 0000000000..5cf014e881
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiModuleList.cpp
@@ -0,0 +1,279 @@
+//===- DbiModuleList.cpp - PDB module information list --------------------===//
+//
+// 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/PDB/Native/DbiModuleList.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cassert>
+#include <cstddef>
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+DbiModuleSourceFilesIterator::DbiModuleSourceFilesIterator(
+ const DbiModuleList &Modules, uint32_t Modi, uint16_t Filei)
+ : Modules(&Modules), Modi(Modi), Filei(Filei) {
+ setValue();
+}
+
+bool DbiModuleSourceFilesIterator::
+operator==(const DbiModuleSourceFilesIterator &R) const {
+ // incompatible iterators are never equal
+ if (!isCompatible(R))
+ return false;
+
+ // If they're compatible, and they're both ends, then they're equal.
+ if (isEnd() && R.isEnd())
+ return true;
+
+ // If one is an end and the other is not, they're not equal.
+ if (isEnd() != R.isEnd())
+ return false;
+
+ // Now we know:
+ // - They're compatible
+ // - They're not *both* end iterators
+ // - Their endness is the same.
+ // Thus, they're compatible iterators pointing to a valid file on the same
+ // module. All we need to check are the file indices.
+ assert(Modules == R.Modules);
+ assert(Modi == R.Modi);
+ assert(!isEnd());
+ assert(!R.isEnd());
+
+ return (Filei == R.Filei);
+}
+
+bool DbiModuleSourceFilesIterator::
+operator<(const DbiModuleSourceFilesIterator &R) const {
+ assert(isCompatible(R));
+
+ // It's not sufficient to compare the file indices, because default
+ // constructed iterators could be equal to iterators with valid indices. To
+ // account for this, early-out if they're equal.
+ if (*this == R)
+ return false;
+
+ return Filei < R.Filei;
+}
+
+std::ptrdiff_t DbiModuleSourceFilesIterator::
+operator-(const DbiModuleSourceFilesIterator &R) const {
+ assert(isCompatible(R));
+ assert(!(*this < R));
+
+ // If they're both end iterators, the distance is 0.
+ if (isEnd() && R.isEnd())
+ return 0;
+
+ assert(!R.isEnd());
+
+ // At this point, R cannot be end, but *this can, which means that *this
+ // might be a universal end iterator with none of its fields set. So in that
+ // case have to rely on R as the authority to figure out how many files there
+ // are to compute the distance.
+ uint32_t Thisi = Filei;
+ if (isEnd()) {
+ uint32_t RealModi = R.Modi;
+ Thisi = R.Modules->getSourceFileCount(RealModi);
+ }
+
+ assert(Thisi >= R.Filei);
+ return Thisi - R.Filei;
+}
+
+DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
+operator+=(std::ptrdiff_t N) {
+ assert(!isEnd());
+
+ Filei += N;
+ assert(Filei <= Modules->getSourceFileCount(Modi));
+ setValue();
+ return *this;
+}
+
+DbiModuleSourceFilesIterator &DbiModuleSourceFilesIterator::
+operator-=(std::ptrdiff_t N) {
+ // Note that we can subtract from an end iterator, but not a universal end
+ // iterator.
+ assert(!isUniversalEnd());
+
+ assert(N <= Filei);
+
+ Filei -= N;
+ return *this;
+}
+
+void DbiModuleSourceFilesIterator::setValue() {
+ if (isEnd()) {
+ ThisValue = "";
+ return;
+ }
+
+ uint32_t Off = Modules->ModuleInitialFileIndex[Modi] + Filei;
+ auto ExpectedValue = Modules->getFileName(Off);
+ if (!ExpectedValue) {
+ consumeError(ExpectedValue.takeError());
+ Filei = Modules->getSourceFileCount(Modi);
+ } else
+ ThisValue = *ExpectedValue;
+}
+
+bool DbiModuleSourceFilesIterator::isEnd() const {
+ if (isUniversalEnd())
+ return true;
+
+ assert(Modules);
+ assert(Modi <= Modules->getModuleCount());
+ assert(Filei <= Modules->getSourceFileCount(Modi));
+
+ if (Modi == Modules->getModuleCount())
+ return true;
+ if (Filei == Modules->getSourceFileCount(Modi))
+ return true;
+ return false;
+}
+
+bool DbiModuleSourceFilesIterator::isUniversalEnd() const { return !Modules; }
+
+bool DbiModuleSourceFilesIterator::isCompatible(
+ const DbiModuleSourceFilesIterator &R) const {
+ // Universal iterators are compatible with any other iterator.
+ if (isUniversalEnd() || R.isUniversalEnd())
+ return true;
+
+ // At this point, neither iterator is a universal end iterator, although one
+ // or both might be non-universal end iterators. Regardless, the module index
+ // is valid, so they are compatible if and only if they refer to the same
+ // module.
+ return Modi == R.Modi;
+}
+
+Error DbiModuleList::initialize(BinaryStreamRef ModInfo,
+ BinaryStreamRef FileInfo) {
+ if (auto EC = initializeModInfo(ModInfo))
+ return EC;
+ if (auto EC = initializeFileInfo(FileInfo))
+ return EC;
+
+ return Error::success();
+}
+
+Error DbiModuleList::initializeModInfo(BinaryStreamRef ModInfo) {
+ ModInfoSubstream = ModInfo;
+
+ if (ModInfo.getLength() == 0)
+ return Error::success();
+
+ BinaryStreamReader Reader(ModInfo);
+
+ if (auto EC = Reader.readArray(Descriptors, ModInfo.getLength()))
+ return EC;
+
+ return Error::success();
+}
+
+Error DbiModuleList::initializeFileInfo(BinaryStreamRef FileInfo) {
+ FileInfoSubstream = FileInfo;
+
+ if (FileInfo.getLength() == 0)
+ return Error::success();
+
+ BinaryStreamReader FISR(FileInfo);
+ if (auto EC = FISR.readObject(FileInfoHeader))
+ return EC;
+
+ // First is an array of `NumModules` module indices. This does not seem to be
+ // used for anything meaningful, so we ignore it.
+ FixedStreamArray<support::ulittle16_t> ModuleIndices;
+ if (auto EC = FISR.readArray(ModuleIndices, FileInfoHeader->NumModules))
+ return EC;
+ if (auto EC = FISR.readArray(ModFileCountArray, FileInfoHeader->NumModules))
+ return EC;
+
+ // Compute the real number of source files. We can't trust the value in
+ // `FileInfoHeader->NumSourceFiles` because it is a unit16, and the sum of all
+ // source file counts might be larger than a unit16. So we compute the real
+ // count by summing up the individual counts.
+ uint32_t NumSourceFiles = 0;
+ for (auto Count : ModFileCountArray)
+ NumSourceFiles += Count;
+
+ // In the reference implementation, this array is where the pointer documented
+ // at the definition of ModuleInfoHeader::FileNameOffs points to. Note that
+ // although the field in ModuleInfoHeader is ignored this array is not, as it
+ // is the authority on where each filename begins in the names buffer.
+ if (auto EC = FISR.readArray(FileNameOffsets, NumSourceFiles))
+ return EC;
+
+ if (auto EC = FISR.readStreamRef(NamesBuffer))
+ return EC;
+
+ auto DescriptorIter = Descriptors.begin();
+ uint32_t NextFileIndex = 0;
+ ModuleInitialFileIndex.resize(FileInfoHeader->NumModules);
+ ModuleDescriptorOffsets.resize(FileInfoHeader->NumModules);
+ for (size_t I = 0; I < FileInfoHeader->NumModules; ++I) {
+ assert(DescriptorIter != Descriptors.end());
+ ModuleInitialFileIndex[I] = NextFileIndex;
+ ModuleDescriptorOffsets[I] = DescriptorIter.offset();
+
+ NextFileIndex += ModFileCountArray[I];
+ ++DescriptorIter;
+ }
+
+ assert(DescriptorIter == Descriptors.end());
+ assert(NextFileIndex == NumSourceFiles);
+
+ return Error::success();
+}
+
+uint32_t DbiModuleList::getModuleCount() const {
+ return FileInfoHeader->NumModules;
+}
+
+uint32_t DbiModuleList::getSourceFileCount() const {
+ return FileNameOffsets.size();
+}
+
+uint16_t DbiModuleList::getSourceFileCount(uint32_t Modi) const {
+ return ModFileCountArray[Modi];
+}
+
+DbiModuleDescriptor DbiModuleList::getModuleDescriptor(uint32_t Modi) const {
+ assert(Modi < getModuleCount());
+ uint32_t Offset = ModuleDescriptorOffsets[Modi];
+ auto Iter = Descriptors.at(Offset);
+ assert(Iter != Descriptors.end());
+ return *Iter;
+}
+
+iterator_range<DbiModuleSourceFilesIterator>
+DbiModuleList::source_files(uint32_t Modi) const {
+ return make_range<DbiModuleSourceFilesIterator>(
+ DbiModuleSourceFilesIterator(*this, Modi, 0),
+ DbiModuleSourceFilesIterator());
+}
+
+Expected<StringRef> DbiModuleList::getFileName(uint32_t Index) const {
+ BinaryStreamReader Names(NamesBuffer);
+ if (Index >= getSourceFileCount())
+ return make_error<RawError>(raw_error_code::index_out_of_bounds);
+
+ uint32_t FileOffset = FileNameOffsets[Index];
+ Names.setOffset(FileOffset);
+ StringRef Name;
+ if (auto EC = Names.readCString(Name))
+ return std::move(EC);
+ return Name;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiStream.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiStream.cpp
new file mode 100644
index 0000000000..4eb1680417
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiStream.cpp
@@ -0,0 +1,383 @@
+//===- DbiStream.cpp - PDB Dbi Stream (Stream 3) Access -------------------===//
+//
+// 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/PDB/Native/DbiStream.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
+#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/BinaryStreamArray.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cstddef>
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+using namespace llvm::support;
+
+template <typename ContribType>
+static Error loadSectionContribs(FixedStreamArray<ContribType> &Output,
+ BinaryStreamReader &Reader) {
+ if (Reader.bytesRemaining() % sizeof(ContribType) != 0)
+ return make_error<RawError>(
+ raw_error_code::corrupt_file,
+ "Invalid number of bytes of section contributions");
+
+ uint32_t Count = Reader.bytesRemaining() / sizeof(ContribType);
+ if (auto EC = Reader.readArray(Output, Count))
+ return EC;
+ return Error::success();
+}
+
+DbiStream::DbiStream(std::unique_ptr<BinaryStream> Stream)
+ : Stream(std::move(Stream)), Header(nullptr) {}
+
+DbiStream::~DbiStream() = default;
+
+Error DbiStream::reload(PDBFile *Pdb) {
+ BinaryStreamReader Reader(*Stream);
+
+ if (Stream->getLength() < sizeof(DbiStreamHeader))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "DBI Stream does not contain a header.");
+ if (auto EC = Reader.readObject(Header))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "DBI Stream does not contain a header.");
+
+ if (Header->VersionSignature != -1)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid DBI version signature.");
+
+ // Require at least version 7, which should be present in all PDBs
+ // produced in the last decade and allows us to avoid having to
+ // special case all kinds of complicated arcane formats.
+ if (Header->VersionHeader < PdbDbiV70)
+ return make_error<RawError>(raw_error_code::feature_unsupported,
+ "Unsupported DBI version.");
+
+ if (Stream->getLength() !=
+ sizeof(DbiStreamHeader) + Header->ModiSubstreamSize +
+ Header->SecContrSubstreamSize + Header->SectionMapSize +
+ Header->FileInfoSize + Header->TypeServerSize +
+ Header->OptionalDbgHdrSize + Header->ECSubstreamSize)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "DBI Length does not equal sum of substreams.");
+
+ // Only certain substreams are guaranteed to be aligned. Validate
+ // them here.
+ if (Header->ModiSubstreamSize % sizeof(uint32_t) != 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "DBI MODI substream not aligned.");
+ if (Header->SecContrSubstreamSize % sizeof(uint32_t) != 0)
+ return make_error<RawError>(
+ raw_error_code::corrupt_file,
+ "DBI section contribution substream not aligned.");
+ if (Header->SectionMapSize % sizeof(uint32_t) != 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "DBI section map substream not aligned.");
+ if (Header->FileInfoSize % sizeof(uint32_t) != 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "DBI file info substream not aligned.");
+ if (Header->TypeServerSize % sizeof(uint32_t) != 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "DBI type server substream not aligned.");
+
+ if (auto EC = Reader.readSubstream(ModiSubstream, Header->ModiSubstreamSize))
+ return EC;
+
+ if (auto EC = Reader.readSubstream(SecContrSubstream,
+ Header->SecContrSubstreamSize))
+ return EC;
+ if (auto EC = Reader.readSubstream(SecMapSubstream, Header->SectionMapSize))
+ return EC;
+ if (auto EC = Reader.readSubstream(FileInfoSubstream, Header->FileInfoSize))
+ return EC;
+ if (auto EC =
+ Reader.readSubstream(TypeServerMapSubstream, Header->TypeServerSize))
+ return EC;
+ if (auto EC = Reader.readSubstream(ECSubstream, Header->ECSubstreamSize))
+ return EC;
+ if (auto EC = Reader.readArray(
+ DbgStreams, Header->OptionalDbgHdrSize / sizeof(ulittle16_t)))
+ return EC;
+
+ if (auto EC = Modules.initialize(ModiSubstream.StreamData,
+ FileInfoSubstream.StreamData))
+ return EC;
+
+ if (auto EC = initializeSectionContributionData())
+ return EC;
+ if (auto EC = initializeSectionHeadersData(Pdb))
+ return EC;
+ if (auto EC = initializeSectionMapData())
+ return EC;
+ if (auto EC = initializeOldFpoRecords(Pdb))
+ return EC;
+ if (auto EC = initializeNewFpoRecords(Pdb))
+ return EC;
+
+ if (Reader.bytesRemaining() > 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Found unexpected bytes in DBI Stream.");
+
+ if (!ECSubstream.empty()) {
+ BinaryStreamReader ECReader(ECSubstream.StreamData);
+ if (auto EC = ECNames.reload(ECReader))
+ return EC;
+ }
+
+ return Error::success();
+}
+
+PdbRaw_DbiVer DbiStream::getDbiVersion() const {
+ uint32_t Value = Header->VersionHeader;
+ return static_cast<PdbRaw_DbiVer>(Value);
+}
+
+uint32_t DbiStream::getAge() const { return Header->Age; }
+
+uint16_t DbiStream::getPublicSymbolStreamIndex() const {
+ return Header->PublicSymbolStreamIndex;
+}
+
+uint16_t DbiStream::getGlobalSymbolStreamIndex() const {
+ return Header->GlobalSymbolStreamIndex;
+}
+
+uint16_t DbiStream::getFlags() const { return Header->Flags; }
+
+bool DbiStream::isIncrementallyLinked() const {
+ return (Header->Flags & DbiFlags::FlagIncrementalMask) != 0;
+}
+
+bool DbiStream::hasCTypes() const {
+ return (Header->Flags & DbiFlags::FlagHasCTypesMask) != 0;
+}
+
+bool DbiStream::isStripped() const {
+ return (Header->Flags & DbiFlags::FlagStrippedMask) != 0;
+}
+
+uint16_t DbiStream::getBuildNumber() const { return Header->BuildNumber; }
+
+uint16_t DbiStream::getBuildMajorVersion() const {
+ return (Header->BuildNumber & DbiBuildNo::BuildMajorMask) >>
+ DbiBuildNo::BuildMajorShift;
+}
+
+uint16_t DbiStream::getBuildMinorVersion() const {
+ return (Header->BuildNumber & DbiBuildNo::BuildMinorMask) >>
+ DbiBuildNo::BuildMinorShift;
+}
+
+uint16_t DbiStream::getPdbDllRbld() const { return Header->PdbDllRbld; }
+
+uint32_t DbiStream::getPdbDllVersion() const { return Header->PdbDllVersion; }
+
+uint32_t DbiStream::getSymRecordStreamIndex() const {
+ return Header->SymRecordStreamIndex;
+}
+
+PDB_Machine DbiStream::getMachineType() const {
+ uint16_t Machine = Header->MachineType;
+ return static_cast<PDB_Machine>(Machine);
+}
+
+FixedStreamArray<object::coff_section> DbiStream::getSectionHeaders() const {
+ return SectionHeaders;
+}
+
+bool DbiStream::hasOldFpoRecords() const { return OldFpoStream != nullptr; }
+
+FixedStreamArray<object::FpoData> DbiStream::getOldFpoRecords() const {
+ return OldFpoRecords;
+}
+
+bool DbiStream::hasNewFpoRecords() const { return NewFpoStream != nullptr; }
+
+const DebugFrameDataSubsectionRef &DbiStream::getNewFpoRecords() const {
+ return NewFpoRecords;
+}
+
+const DbiModuleList &DbiStream::modules() const { return Modules; }
+
+FixedStreamArray<SecMapEntry> DbiStream::getSectionMap() const {
+ return SectionMap;
+}
+
+void DbiStream::visitSectionContributions(
+ ISectionContribVisitor &Visitor) const {
+ if (!SectionContribs.empty()) {
+ assert(SectionContribVersion == DbiSecContribVer60);
+ for (auto &SC : SectionContribs)
+ Visitor.visit(SC);
+ } else if (!SectionContribs2.empty()) {
+ assert(SectionContribVersion == DbiSecContribV2);
+ for (auto &SC : SectionContribs2)
+ Visitor.visit(SC);
+ }
+}
+
+Expected<StringRef> DbiStream::getECName(uint32_t NI) const {
+ return ECNames.getStringForID(NI);
+}
+
+Error DbiStream::initializeSectionContributionData() {
+ if (SecContrSubstream.empty())
+ return Error::success();
+
+ BinaryStreamReader SCReader(SecContrSubstream.StreamData);
+ if (auto EC = SCReader.readEnum(SectionContribVersion))
+ return EC;
+
+ if (SectionContribVersion == DbiSecContribVer60)
+ return loadSectionContribs<SectionContrib>(SectionContribs, SCReader);
+ if (SectionContribVersion == DbiSecContribV2)
+ return loadSectionContribs<SectionContrib2>(SectionContribs2, SCReader);
+
+ return make_error<RawError>(raw_error_code::feature_unsupported,
+ "Unsupported DBI Section Contribution version");
+}
+
+// Initializes this->SectionHeaders.
+Error DbiStream::initializeSectionHeadersData(PDBFile *Pdb) {
+ Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream =
+ createIndexedStreamForHeaderType(Pdb, DbgHeaderType::SectionHdr);
+ if (auto EC = ExpectedStream.takeError())
+ return EC;
+
+ auto &SHS = *ExpectedStream;
+ if (!SHS)
+ return Error::success();
+
+ size_t StreamLen = SHS->getLength();
+ if (StreamLen % sizeof(object::coff_section))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Corrupted section header stream.");
+
+ size_t NumSections = StreamLen / sizeof(object::coff_section);
+ BinaryStreamReader Reader(*SHS);
+ if (auto EC = Reader.readArray(SectionHeaders, NumSections))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not read a bitmap.");
+
+ SectionHeaderStream = std::move(SHS);
+ return Error::success();
+}
+
+// Initializes this->Fpos.
+Error DbiStream::initializeOldFpoRecords(PDBFile *Pdb) {
+ Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream =
+ createIndexedStreamForHeaderType(Pdb, DbgHeaderType::FPO);
+ if (auto EC = ExpectedStream.takeError())
+ return EC;
+
+ auto &FS = *ExpectedStream;
+ if (!FS)
+ return Error::success();
+
+ size_t StreamLen = FS->getLength();
+ if (StreamLen % sizeof(object::FpoData))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Corrupted Old FPO stream.");
+
+ size_t NumRecords = StreamLen / sizeof(object::FpoData);
+ BinaryStreamReader Reader(*FS);
+ if (auto EC = Reader.readArray(OldFpoRecords, NumRecords))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Corrupted Old FPO stream.");
+ OldFpoStream = std::move(FS);
+ return Error::success();
+}
+
+Error DbiStream::initializeNewFpoRecords(PDBFile *Pdb) {
+ Expected<std::unique_ptr<msf::MappedBlockStream>> ExpectedStream =
+ createIndexedStreamForHeaderType(Pdb, DbgHeaderType::NewFPO);
+ if (auto EC = ExpectedStream.takeError())
+ return EC;
+
+ auto &FS = *ExpectedStream;
+ if (!FS)
+ return Error::success();
+
+ if (auto EC = NewFpoRecords.initialize(*FS))
+ return EC;
+
+ NewFpoStream = std::move(FS);
+ return Error::success();
+}
+
+Expected<std::unique_ptr<msf::MappedBlockStream>>
+DbiStream::createIndexedStreamForHeaderType(PDBFile *Pdb,
+ DbgHeaderType Type) const {
+ if (!Pdb)
+ return nullptr;
+
+ if (DbgStreams.empty())
+ return nullptr;
+
+ uint32_t StreamNum = getDebugStreamIndex(Type);
+
+ // This means there is no such stream.
+ if (StreamNum == kInvalidStreamIndex)
+ return nullptr;
+
+ return Pdb->safelyCreateIndexedStream(StreamNum);
+}
+
+BinarySubstreamRef DbiStream::getSectionContributionData() const {
+ return SecContrSubstream;
+}
+
+BinarySubstreamRef DbiStream::getSecMapSubstreamData() const {
+ return SecMapSubstream;
+}
+
+BinarySubstreamRef DbiStream::getModiSubstreamData() const {
+ return ModiSubstream;
+}
+
+BinarySubstreamRef DbiStream::getFileInfoSubstreamData() const {
+ return FileInfoSubstream;
+}
+
+BinarySubstreamRef DbiStream::getTypeServerMapSubstreamData() const {
+ return TypeServerMapSubstream;
+}
+
+BinarySubstreamRef DbiStream::getECSubstreamData() const { return ECSubstream; }
+
+Error DbiStream::initializeSectionMapData() {
+ if (SecMapSubstream.empty())
+ return Error::success();
+
+ BinaryStreamReader SMReader(SecMapSubstream.StreamData);
+ const SecMapHeader *Header;
+ if (auto EC = SMReader.readObject(Header))
+ return EC;
+ if (auto EC = SMReader.readArray(SectionMap, Header->SecCount))
+ return EC;
+ return Error::success();
+}
+
+uint32_t DbiStream::getDebugStreamIndex(DbgHeaderType Type) const {
+ uint16_t T = static_cast<uint16_t>(Type);
+ if (T >= DbgStreams.size())
+ return kInvalidStreamIndex;
+ return DbgStreams[T];
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
new file mode 100644
index 0000000000..0584966a98
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/DbiStreamBuilder.cpp
@@ -0,0 +1,454 @@
+//===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- 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/PDB/Native/DbiStreamBuilder.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/DebugInfo/CodeView/DebugFrameDataSubsection.h"
+#include "llvm/DebugInfo/MSF/MSFBuilder.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptorBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Parallel.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+DbiStreamBuilder::DbiStreamBuilder(msf::MSFBuilder &Msf)
+ : Msf(Msf), Allocator(Msf.getAllocator()), Age(1), BuildNumber(0),
+ PdbDllVersion(0), PdbDllRbld(0), Flags(0), MachineType(PDB_Machine::x86),
+ Header(nullptr) {}
+
+DbiStreamBuilder::~DbiStreamBuilder() {}
+
+void DbiStreamBuilder::setVersionHeader(PdbRaw_DbiVer V) { VerHeader = V; }
+
+void DbiStreamBuilder::setAge(uint32_t A) { Age = A; }
+
+void DbiStreamBuilder::setBuildNumber(uint16_t B) { BuildNumber = B; }
+
+void DbiStreamBuilder::setBuildNumber(uint8_t Major, uint8_t Minor) {
+ BuildNumber = (uint16_t(Major) << DbiBuildNo::BuildMajorShift) &
+ DbiBuildNo::BuildMajorMask;
+ BuildNumber |= (uint16_t(Minor) << DbiBuildNo::BuildMinorShift) &
+ DbiBuildNo::BuildMinorMask;
+ BuildNumber |= DbiBuildNo::NewVersionFormatMask;
+}
+
+void DbiStreamBuilder::setPdbDllVersion(uint16_t V) { PdbDllVersion = V; }
+
+void DbiStreamBuilder::setPdbDllRbld(uint16_t R) { PdbDllRbld = R; }
+
+void DbiStreamBuilder::setFlags(uint16_t F) { Flags = F; }
+
+void DbiStreamBuilder::setMachineType(PDB_Machine M) { MachineType = M; }
+
+void DbiStreamBuilder::setMachineType(COFF::MachineTypes M) {
+ // These enums are mirrors of each other, so we can just cast the value.
+ MachineType = static_cast<pdb::PDB_Machine>(static_cast<unsigned>(M));
+}
+
+void DbiStreamBuilder::setGlobalsStreamIndex(uint32_t Index) {
+ GlobalsStreamIndex = Index;
+}
+
+void DbiStreamBuilder::setSymbolRecordStreamIndex(uint32_t Index) {
+ SymRecordStreamIndex = Index;
+}
+
+void DbiStreamBuilder::setPublicsStreamIndex(uint32_t Index) {
+ PublicsStreamIndex = Index;
+}
+
+void DbiStreamBuilder::addNewFpoData(const codeview::FrameData &FD) {
+ if (!NewFpoData.hasValue())
+ NewFpoData.emplace(false);
+
+ NewFpoData->addFrameData(FD);
+}
+
+void DbiStreamBuilder::addOldFpoData(const object::FpoData &FD) {
+ OldFpoData.push_back(FD);
+}
+
+Error DbiStreamBuilder::addDbgStream(pdb::DbgHeaderType Type,
+ ArrayRef<uint8_t> Data) {
+ assert(Type != DbgHeaderType::NewFPO &&
+ "NewFPO data should be written via addFrameData()!");
+
+ DbgStreams[(int)Type].emplace();
+ DbgStreams[(int)Type]->Size = Data.size();
+ DbgStreams[(int)Type]->WriteFn = [Data](BinaryStreamWriter &Writer) {
+ return Writer.writeArray(Data);
+ };
+ return Error::success();
+}
+
+uint32_t DbiStreamBuilder::addECName(StringRef Name) {
+ return ECNamesBuilder.insert(Name);
+}
+
+uint32_t DbiStreamBuilder::calculateSerializedLength() const {
+ // For now we only support serializing the header.
+ return sizeof(DbiStreamHeader) + calculateFileInfoSubstreamSize() +
+ calculateModiSubstreamSize() + calculateSectionContribsStreamSize() +
+ calculateSectionMapStreamSize() + calculateDbgStreamsSize() +
+ ECNamesBuilder.calculateSerializedSize();
+}
+
+Expected<DbiModuleDescriptorBuilder &>
+DbiStreamBuilder::addModuleInfo(StringRef ModuleName) {
+ uint32_t Index = ModiList.size();
+ ModiList.push_back(
+ std::make_unique<DbiModuleDescriptorBuilder>(ModuleName, Index, Msf));
+ return *ModiList.back();
+}
+
+Error DbiStreamBuilder::addModuleSourceFile(DbiModuleDescriptorBuilder &Module,
+ StringRef File) {
+ uint32_t Index = SourceFileNames.size();
+ SourceFileNames.insert(std::make_pair(File, Index));
+ Module.addSourceFile(File);
+ return Error::success();
+}
+
+Expected<uint32_t> DbiStreamBuilder::getSourceFileNameIndex(StringRef File) {
+ auto NameIter = SourceFileNames.find(File);
+ if (NameIter == SourceFileNames.end())
+ return make_error<RawError>(raw_error_code::no_entry,
+ "The specified source file was not found");
+ return NameIter->getValue();
+}
+
+uint32_t DbiStreamBuilder::calculateModiSubstreamSize() const {
+ uint32_t Size = 0;
+ for (const auto &M : ModiList)
+ Size += M->calculateSerializedLength();
+ return Size;
+}
+
+uint32_t DbiStreamBuilder::calculateSectionContribsStreamSize() const {
+ if (SectionContribs.empty())
+ return 0;
+ return sizeof(enum PdbRaw_DbiSecContribVer) +
+ sizeof(SectionContribs[0]) * SectionContribs.size();
+}
+
+uint32_t DbiStreamBuilder::calculateSectionMapStreamSize() const {
+ if (SectionMap.empty())
+ return 0;
+ return sizeof(SecMapHeader) + sizeof(SecMapEntry) * SectionMap.size();
+}
+
+uint32_t DbiStreamBuilder::calculateNamesOffset() const {
+ uint32_t Offset = 0;
+ Offset += sizeof(ulittle16_t); // NumModules
+ Offset += sizeof(ulittle16_t); // NumSourceFiles
+ Offset += ModiList.size() * sizeof(ulittle16_t); // ModIndices
+ Offset += ModiList.size() * sizeof(ulittle16_t); // ModFileCounts
+ uint32_t NumFileInfos = 0;
+ for (const auto &M : ModiList)
+ NumFileInfos += M->source_files().size();
+ Offset += NumFileInfos * sizeof(ulittle32_t); // FileNameOffsets
+ return Offset;
+}
+
+uint32_t DbiStreamBuilder::calculateFileInfoSubstreamSize() const {
+ uint32_t Size = calculateNamesOffset();
+ Size += calculateNamesBufferSize();
+ return alignTo(Size, sizeof(uint32_t));
+}
+
+uint32_t DbiStreamBuilder::calculateNamesBufferSize() const {
+ uint32_t Size = 0;
+ for (const auto &F : SourceFileNames) {
+ Size += F.getKeyLength() + 1; // Names[I];
+ }
+ return Size;
+}
+
+uint32_t DbiStreamBuilder::calculateDbgStreamsSize() const {
+ return DbgStreams.size() * sizeof(uint16_t);
+}
+
+Error DbiStreamBuilder::generateFileInfoSubstream() {
+ uint32_t Size = calculateFileInfoSubstreamSize();
+ auto Data = Allocator.Allocate<uint8_t>(Size);
+ uint32_t NamesOffset = calculateNamesOffset();
+
+ FileInfoBuffer = MutableBinaryByteStream(MutableArrayRef<uint8_t>(Data, Size),
+ llvm::support::little);
+
+ WritableBinaryStreamRef MetadataBuffer =
+ WritableBinaryStreamRef(FileInfoBuffer).keep_front(NamesOffset);
+ BinaryStreamWriter MetadataWriter(MetadataBuffer);
+
+ uint16_t ModiCount = std::min<uint32_t>(UINT16_MAX, ModiList.size());
+ uint16_t FileCount = std::min<uint32_t>(UINT16_MAX, SourceFileNames.size());
+ if (auto EC = MetadataWriter.writeInteger(ModiCount)) // NumModules
+ return EC;
+ if (auto EC = MetadataWriter.writeInteger(FileCount)) // NumSourceFiles
+ return EC;
+ for (uint16_t I = 0; I < ModiCount; ++I) {
+ if (auto EC = MetadataWriter.writeInteger(I)) // Mod Indices
+ return EC;
+ }
+ for (const auto &MI : ModiList) {
+ FileCount = static_cast<uint16_t>(MI->source_files().size());
+ if (auto EC = MetadataWriter.writeInteger(FileCount)) // Mod File Counts
+ return EC;
+ }
+
+ // Before writing the FileNameOffsets array, write the NamesBuffer array.
+ // A side effect of this is that this will actually compute the various
+ // file name offsets, so we can then go back and write the FileNameOffsets
+ // array to the other substream.
+ NamesBuffer = WritableBinaryStreamRef(FileInfoBuffer).drop_front(NamesOffset);
+ BinaryStreamWriter NameBufferWriter(NamesBuffer);
+ for (auto &Name : SourceFileNames) {
+ Name.second = NameBufferWriter.getOffset();
+ if (auto EC = NameBufferWriter.writeCString(Name.getKey()))
+ return EC;
+ }
+
+ for (const auto &MI : ModiList) {
+ for (StringRef Name : MI->source_files()) {
+ auto Result = SourceFileNames.find(Name);
+ if (Result == SourceFileNames.end())
+ return make_error<RawError>(raw_error_code::no_entry,
+ "The source file was not found.");
+ if (auto EC = MetadataWriter.writeInteger(Result->second))
+ return EC;
+ }
+ }
+
+ if (auto EC = NameBufferWriter.padToAlignment(sizeof(uint32_t)))
+ return EC;
+
+ if (NameBufferWriter.bytesRemaining() > 0)
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "The names buffer contained unexpected data.");
+
+ if (MetadataWriter.bytesRemaining() > sizeof(uint32_t))
+ return make_error<RawError>(
+ raw_error_code::invalid_format,
+ "The metadata buffer contained unexpected data.");
+
+ return Error::success();
+}
+
+Error DbiStreamBuilder::finalize() {
+ if (Header)
+ return Error::success();
+
+ for (auto &MI : ModiList)
+ MI->finalize();
+
+ if (auto EC = generateFileInfoSubstream())
+ return EC;
+
+ DbiStreamHeader *H = Allocator.Allocate<DbiStreamHeader>();
+ ::memset(H, 0, sizeof(DbiStreamHeader));
+ H->VersionHeader = *VerHeader;
+ H->VersionSignature = -1;
+ H->Age = Age;
+ H->BuildNumber = BuildNumber;
+ H->Flags = Flags;
+ H->PdbDllRbld = PdbDllRbld;
+ H->PdbDllVersion = PdbDllVersion;
+ H->MachineType = static_cast<uint16_t>(MachineType);
+
+ H->ECSubstreamSize = ECNamesBuilder.calculateSerializedSize();
+ H->FileInfoSize = FileInfoBuffer.getLength();
+ H->ModiSubstreamSize = calculateModiSubstreamSize();
+ H->OptionalDbgHdrSize = DbgStreams.size() * sizeof(uint16_t);
+ H->SecContrSubstreamSize = calculateSectionContribsStreamSize();
+ H->SectionMapSize = calculateSectionMapStreamSize();
+ H->TypeServerSize = 0;
+ H->SymRecordStreamIndex = SymRecordStreamIndex;
+ H->PublicSymbolStreamIndex = PublicsStreamIndex;
+ H->MFCTypeServerIndex = 0; // Not sure what this is, but link.exe writes 0.
+ H->GlobalSymbolStreamIndex = GlobalsStreamIndex;
+
+ Header = H;
+ return Error::success();
+}
+
+Error DbiStreamBuilder::finalizeMsfLayout() {
+ if (NewFpoData.hasValue()) {
+ DbgStreams[(int)DbgHeaderType::NewFPO].emplace();
+ DbgStreams[(int)DbgHeaderType::NewFPO]->Size =
+ NewFpoData->calculateSerializedSize();
+ DbgStreams[(int)DbgHeaderType::NewFPO]->WriteFn =
+ [this](BinaryStreamWriter &Writer) {
+ return NewFpoData->commit(Writer);
+ };
+ }
+
+ if (!OldFpoData.empty()) {
+ DbgStreams[(int)DbgHeaderType::FPO].emplace();
+ DbgStreams[(int)DbgHeaderType::FPO]->Size =
+ sizeof(object::FpoData) * OldFpoData.size();
+ DbgStreams[(int)DbgHeaderType::FPO]->WriteFn =
+ [this](BinaryStreamWriter &Writer) {
+ return Writer.writeArray(makeArrayRef(OldFpoData));
+ };
+ }
+
+ for (auto &S : DbgStreams) {
+ if (!S.hasValue())
+ continue;
+ auto ExpectedIndex = Msf.addStream(S->Size);
+ if (!ExpectedIndex)
+ return ExpectedIndex.takeError();
+ S->StreamNumber = *ExpectedIndex;
+ }
+
+ for (auto &MI : ModiList) {
+ if (auto EC = MI->finalizeMsfLayout())
+ return EC;
+ }
+
+ uint32_t Length = calculateSerializedLength();
+ if (auto EC = Msf.setStreamSize(StreamDBI, Length))
+ return EC;
+ return Error::success();
+}
+
+static uint16_t toSecMapFlags(uint32_t Flags) {
+ uint16_t Ret = 0;
+ if (Flags & COFF::IMAGE_SCN_MEM_READ)
+ Ret |= static_cast<uint16_t>(OMFSegDescFlags::Read);
+ if (Flags & COFF::IMAGE_SCN_MEM_WRITE)
+ Ret |= static_cast<uint16_t>(OMFSegDescFlags::Write);
+ if (Flags & COFF::IMAGE_SCN_MEM_EXECUTE)
+ Ret |= static_cast<uint16_t>(OMFSegDescFlags::Execute);
+ if (!(Flags & COFF::IMAGE_SCN_MEM_16BIT))
+ Ret |= static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit);
+
+ // This seems always 1.
+ Ret |= static_cast<uint16_t>(OMFSegDescFlags::IsSelector);
+
+ return Ret;
+}
+
+// Populate the Section Map from COFF section headers.
+//
+// A Section Map seem to be a copy of a COFF section list in other format.
+// I don't know why a PDB file contains both a COFF section header and
+// a Section Map, but it seems it must be present in a PDB.
+void DbiStreamBuilder::createSectionMap(
+ ArrayRef<llvm::object::coff_section> SecHdrs) {
+ int Idx = 0;
+
+ auto Add = [&]() -> SecMapEntry & {
+ SectionMap.emplace_back();
+ auto &Entry = SectionMap.back();
+ memset(&Entry, 0, sizeof(Entry));
+
+ Entry.Frame = Idx + 1;
+
+ // We don't know the meaning of these fields yet.
+ Entry.SecName = UINT16_MAX;
+ Entry.ClassName = UINT16_MAX;
+
+ return Entry;
+ };
+
+ for (auto &Hdr : SecHdrs) {
+ auto &Entry = Add();
+ Entry.Flags = toSecMapFlags(Hdr.Characteristics);
+ Entry.SecByteLength = Hdr.VirtualSize;
+ ++Idx;
+ }
+
+ // The last entry is for absolute symbols.
+ auto &Entry = Add();
+ Entry.Flags = static_cast<uint16_t>(OMFSegDescFlags::AddressIs32Bit) |
+ static_cast<uint16_t>(OMFSegDescFlags::IsAbsoluteAddress);
+ Entry.SecByteLength = UINT32_MAX;
+}
+
+Error DbiStreamBuilder::commit(const msf::MSFLayout &Layout,
+ WritableBinaryStreamRef MsfBuffer) {
+ if (auto EC = finalize())
+ return EC;
+
+ auto DbiS = WritableMappedBlockStream::createIndexedStream(
+ Layout, MsfBuffer, StreamDBI, Allocator);
+
+ BinaryStreamWriter Writer(*DbiS);
+ if (auto EC = Writer.writeObject(*Header))
+ return EC;
+
+ for (auto &M : ModiList) {
+ if (auto EC = M->commit(Writer))
+ return EC;
+ }
+
+ // Commit symbol streams. This is a lot of data, so do it in parallel.
+ if (auto EC = parallelForEachError(
+ ModiList, [&](std::unique_ptr<DbiModuleDescriptorBuilder> &M) {
+ return M->commitSymbolStream(Layout, MsfBuffer);
+ }))
+ return EC;
+
+ if (!SectionContribs.empty()) {
+ if (auto EC = Writer.writeEnum(DbiSecContribVer60))
+ return EC;
+ if (auto EC = Writer.writeArray(makeArrayRef(SectionContribs)))
+ return EC;
+ }
+
+ if (!SectionMap.empty()) {
+ ulittle16_t Size = static_cast<ulittle16_t>(SectionMap.size());
+ SecMapHeader SMHeader = {Size, Size};
+ if (auto EC = Writer.writeObject(SMHeader))
+ return EC;
+ if (auto EC = Writer.writeArray(makeArrayRef(SectionMap)))
+ return EC;
+ }
+
+ if (auto EC = Writer.writeStreamRef(FileInfoBuffer))
+ return EC;
+
+ if (auto EC = ECNamesBuilder.commit(Writer))
+ return EC;
+
+ for (auto &Stream : DbgStreams) {
+ uint16_t StreamNumber = kInvalidStreamIndex;
+ if (Stream.hasValue())
+ StreamNumber = Stream->StreamNumber;
+ if (auto EC = Writer.writeInteger(StreamNumber))
+ return EC;
+ }
+
+ for (auto &Stream : DbgStreams) {
+ if (!Stream.hasValue())
+ continue;
+ assert(Stream->StreamNumber != kInvalidStreamIndex);
+
+ auto WritableStream = WritableMappedBlockStream::createIndexedStream(
+ Layout, MsfBuffer, Stream->StreamNumber, Allocator);
+ BinaryStreamWriter DbgStreamWriter(*WritableStream);
+
+ if (auto EC = Stream->WriteFn(DbgStreamWriter))
+ return EC;
+ }
+
+ if (Writer.bytesRemaining() > 0)
+ return make_error<RawError>(raw_error_code::invalid_format,
+ "Unexpected bytes found in DBI Stream");
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/EnumTables.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/EnumTables.cpp
new file mode 100644
index 0000000000..37192ba36a
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/EnumTables.cpp
@@ -0,0 +1,37 @@
+//===- EnumTables.cpp - Enum to string conversion tables --------*- 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/PDB/Native/EnumTables.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+#define PDB_ENUM_CLASS_ENT(enum_class, enum) \
+ { #enum, std::underlying_type < enum_class > ::type(enum_class::enum) }
+
+#define PDB_ENUM_ENT(ns, enum) \
+ { #enum, ns::enum }
+
+static const EnumEntry<uint16_t> OMFSegMapDescFlagNames[] = {
+ PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Read),
+ PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Write),
+ PDB_ENUM_CLASS_ENT(OMFSegDescFlags, Execute),
+ PDB_ENUM_CLASS_ENT(OMFSegDescFlags, AddressIs32Bit),
+ PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsSelector),
+ PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsAbsoluteAddress),
+ PDB_ENUM_CLASS_ENT(OMFSegDescFlags, IsGroup),
+};
+
+namespace llvm {
+namespace pdb {
+ArrayRef<EnumEntry<uint16_t>> getOMFSegMapDescFlagNames() {
+ return makeArrayRef(OMFSegMapDescFlagNames);
+}
+}
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp
new file mode 100644
index 0000000000..9084e689d1
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/GSIStreamBuilder.cpp
@@ -0,0 +1,494 @@
+//===- DbiStreamBuilder.cpp - PDB Dbi Stream Creation -----------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// The data structures defined in this file are based on the reference
+// implementation which is available at
+// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.cpp
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
+#include "llvm/DebugInfo/CodeView/RecordName.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/SymbolSerializer.h"
+#include "llvm/DebugInfo/MSF/MSFBuilder.h"
+#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/Hash.h"
+#include "llvm/Support/BinaryItemStream.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Parallel.h"
+#include "llvm/Support/xxhash.h"
+#include <algorithm>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+using namespace llvm::codeview;
+
+// Helper class for building the public and global PDB hash table buckets.
+struct llvm::pdb::GSIHashStreamBuilder {
+ // Sum of the size of all public or global records.
+ uint32_t RecordByteSize = 0;
+
+ std::vector<PSHashRecord> HashRecords;
+
+ // The hash bitmap has `ceil((IPHR_HASH + 1) / 32)` words in it. The
+ // reference implementation builds a hash table with IPHR_HASH buckets in it.
+ // The last bucket is used to link together free hash table cells in a linked
+ // list, but it is always empty in the compressed, on-disk format. However,
+ // the bitmap must have a bit for it.
+ std::array<support::ulittle32_t, (IPHR_HASH + 32) / 32> HashBitmap;
+
+ std::vector<support::ulittle32_t> HashBuckets;
+
+ uint32_t calculateSerializedLength() const;
+ Error commit(BinaryStreamWriter &Writer);
+
+ void finalizePublicBuckets();
+ void finalizeGlobalBuckets(uint32_t RecordZeroOffset);
+
+ // Assign public and global symbol records into hash table buckets.
+ // Modifies the list of records to store the bucket index, but does not
+ // change the order.
+ void finalizeBuckets(uint32_t RecordZeroOffset,
+ MutableArrayRef<BulkPublic> Globals);
+};
+
+// DenseMapInfo implementation for deduplicating symbol records.
+struct llvm::pdb::SymbolDenseMapInfo {
+ static inline CVSymbol getEmptyKey() {
+ static CVSymbol Empty;
+ return Empty;
+ }
+ static inline CVSymbol getTombstoneKey() {
+ static CVSymbol Tombstone(
+ DenseMapInfo<ArrayRef<uint8_t>>::getTombstoneKey());
+ return Tombstone;
+ }
+ static unsigned getHashValue(const CVSymbol &Val) {
+ return xxHash64(Val.RecordData);
+ }
+ static bool isEqual(const CVSymbol &LHS, const CVSymbol &RHS) {
+ return LHS.RecordData == RHS.RecordData;
+ }
+};
+
+namespace {
+LLVM_PACKED_START
+struct PublicSym32Layout {
+ RecordPrefix Prefix;
+ PublicSym32Header Pub;
+ // char Name[];
+};
+LLVM_PACKED_END
+} // namespace
+
+// Calculate how much memory this public needs when serialized.
+static uint32_t sizeOfPublic(const BulkPublic &Pub) {
+ uint32_t NameLen = Pub.NameLen;
+ NameLen = std::min(NameLen,
+ uint32_t(MaxRecordLength - sizeof(PublicSym32Layout) - 1));
+ return alignTo(sizeof(PublicSym32Layout) + NameLen + 1, 4);
+}
+
+static CVSymbol serializePublic(uint8_t *Mem, const BulkPublic &Pub) {
+ // Assume the caller has allocated sizeOfPublic bytes.
+ uint32_t NameLen = std::min(
+ Pub.NameLen, uint32_t(MaxRecordLength - sizeof(PublicSym32Layout) - 1));
+ size_t Size = alignTo(sizeof(PublicSym32Layout) + NameLen + 1, 4);
+ assert(Size == sizeOfPublic(Pub));
+ auto *FixedMem = reinterpret_cast<PublicSym32Layout *>(Mem);
+ FixedMem->Prefix.RecordKind = static_cast<uint16_t>(codeview::S_PUB32);
+ FixedMem->Prefix.RecordLen = static_cast<uint16_t>(Size - 2);
+ FixedMem->Pub.Flags = Pub.Flags;
+ FixedMem->Pub.Offset = Pub.Offset;
+ FixedMem->Pub.Segment = Pub.Segment;
+ char *NameMem = reinterpret_cast<char *>(FixedMem + 1);
+ memcpy(NameMem, Pub.Name, NameLen);
+ // Zero the null terminator and remaining bytes.
+ memset(&NameMem[NameLen], 0, Size - sizeof(PublicSym32Layout) - NameLen);
+ return CVSymbol(makeArrayRef(reinterpret_cast<uint8_t *>(Mem), Size));
+}
+
+uint32_t GSIHashStreamBuilder::calculateSerializedLength() const {
+ uint32_t Size = sizeof(GSIHashHeader);
+ Size += HashRecords.size() * sizeof(PSHashRecord);
+ Size += HashBitmap.size() * sizeof(uint32_t);
+ Size += HashBuckets.size() * sizeof(uint32_t);
+ return Size;
+}
+
+Error GSIHashStreamBuilder::commit(BinaryStreamWriter &Writer) {
+ GSIHashHeader Header;
+ Header.VerSignature = GSIHashHeader::HdrSignature;
+ Header.VerHdr = GSIHashHeader::HdrVersion;
+ Header.HrSize = HashRecords.size() * sizeof(PSHashRecord);
+ Header.NumBuckets = HashBitmap.size() * 4 + HashBuckets.size() * 4;
+
+ if (auto EC = Writer.writeObject(Header))
+ return EC;
+
+ if (auto EC = Writer.writeArray(makeArrayRef(HashRecords)))
+ return EC;
+ if (auto EC = Writer.writeArray(makeArrayRef(HashBitmap)))
+ return EC;
+ if (auto EC = Writer.writeArray(makeArrayRef(HashBuckets)))
+ return EC;
+ return Error::success();
+}
+
+static bool isAsciiString(StringRef S) {
+ return llvm::all_of(S, [](char C) { return unsigned(C) < 0x80; });
+}
+
+// See `caseInsensitiveComparePchPchCchCch` in gsi.cpp
+static int gsiRecordCmp(StringRef S1, StringRef S2) {
+ size_t LS = S1.size();
+ size_t RS = S2.size();
+ // Shorter strings always compare less than longer strings.
+ if (LS != RS)
+ return (LS > RS) - (LS < RS);
+
+ // If either string contains non ascii characters, memcmp them.
+ if (LLVM_UNLIKELY(!isAsciiString(S1) || !isAsciiString(S2)))
+ return memcmp(S1.data(), S2.data(), LS);
+
+ // Both strings are ascii, perform a case-insensitive comparison.
+ return S1.compare_insensitive(S2.data());
+}
+
+void GSIStreamBuilder::finalizePublicBuckets() {
+ PSH->finalizeBuckets(0, Publics);
+}
+
+void GSIStreamBuilder::finalizeGlobalBuckets(uint32_t RecordZeroOffset) {
+ // Build up a list of globals to be bucketed. Use the BulkPublic data
+ // structure for this purpose, even though these are global records, not
+ // public records. Most of the same fields are required:
+ // - Name
+ // - NameLen
+ // - SymOffset
+ // - BucketIdx
+ // The dead fields are Offset, Segment, and Flags.
+ std::vector<BulkPublic> Records;
+ Records.resize(Globals.size());
+ uint32_t SymOffset = RecordZeroOffset;
+ for (size_t I = 0, E = Globals.size(); I < E; ++I) {
+ StringRef Name = getSymbolName(Globals[I]);
+ Records[I].Name = Name.data();
+ Records[I].NameLen = Name.size();
+ Records[I].SymOffset = SymOffset;
+ SymOffset += Globals[I].length();
+ }
+
+ GSH->finalizeBuckets(RecordZeroOffset, Records);
+}
+
+void GSIHashStreamBuilder::finalizeBuckets(
+ uint32_t RecordZeroOffset, MutableArrayRef<BulkPublic> Records) {
+ // Hash every name in parallel.
+ parallelForEachN(0, Records.size(), [&](size_t I) {
+ Records[I].setBucketIdx(hashStringV1(Records[I].Name) % IPHR_HASH);
+ });
+
+ // Count up the size of each bucket. Then, use an exclusive prefix sum to
+ // calculate the bucket start offsets. This is C++17 std::exclusive_scan, but
+ // we can't use it yet.
+ uint32_t BucketStarts[IPHR_HASH] = {0};
+ for (const BulkPublic &P : Records)
+ ++BucketStarts[P.BucketIdx];
+ uint32_t Sum = 0;
+ for (uint32_t &B : BucketStarts) {
+ uint32_t Size = B;
+ B = Sum;
+ Sum += Size;
+ }
+
+ // Place globals into the hash table in bucket order. When placing a global,
+ // update the bucket start. Every hash table slot should be filled. Always use
+ // a refcount of one for now.
+ HashRecords.resize(Records.size());
+ uint32_t BucketCursors[IPHR_HASH];
+ memcpy(BucketCursors, BucketStarts, sizeof(BucketCursors));
+ for (int I = 0, E = Records.size(); I < E; ++I) {
+ uint32_t HashIdx = BucketCursors[Records[I].BucketIdx]++;
+ HashRecords[HashIdx].Off = I;
+ HashRecords[HashIdx].CRef = 1;
+ }
+
+ // Within the buckets, sort each bucket by memcmp of the symbol's name. It's
+ // important that we use the same sorting algorithm as is used by the
+ // reference implementation to ensure that the search for a record within a
+ // bucket can properly early-out when it detects the record won't be found.
+ // The algorithm used here corresponds to the function
+ // caseInsensitiveComparePchPchCchCch in the reference implementation.
+ parallelForEachN(0, IPHR_HASH, [&](size_t I) {
+ auto B = HashRecords.begin() + BucketStarts[I];
+ auto E = HashRecords.begin() + BucketCursors[I];
+ if (B == E)
+ return;
+ auto BucketCmp = [Records](const PSHashRecord &LHash,
+ const PSHashRecord &RHash) {
+ const BulkPublic &L = Records[uint32_t(LHash.Off)];
+ const BulkPublic &R = Records[uint32_t(RHash.Off)];
+ assert(L.BucketIdx == R.BucketIdx);
+ int Cmp = gsiRecordCmp(L.getName(), R.getName());
+ if (Cmp != 0)
+ return Cmp < 0;
+ // This comparison is necessary to make the sorting stable in the presence
+ // of two static globals with the same name. The easiest way to observe
+ // this is with S_LDATA32 records.
+ return L.SymOffset < R.SymOffset;
+ };
+ llvm::sort(B, E, BucketCmp);
+
+ // After we are done sorting, replace the global indices with the stream
+ // offsets of each global. Add one when writing symbol offsets to disk.
+ // See GSI1::fixSymRecs.
+ for (PSHashRecord &HRec : make_range(B, E))
+ HRec.Off = Records[uint32_t(HRec.Off)].SymOffset + 1;
+ });
+
+ // For each non-empty bucket, push the bucket start offset into HashBuckets
+ // and set a bit in the hash bitmap.
+ for (uint32_t I = 0; I < HashBitmap.size(); ++I) {
+ uint32_t Word = 0;
+ for (uint32_t J = 0; J < 32; ++J) {
+ // Skip empty buckets.
+ uint32_t BucketIdx = I * 32 + J;
+ if (BucketIdx >= IPHR_HASH ||
+ BucketStarts[BucketIdx] == BucketCursors[BucketIdx])
+ continue;
+ Word |= (1U << J);
+
+ // Calculate what the offset of the first hash record in the chain would
+ // be if it were inflated to contain 32-bit pointers. On a 32-bit system,
+ // each record would be 12 bytes. See HROffsetCalc in gsi.h.
+ const int SizeOfHROffsetCalc = 12;
+ ulittle32_t ChainStartOff =
+ ulittle32_t(BucketStarts[BucketIdx] * SizeOfHROffsetCalc);
+ HashBuckets.push_back(ChainStartOff);
+ }
+ HashBitmap[I] = Word;
+ }
+}
+
+GSIStreamBuilder::GSIStreamBuilder(msf::MSFBuilder &Msf)
+ : Msf(Msf), PSH(std::make_unique<GSIHashStreamBuilder>()),
+ GSH(std::make_unique<GSIHashStreamBuilder>()) {}
+
+GSIStreamBuilder::~GSIStreamBuilder() {}
+
+uint32_t GSIStreamBuilder::calculatePublicsHashStreamSize() const {
+ uint32_t Size = 0;
+ Size += sizeof(PublicsStreamHeader);
+ Size += PSH->calculateSerializedLength();
+ Size += Publics.size() * sizeof(uint32_t); // AddrMap
+ // FIXME: Add thunk map and section offsets for incremental linking.
+
+ return Size;
+}
+
+uint32_t GSIStreamBuilder::calculateGlobalsHashStreamSize() const {
+ return GSH->calculateSerializedLength();
+}
+
+Error GSIStreamBuilder::finalizeMsfLayout() {
+ // First we write public symbol records, then we write global symbol records.
+ finalizePublicBuckets();
+ finalizeGlobalBuckets(PSH->RecordByteSize);
+
+ Expected<uint32_t> Idx = Msf.addStream(calculateGlobalsHashStreamSize());
+ if (!Idx)
+ return Idx.takeError();
+ GlobalsStreamIndex = *Idx;
+
+ Idx = Msf.addStream(calculatePublicsHashStreamSize());
+ if (!Idx)
+ return Idx.takeError();
+ PublicsStreamIndex = *Idx;
+
+ uint32_t RecordBytes = PSH->RecordByteSize + GSH->RecordByteSize;
+
+ Idx = Msf.addStream(RecordBytes);
+ if (!Idx)
+ return Idx.takeError();
+ RecordStreamIndex = *Idx;
+ return Error::success();
+}
+
+void GSIStreamBuilder::addPublicSymbols(std::vector<BulkPublic> &&PublicsIn) {
+ assert(Publics.empty() && PSH->RecordByteSize == 0 &&
+ "publics can only be added once");
+ Publics = std::move(PublicsIn);
+
+ // Sort the symbols by name. PDBs contain lots of symbols, so use parallelism.
+ parallelSort(Publics, [](const BulkPublic &L, const BulkPublic &R) {
+ return L.getName() < R.getName();
+ });
+
+ // Assign offsets and calculate the length of the public symbol records.
+ uint32_t SymOffset = 0;
+ for (BulkPublic &Pub : Publics) {
+ Pub.SymOffset = SymOffset;
+ SymOffset += sizeOfPublic(Pub);
+ }
+
+ // Remember the length of the public stream records.
+ PSH->RecordByteSize = SymOffset;
+}
+
+void GSIStreamBuilder::addGlobalSymbol(const ProcRefSym &Sym) {
+ serializeAndAddGlobal(Sym);
+}
+
+void GSIStreamBuilder::addGlobalSymbol(const DataSym &Sym) {
+ serializeAndAddGlobal(Sym);
+}
+
+void GSIStreamBuilder::addGlobalSymbol(const ConstantSym &Sym) {
+ serializeAndAddGlobal(Sym);
+}
+
+template <typename T>
+void GSIStreamBuilder::serializeAndAddGlobal(const T &Symbol) {
+ T Copy(Symbol);
+ addGlobalSymbol(SymbolSerializer::writeOneSymbol(Copy, Msf.getAllocator(),
+ CodeViewContainer::Pdb));
+}
+
+void GSIStreamBuilder::addGlobalSymbol(const codeview::CVSymbol &Symbol) {
+ // Ignore duplicate typedefs and constants.
+ if (Symbol.kind() == S_UDT || Symbol.kind() == S_CONSTANT) {
+ auto Iter = GlobalsSeen.insert(Symbol);
+ if (!Iter.second)
+ return;
+ }
+ GSH->RecordByteSize += Symbol.length();
+ Globals.push_back(Symbol);
+}
+
+// Serialize each public and write it.
+static Error writePublics(BinaryStreamWriter &Writer,
+ ArrayRef<BulkPublic> Publics) {
+ std::vector<uint8_t> Storage;
+ for (const BulkPublic &Pub : Publics) {
+ Storage.resize(sizeOfPublic(Pub));
+ serializePublic(Storage.data(), Pub);
+ if (Error E = Writer.writeBytes(Storage))
+ return E;
+ }
+ return Error::success();
+}
+
+static Error writeRecords(BinaryStreamWriter &Writer,
+ ArrayRef<CVSymbol> Records) {
+ BinaryItemStream<CVSymbol> ItemStream(support::endianness::little);
+ ItemStream.setItems(Records);
+ BinaryStreamRef RecordsRef(ItemStream);
+ return Writer.writeStreamRef(RecordsRef);
+}
+
+Error GSIStreamBuilder::commitSymbolRecordStream(
+ WritableBinaryStreamRef Stream) {
+ BinaryStreamWriter Writer(Stream);
+
+ // Write public symbol records first, followed by global symbol records. This
+ // must match the order that we assume in finalizeMsfLayout when computing
+ // PSHZero and GSHZero.
+ if (auto EC = writePublics(Writer, Publics))
+ return EC;
+ if (auto EC = writeRecords(Writer, Globals))
+ return EC;
+
+ return Error::success();
+}
+
+static std::vector<support::ulittle32_t>
+computeAddrMap(ArrayRef<BulkPublic> Publics) {
+ // Build a parallel vector of indices into the Publics vector, and sort it by
+ // address.
+ std::vector<ulittle32_t> PubAddrMap;
+ PubAddrMap.reserve(Publics.size());
+ for (int I = 0, E = Publics.size(); I < E; ++I)
+ PubAddrMap.push_back(ulittle32_t(I));
+
+ auto AddrCmp = [Publics](const ulittle32_t &LIdx, const ulittle32_t &RIdx) {
+ const BulkPublic &L = Publics[LIdx];
+ const BulkPublic &R = Publics[RIdx];
+ if (L.Segment != R.Segment)
+ return L.Segment < R.Segment;
+ if (L.Offset != R.Offset)
+ return L.Offset < R.Offset;
+ // parallelSort is unstable, so we have to do name comparison to ensure
+ // that two names for the same location come out in a deterministic order.
+ return L.getName() < R.getName();
+ };
+ parallelSort(PubAddrMap, AddrCmp);
+
+ // Rewrite the public symbol indices into symbol offsets.
+ for (ulittle32_t &Entry : PubAddrMap)
+ Entry = Publics[Entry].SymOffset;
+ return PubAddrMap;
+}
+
+Error GSIStreamBuilder::commitPublicsHashStream(
+ WritableBinaryStreamRef Stream) {
+ BinaryStreamWriter Writer(Stream);
+ PublicsStreamHeader Header;
+
+ // FIXME: Fill these in. They are for incremental linking.
+ Header.SymHash = PSH->calculateSerializedLength();
+ Header.AddrMap = Publics.size() * 4;
+ Header.NumThunks = 0;
+ Header.SizeOfThunk = 0;
+ Header.ISectThunkTable = 0;
+ memset(Header.Padding, 0, sizeof(Header.Padding));
+ Header.OffThunkTable = 0;
+ Header.NumSections = 0;
+ if (auto EC = Writer.writeObject(Header))
+ return EC;
+
+ if (auto EC = PSH->commit(Writer))
+ return EC;
+
+ std::vector<support::ulittle32_t> PubAddrMap = computeAddrMap(Publics);
+ assert(PubAddrMap.size() == Publics.size());
+ if (auto EC = Writer.writeArray(makeArrayRef(PubAddrMap)))
+ return EC;
+
+ return Error::success();
+}
+
+Error GSIStreamBuilder::commitGlobalsHashStream(
+ WritableBinaryStreamRef Stream) {
+ BinaryStreamWriter Writer(Stream);
+ return GSH->commit(Writer);
+}
+
+Error GSIStreamBuilder::commit(const msf::MSFLayout &Layout,
+ WritableBinaryStreamRef Buffer) {
+ auto GS = WritableMappedBlockStream::createIndexedStream(
+ Layout, Buffer, getGlobalsStreamIndex(), Msf.getAllocator());
+ auto PS = WritableMappedBlockStream::createIndexedStream(
+ Layout, Buffer, getPublicsStreamIndex(), Msf.getAllocator());
+ auto PRS = WritableMappedBlockStream::createIndexedStream(
+ Layout, Buffer, getRecordStreamIndex(), Msf.getAllocator());
+
+ if (auto EC = commitSymbolRecordStream(*PRS))
+ return EC;
+ if (auto EC = commitGlobalsHashStream(*GS))
+ return EC;
+ if (auto EC = commitPublicsHashStream(*PS))
+ return EC;
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/GlobalsStream.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/GlobalsStream.cpp
new file mode 100644
index 0000000000..f27d60f468
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/GlobalsStream.cpp
@@ -0,0 +1,181 @@
+//===- GlobalsStream.cpp - PDB Index of Symbols by Name ---------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// The on-disk structores used in this file are based on the reference
+// implementation which is available at
+// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h
+//
+// When you are reading the reference source code, you'd find the
+// information below useful.
+//
+// - ppdb1->m_fMinimalDbgInfo seems to be always true.
+// - SMALLBUCKETS macro is defined.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+
+#include "llvm/DebugInfo/CodeView/RecordName.h"
+#include "llvm/DebugInfo/PDB/Native/Hash.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+
+using namespace llvm;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+GlobalsStream::GlobalsStream(std::unique_ptr<MappedBlockStream> Stream)
+ : Stream(std::move(Stream)) {}
+
+GlobalsStream::~GlobalsStream() = default;
+
+Error GlobalsStream::reload() {
+ BinaryStreamReader Reader(*Stream);
+ if (auto E = GlobalsTable.read(Reader))
+ return E;
+ return Error::success();
+}
+
+std::vector<std::pair<uint32_t, codeview::CVSymbol>>
+GlobalsStream::findRecordsByName(StringRef Name,
+ const SymbolStream &Symbols) const {
+ std::vector<std::pair<uint32_t, codeview::CVSymbol>> Result;
+
+ // Hash the name to figure out which bucket this goes into.
+ size_t ExpandedBucketIndex = hashStringV1(Name) % IPHR_HASH;
+ int32_t CompressedBucketIndex = GlobalsTable.BucketMap[ExpandedBucketIndex];
+ if (CompressedBucketIndex == -1)
+ return Result;
+
+ uint32_t LastBucketIndex = GlobalsTable.HashBuckets.size() - 1;
+ uint32_t StartRecordIndex =
+ GlobalsTable.HashBuckets[CompressedBucketIndex] / 12;
+ uint32_t EndRecordIndex = 0;
+ if (LLVM_LIKELY(uint32_t(CompressedBucketIndex) < LastBucketIndex)) {
+ EndRecordIndex = GlobalsTable.HashBuckets[CompressedBucketIndex + 1];
+ } else {
+ // If this is the last bucket, it consists of all hash records until the end
+ // of the HashRecords array.
+ EndRecordIndex = GlobalsTable.HashRecords.size() * 12;
+ }
+
+ EndRecordIndex /= 12;
+
+ assert(EndRecordIndex <= GlobalsTable.HashRecords.size());
+ while (StartRecordIndex < EndRecordIndex) {
+ PSHashRecord PSH = GlobalsTable.HashRecords[StartRecordIndex];
+ uint32_t Off = PSH.Off - 1;
+ codeview::CVSymbol Record = Symbols.readRecord(Off);
+ if (codeview::getSymbolName(Record) == Name)
+ Result.push_back(std::make_pair(Off, std::move(Record)));
+ ++StartRecordIndex;
+ }
+ return Result;
+}
+
+static Error checkHashHdrVersion(const GSIHashHeader *HashHdr) {
+ if (HashHdr->VerHdr != GSIHashHeader::HdrVersion)
+ return make_error<RawError>(
+ raw_error_code::feature_unsupported,
+ "Encountered unsupported globals stream version.");
+
+ return Error::success();
+}
+
+static Error readGSIHashHeader(const GSIHashHeader *&HashHdr,
+ BinaryStreamReader &Reader) {
+ if (Reader.readObject(HashHdr))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Stream does not contain a GSIHashHeader.");
+
+ if (HashHdr->VerSignature != GSIHashHeader::HdrSignature)
+ return make_error<RawError>(
+ raw_error_code::feature_unsupported,
+ "GSIHashHeader signature (0xffffffff) not found.");
+
+ return Error::success();
+}
+
+static Error readGSIHashRecords(FixedStreamArray<PSHashRecord> &HashRecords,
+ const GSIHashHeader *HashHdr,
+ BinaryStreamReader &Reader) {
+ if (auto EC = checkHashHdrVersion(HashHdr))
+ return EC;
+
+ // HashHdr->HrSize specifies the number of bytes of PSHashRecords we have.
+ // Verify that we can read them all.
+ if (HashHdr->HrSize % sizeof(PSHashRecord))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid HR array size.");
+ uint32_t NumHashRecords = HashHdr->HrSize / sizeof(PSHashRecord);
+ if (auto EC = Reader.readArray(HashRecords, NumHashRecords))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Error reading hash records."));
+
+ return Error::success();
+}
+
+static Error
+readGSIHashBuckets(FixedStreamArray<support::ulittle32_t> &HashBuckets,
+ FixedStreamArray<support::ulittle32_t> &HashBitmap,
+ const GSIHashHeader *HashHdr,
+ MutableArrayRef<int32_t> BucketMap,
+ BinaryStreamReader &Reader) {
+ if (auto EC = checkHashHdrVersion(HashHdr))
+ return EC;
+
+ // Before the actual hash buckets, there is a bitmap of length determined by
+ // IPHR_HASH.
+ size_t BitmapSizeInBits = alignTo(IPHR_HASH + 1, 32);
+ uint32_t NumBitmapEntries = BitmapSizeInBits / 32;
+ if (auto EC = Reader.readArray(HashBitmap, NumBitmapEntries))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not read a bitmap."));
+ uint32_t NumBuckets1 = 0;
+ uint32_t CompressedBucketIdx = 0;
+ for (uint32_t I = 0; I <= IPHR_HASH; ++I) {
+ uint8_t WordIdx = I / 32;
+ uint8_t BitIdx = I % 32;
+ bool IsSet = HashBitmap[WordIdx] & (1U << BitIdx);
+ if (IsSet) {
+ ++NumBuckets1;
+ BucketMap[I] = CompressedBucketIdx++;
+ } else {
+ BucketMap[I] = -1;
+ }
+ }
+
+ uint32_t NumBuckets = 0;
+ for (uint32_t B : HashBitmap)
+ NumBuckets += countPopulation(B);
+
+ // Hash buckets follow.
+ if (auto EC = Reader.readArray(HashBuckets, NumBuckets))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Hash buckets corrupted."));
+
+ return Error::success();
+}
+
+Error GSIHashTable::read(BinaryStreamReader &Reader) {
+ if (auto EC = readGSIHashHeader(HashHdr, Reader))
+ return EC;
+ if (auto EC = readGSIHashRecords(HashRecords, HashHdr, Reader))
+ return EC;
+ if (HashHdr->HrSize > 0)
+ if (auto EC = readGSIHashBuckets(HashBuckets, HashBitmap, HashHdr,
+ BucketMap, Reader))
+ return EC;
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/Hash.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/Hash.cpp
new file mode 100644
index 0000000000..7fb6b4bd5d
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/Hash.cpp
@@ -0,0 +1,84 @@
+//===- Hash.cpp - PDB Hash Functions --------------------------------------===//
+//
+// 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/PDB/Native/Hash.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/CRC.h"
+#include "llvm/Support/Endian.h"
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::support;
+
+// Corresponds to `Hasher::lhashPbCb` in PDB/include/misc.h.
+// Used for name hash table and TPI/IPI hashes.
+uint32_t pdb::hashStringV1(StringRef Str) {
+ uint32_t Result = 0;
+ uint32_t Size = Str.size();
+
+ ArrayRef<ulittle32_t> Longs(reinterpret_cast<const ulittle32_t *>(Str.data()),
+ Size / 4);
+
+ for (auto Value : Longs)
+ Result ^= Value;
+
+ const uint8_t *Remainder = reinterpret_cast<const uint8_t *>(Longs.end());
+ uint32_t RemainderSize = Size % 4;
+
+ // Maximum of 3 bytes left. Hash a 2 byte word if possible, then hash the
+ // possibly remaining 1 byte.
+ if (RemainderSize >= 2) {
+ uint16_t Value = *reinterpret_cast<const ulittle16_t *>(Remainder);
+ Result ^= static_cast<uint32_t>(Value);
+ Remainder += 2;
+ RemainderSize -= 2;
+ }
+
+ // hash possible odd byte
+ if (RemainderSize == 1) {
+ Result ^= *(Remainder++);
+ }
+
+ const uint32_t toLowerMask = 0x20202020;
+ Result |= toLowerMask;
+ Result ^= (Result >> 11);
+
+ return Result ^ (Result >> 16);
+}
+
+// Corresponds to `HasherV2::HashULONG` in PDB/include/misc.h.
+// Used for name hash table.
+uint32_t pdb::hashStringV2(StringRef Str) {
+ uint32_t Hash = 0xb170a1bf;
+
+ ArrayRef<char> Buffer(Str.begin(), Str.end());
+
+ ArrayRef<ulittle32_t> Items(
+ reinterpret_cast<const ulittle32_t *>(Buffer.data()),
+ Buffer.size() / sizeof(ulittle32_t));
+ for (ulittle32_t Item : Items) {
+ Hash += Item;
+ Hash += (Hash << 10);
+ Hash ^= (Hash >> 6);
+ }
+ Buffer = Buffer.slice(Items.size() * sizeof(ulittle32_t));
+ for (uint8_t Item : Buffer) {
+ Hash += Item;
+ Hash += (Hash << 10);
+ Hash ^= (Hash >> 6);
+ }
+
+ return Hash * 1664525U + 1013904223U;
+}
+
+// Corresponds to `SigForPbCb` in langapi/shared/crc32.h.
+uint32_t pdb::hashBufferV8(ArrayRef<uint8_t> Buf) {
+ JamCRC JC(/*Init=*/0U);
+ JC.update(Buf);
+ return JC.getCRC();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/HashTable.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/HashTable.cpp
new file mode 100644
index 0000000000..dfdcdf1f4e
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/HashTable.cpp
@@ -0,0 +1,71 @@
+//===- HashTable.cpp - PDB Hash Table -------------------------------------===//
+//
+// 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/PDB/Native/HashTable.h"
+#include "llvm/ADT/Optional.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MathExtras.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+Error llvm::pdb::readSparseBitVector(BinaryStreamReader &Stream,
+ SparseBitVector<> &V) {
+ uint32_t NumWords;
+ if (auto EC = Stream.readInteger(NumWords))
+ return joinErrors(
+ std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Expected hash table number of words"));
+
+ for (uint32_t I = 0; I != NumWords; ++I) {
+ uint32_t Word;
+ if (auto EC = Stream.readInteger(Word))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Expected hash table word"));
+ for (unsigned Idx = 0; Idx < 32; ++Idx)
+ if (Word & (1U << Idx))
+ V.set((I * 32) + Idx);
+ }
+ return Error::success();
+}
+
+Error llvm::pdb::writeSparseBitVector(BinaryStreamWriter &Writer,
+ SparseBitVector<> &Vec) {
+ constexpr int BitsPerWord = 8 * sizeof(uint32_t);
+
+ int ReqBits = Vec.find_last() + 1;
+ uint32_t ReqWords = alignTo(ReqBits, BitsPerWord) / BitsPerWord;
+ if (auto EC = Writer.writeInteger(ReqWords))
+ return joinErrors(
+ std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not write linear map number of words"));
+
+ uint32_t Idx = 0;
+ for (uint32_t I = 0; I != ReqWords; ++I) {
+ uint32_t Word = 0;
+ for (uint32_t WordIdx = 0; WordIdx < 32; ++WordIdx, ++Idx) {
+ if (Vec.test(Idx))
+ Word |= (1 << WordIdx);
+ }
+ if (auto EC = Writer.writeInteger(Word))
+ return joinErrors(std::move(EC), make_error<RawError>(
+ raw_error_code::corrupt_file,
+ "Could not write linear map word"));
+ }
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/InfoStream.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/InfoStream.cpp
new file mode 100644
index 0000000000..f41bb32d69
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/InfoStream.cpp
@@ -0,0 +1,131 @@
+//===- InfoStream.cpp - PDB Info Stream (Stream 1) Access -------*- 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/PDB/Native/InfoStream.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/SmallVector.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
+#include "llvm/Support/BinaryStreamReader.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+InfoStream::InfoStream(std::unique_ptr<BinaryStream> Stream)
+ : Stream(std::move(Stream)), Header(nullptr) {}
+
+Error InfoStream::reload() {
+ BinaryStreamReader Reader(*Stream);
+
+ if (auto EC = Reader.readObject(Header))
+ return joinErrors(
+ std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "PDB Stream does not contain a header."));
+
+ switch (Header->Version) {
+ case PdbImplVC70:
+ case PdbImplVC80:
+ case PdbImplVC110:
+ case PdbImplVC140:
+ break;
+ default:
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Unsupported PDB stream version.");
+ }
+
+ uint32_t Offset = Reader.getOffset();
+ if (auto EC = NamedStreams.load(Reader))
+ return EC;
+ uint32_t NewOffset = Reader.getOffset();
+ NamedStreamMapByteSize = NewOffset - Offset;
+
+ Reader.setOffset(Offset);
+ if (auto EC = Reader.readSubstream(SubNamedStreams, NamedStreamMapByteSize))
+ return EC;
+
+ bool Stop = false;
+ while (!Stop && !Reader.empty()) {
+ PdbRaw_FeatureSig Sig;
+ if (auto EC = Reader.readEnum(Sig))
+ return EC;
+ // Since this value comes from a file, it's possible we have some strange
+ // value which doesn't correspond to any value. We don't want to warn on
+ // -Wcovered-switch-default in this case, so switch on the integral value
+ // instead of the enumeration value.
+ switch (uint32_t(Sig)) {
+ case uint32_t(PdbRaw_FeatureSig::VC110):
+ // No other flags for VC110 PDB.
+ Stop = true;
+ LLVM_FALLTHROUGH;
+ case uint32_t(PdbRaw_FeatureSig::VC140):
+ Features |= PdbFeatureContainsIdStream;
+ break;
+ case uint32_t(PdbRaw_FeatureSig::NoTypeMerge):
+ Features |= PdbFeatureNoTypeMerging;
+ break;
+ case uint32_t(PdbRaw_FeatureSig::MinimalDebugInfo):
+ Features |= PdbFeatureMinimalDebugInfo;
+ break;
+ default:
+ continue;
+ }
+ FeatureSignatures.push_back(Sig);
+ }
+ return Error::success();
+}
+
+uint32_t InfoStream::getStreamSize() const { return Stream->getLength(); }
+
+Expected<uint32_t> InfoStream::getNamedStreamIndex(llvm::StringRef Name) const {
+ uint32_t Result;
+ if (!NamedStreams.get(Name, Result))
+ return make_error<RawError>(raw_error_code::no_stream);
+ return Result;
+}
+
+StringMap<uint32_t> InfoStream::named_streams() const {
+ return NamedStreams.entries();
+}
+
+bool InfoStream::containsIdStream() const {
+ return !!(Features & PdbFeatureContainsIdStream);
+}
+
+PdbRaw_ImplVer InfoStream::getVersion() const {
+ return static_cast<PdbRaw_ImplVer>(uint32_t(Header->Version));
+}
+
+uint32_t InfoStream::getSignature() const {
+ return uint32_t(Header->Signature);
+}
+
+uint32_t InfoStream::getAge() const { return uint32_t(Header->Age); }
+
+GUID InfoStream::getGuid() const { return Header->Guid; }
+
+uint32_t InfoStream::getNamedStreamMapByteSize() const {
+ return NamedStreamMapByteSize;
+}
+
+PdbRaw_Features InfoStream::getFeatures() const { return Features; }
+
+ArrayRef<PdbRaw_FeatureSig> InfoStream::getFeatureSignatures() const {
+ return FeatureSignatures;
+}
+
+const NamedStreamMap &InfoStream::getNamedStreams() const {
+ return NamedStreams;
+}
+
+BinarySubstreamRef InfoStream::getNamedStreamsBuffer() const {
+ return SubNamedStreams;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp
new file mode 100644
index 0000000000..42daa7cae7
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/InfoStreamBuilder.cpp
@@ -0,0 +1,82 @@
+//===- InfoStreamBuilder.cpp - PDB Info Stream Creation ---------*- 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/PDB/Native/InfoStreamBuilder.h"
+
+#include "llvm/DebugInfo/MSF/MSFBuilder.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/NamedStreamMap.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFileBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+InfoStreamBuilder::InfoStreamBuilder(msf::MSFBuilder &Msf,
+ NamedStreamMap &NamedStreams)
+ : Msf(Msf), Ver(PdbRaw_ImplVer::PdbImplVC70), Age(0),
+ NamedStreams(NamedStreams) {
+ ::memset(&Guid, 0, sizeof(Guid));
+}
+
+void InfoStreamBuilder::setVersion(PdbRaw_ImplVer V) { Ver = V; }
+
+void InfoStreamBuilder::addFeature(PdbRaw_FeatureSig Sig) {
+ Features.push_back(Sig);
+}
+
+void InfoStreamBuilder::setHashPDBContentsToGUID(bool B) {
+ HashPDBContentsToGUID = B;
+}
+
+void InfoStreamBuilder::setAge(uint32_t A) { Age = A; }
+
+void InfoStreamBuilder::setSignature(uint32_t S) { Signature = S; }
+
+void InfoStreamBuilder::setGuid(GUID G) { Guid = G; }
+
+
+Error InfoStreamBuilder::finalizeMsfLayout() {
+ uint32_t Length = sizeof(InfoStreamHeader) +
+ NamedStreams.calculateSerializedLength() +
+ (Features.size() + 1) * sizeof(uint32_t);
+ if (auto EC = Msf.setStreamSize(StreamPDB, Length))
+ return EC;
+ return Error::success();
+}
+
+Error InfoStreamBuilder::commit(const msf::MSFLayout &Layout,
+ WritableBinaryStreamRef Buffer) const {
+ auto InfoS = WritableMappedBlockStream::createIndexedStream(
+ Layout, Buffer, StreamPDB, Msf.getAllocator());
+ BinaryStreamWriter Writer(*InfoS);
+
+ InfoStreamHeader H;
+ // Leave the build id fields 0 so they can be set as the last step before
+ // committing the file to disk.
+ ::memset(&H, 0, sizeof(H));
+ H.Version = Ver;
+ if (auto EC = Writer.writeObject(H))
+ return EC;
+
+ if (auto EC = NamedStreams.commit(Writer))
+ return EC;
+ if (auto EC = Writer.writeInteger(0))
+ return EC;
+ for (auto E : Features) {
+ if (auto EC = Writer.writeEnum(E))
+ return EC;
+ }
+ assert(Writer.bytesRemaining() == 0);
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp
new file mode 100644
index 0000000000..3f4101db7b
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/InjectedSourceStream.cpp
@@ -0,0 +1,65 @@
+//===- InjectedSourceStream.cpp - PDB Headerblock Stream Access -----------===//
+//
+// 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/PDB/Native/InjectedSourceStream.h"
+
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/Hash.h"
+#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::msf;
+using namespace llvm::support;
+using namespace llvm::pdb;
+
+InjectedSourceStream::InjectedSourceStream(
+ std::unique_ptr<MappedBlockStream> Stream)
+ : Stream(std::move(Stream)) {}
+
+Error InjectedSourceStream::reload(const PDBStringTable &Strings) {
+ BinaryStreamReader Reader(*Stream);
+
+ if (auto EC = Reader.readObject(Header))
+ return EC;
+
+ if (Header->Version !=
+ static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid headerblock header version");
+
+ if (auto EC = InjectedSourceTable.load(Reader))
+ return EC;
+
+ for (const auto& Entry : *this) {
+ if (Entry.second.Size != sizeof(SrcHeaderBlockEntry))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid headerbock entry size");
+ if (Entry.second.Version !=
+ static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid headerbock entry version");
+
+ // Check that all name references are valid.
+ auto Name = Strings.getStringForID(Entry.second.FileNI);
+ if (!Name)
+ return Name.takeError();
+ auto ObjName = Strings.getStringForID(Entry.second.ObjNI);
+ if (!ObjName)
+ return ObjName.takeError();
+ auto VName = Strings.getStringForID(Entry.second.VFileNI);
+ if (!VName)
+ return VName.takeError();
+ }
+
+ assert(Reader.bytesRemaining() == 0);
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp
new file mode 100644
index 0000000000..1445f0bd9e
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/ModuleDebugStream.cpp
@@ -0,0 +1,144 @@
+//===- ModuleDebugStream.cpp - PDB Module Info Stream Access --------------===//
+//
+// 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/PDB/Native/ModuleDebugStream.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/DebugChecksumsSubsection.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecordHelpers.h"
+#include "llvm/DebugInfo/PDB/Native/DbiModuleDescriptor.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamRef.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+ModuleDebugStreamRef::ModuleDebugStreamRef(
+ const DbiModuleDescriptor &Module,
+ std::unique_ptr<MappedBlockStream> Stream)
+ : Mod(Module), Stream(std::move(Stream)) {}
+
+ModuleDebugStreamRef::~ModuleDebugStreamRef() = default;
+
+Error ModuleDebugStreamRef::reload() {
+ BinaryStreamReader Reader(*Stream);
+
+ if (Mod.getModuleStreamIndex() != llvm::pdb::kInvalidStreamIndex) {
+ if (Error E = reloadSerialize(Reader))
+ return E;
+ }
+ if (Reader.bytesRemaining() > 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Unexpected bytes in module stream.");
+ return Error::success();
+}
+
+Error ModuleDebugStreamRef::reloadSerialize(BinaryStreamReader &Reader) {
+ uint32_t SymbolSize = Mod.getSymbolDebugInfoByteSize();
+ uint32_t C11Size = Mod.getC11LineInfoByteSize();
+ uint32_t C13Size = Mod.getC13LineInfoByteSize();
+
+ if (C11Size > 0 && C13Size > 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Module has both C11 and C13 line info");
+
+ BinaryStreamRef S;
+
+ if (auto EC = Reader.readInteger(Signature))
+ return EC;
+ Reader.setOffset(0);
+ if (auto EC = Reader.readSubstream(SymbolsSubstream, SymbolSize))
+ return EC;
+ if (auto EC = Reader.readSubstream(C11LinesSubstream, C11Size))
+ return EC;
+ if (auto EC = Reader.readSubstream(C13LinesSubstream, C13Size))
+ return EC;
+
+ BinaryStreamReader SymbolReader(SymbolsSubstream.StreamData);
+ if (auto EC = SymbolReader.readArray(
+ SymbolArray, SymbolReader.bytesRemaining(), sizeof(uint32_t)))
+ return EC;
+
+ BinaryStreamReader SubsectionsReader(C13LinesSubstream.StreamData);
+ if (auto EC = SubsectionsReader.readArray(Subsections,
+ SubsectionsReader.bytesRemaining()))
+ return EC;
+
+ uint32_t GlobalRefsSize;
+ if (auto EC = Reader.readInteger(GlobalRefsSize))
+ return EC;
+ if (auto EC = Reader.readSubstream(GlobalRefsSubstream, GlobalRefsSize))
+ return EC;
+ return Error::success();
+}
+
+const codeview::CVSymbolArray
+ModuleDebugStreamRef::getSymbolArrayForScope(uint32_t ScopeBegin) const {
+ return limitSymbolArrayToScope(SymbolArray, ScopeBegin);
+}
+
+BinarySubstreamRef ModuleDebugStreamRef::getSymbolsSubstream() const {
+ return SymbolsSubstream;
+}
+
+BinarySubstreamRef ModuleDebugStreamRef::getC11LinesSubstream() const {
+ return C11LinesSubstream;
+}
+
+BinarySubstreamRef ModuleDebugStreamRef::getC13LinesSubstream() const {
+ return C13LinesSubstream;
+}
+
+BinarySubstreamRef ModuleDebugStreamRef::getGlobalRefsSubstream() const {
+ return GlobalRefsSubstream;
+}
+
+iterator_range<codeview::CVSymbolArray::Iterator>
+ModuleDebugStreamRef::symbols(bool *HadError) const {
+ return make_range(SymbolArray.begin(HadError), SymbolArray.end());
+}
+
+CVSymbol ModuleDebugStreamRef::readSymbolAtOffset(uint32_t Offset) const {
+ auto Iter = SymbolArray.at(Offset);
+ assert(Iter != SymbolArray.end());
+ return *Iter;
+}
+
+iterator_range<ModuleDebugStreamRef::DebugSubsectionIterator>
+ModuleDebugStreamRef::subsections() const {
+ return make_range(Subsections.begin(), Subsections.end());
+}
+
+bool ModuleDebugStreamRef::hasDebugSubsections() const {
+ return !C13LinesSubstream.empty();
+}
+
+Error ModuleDebugStreamRef::commit() { return Error::success(); }
+
+Expected<codeview::DebugChecksumsSubsectionRef>
+ModuleDebugStreamRef::findChecksumsSubsection() const {
+ codeview::DebugChecksumsSubsectionRef Result;
+ for (const auto &SS : subsections()) {
+ if (SS.kind() != DebugSubsectionKind::FileChecksums)
+ continue;
+
+ if (auto EC = Result.initialize(SS.getRecordData()))
+ return std::move(EC);
+ return Result;
+ }
+ return Result;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp
new file mode 100644
index 0000000000..1d873b87b3
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NamedStreamMap.cpp
@@ -0,0 +1,126 @@
+//===- NamedStreamMap.cpp - PDB Named Stream Map --------------------------===//
+//
+// 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/PDB/Native/NamedStreamMap.h"
+#include "llvm/ADT/StringMap.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/DebugInfo/PDB/Native/Hash.h"
+#include "llvm/DebugInfo/PDB/Native/HashTable.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamRef.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <tuple>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+NamedStreamMapTraits::NamedStreamMapTraits(NamedStreamMap &NS) : NS(&NS) {}
+
+uint16_t NamedStreamMapTraits::hashLookupKey(StringRef S) const {
+ // In the reference implementation, this uses
+ // HASH Hasher<ULONG*, USHORT*>::hashPbCb(PB pb, size_t cb, ULONG ulMod).
+ // Here, the type HASH is a typedef of unsigned short.
+ // ** It is not a bug that we truncate the result of hashStringV1, in fact
+ // it is a bug if we do not! **
+ // See NMTNI::hash() in the reference implementation.
+ return static_cast<uint16_t>(hashStringV1(S));
+}
+
+StringRef NamedStreamMapTraits::storageKeyToLookupKey(uint32_t Offset) const {
+ return NS->getString(Offset);
+}
+
+uint32_t NamedStreamMapTraits::lookupKeyToStorageKey(StringRef S) {
+ return NS->appendStringData(S);
+}
+
+NamedStreamMap::NamedStreamMap() : HashTraits(*this), OffsetIndexMap(1) {}
+
+Error NamedStreamMap::load(BinaryStreamReader &Stream) {
+ uint32_t StringBufferSize;
+ if (auto EC = Stream.readInteger(StringBufferSize))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Expected string buffer size"));
+
+ StringRef Buffer;
+ if (auto EC = Stream.readFixedString(Buffer, StringBufferSize))
+ return EC;
+ NamesBuffer.assign(Buffer.begin(), Buffer.end());
+
+ return OffsetIndexMap.load(Stream);
+}
+
+Error NamedStreamMap::commit(BinaryStreamWriter &Writer) const {
+ // The first field is the number of bytes of string data.
+ if (auto EC = Writer.writeInteger<uint32_t>(NamesBuffer.size()))
+ return EC;
+
+ // Then the actual string data.
+ StringRef Data(NamesBuffer.data(), NamesBuffer.size());
+ if (auto EC = Writer.writeFixedString(Data))
+ return EC;
+
+ // And finally the Offset Index map.
+ if (auto EC = OffsetIndexMap.commit(Writer))
+ return EC;
+
+ return Error::success();
+}
+
+uint32_t NamedStreamMap::calculateSerializedLength() const {
+ return sizeof(uint32_t) // String data size
+ + NamesBuffer.size() // String data
+ + OffsetIndexMap.calculateSerializedLength(); // Offset Index Map
+}
+
+uint32_t NamedStreamMap::size() const { return OffsetIndexMap.size(); }
+
+StringRef NamedStreamMap::getString(uint32_t Offset) const {
+ assert(NamesBuffer.size() > Offset);
+ return StringRef(NamesBuffer.data() + Offset);
+}
+
+uint32_t NamedStreamMap::hashString(uint32_t Offset) const {
+ return hashStringV1(getString(Offset));
+}
+
+bool NamedStreamMap::get(StringRef Stream, uint32_t &StreamNo) const {
+ auto Iter = OffsetIndexMap.find_as(Stream, HashTraits);
+ if (Iter == OffsetIndexMap.end())
+ return false;
+ StreamNo = (*Iter).second;
+ return true;
+}
+
+StringMap<uint32_t> NamedStreamMap::entries() const {
+ StringMap<uint32_t> Result;
+ for (const auto &Entry : OffsetIndexMap) {
+ StringRef Stream(NamesBuffer.data() + Entry.first);
+ Result.try_emplace(Stream, Entry.second);
+ }
+ return Result;
+}
+
+uint32_t NamedStreamMap::appendStringData(StringRef S) {
+ uint32_t Offset = NamesBuffer.size();
+ llvm::append_range(NamesBuffer, S);
+ NamesBuffer.push_back('\0');
+ return Offset;
+}
+
+void NamedStreamMap::set(StringRef Stream, uint32_t StreamNo) {
+ OffsetIndexMap.set_as(Stream, support::ulittle32_t(StreamNo), HashTraits);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp
new file mode 100644
index 0000000000..7717f062ea
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeCompilandSymbol.cpp
@@ -0,0 +1,60 @@
+//===- NativeCompilandSymbol.cpp - Native impl for compilands ---*- 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/PDB/Native/NativeCompilandSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+
+#include "llvm/ADT/STLExtras.h"
+
+namespace llvm {
+namespace pdb {
+
+NativeCompilandSymbol::NativeCompilandSymbol(NativeSession &Session,
+ SymIndexId SymbolId,
+ DbiModuleDescriptor MI)
+ : NativeRawSymbol(Session, PDB_SymType::Compiland, SymbolId), Module(MI) {}
+
+PDB_SymType NativeCompilandSymbol::getSymTag() const {
+ return PDB_SymType::Compiland;
+}
+
+void NativeCompilandSymbol::dump(raw_ostream &OS, int Indent,
+ PdbSymbolIdField ShowIdFields,
+ PdbSymbolIdField RecurseIdFields) const {
+ NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
+
+ dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session,
+ PdbSymbolIdField::LexicalParent, ShowIdFields,
+ RecurseIdFields);
+ dumpSymbolField(OS, "libraryName", getLibraryName(), Indent);
+ dumpSymbolField(OS, "name", getName(), Indent);
+ dumpSymbolField(OS, "editAndContinueEnabled", isEditAndContinueEnabled(),
+ Indent);
+}
+
+bool NativeCompilandSymbol::isEditAndContinueEnabled() const {
+ return Module.hasECInfo();
+}
+
+SymIndexId NativeCompilandSymbol::getLexicalParentId() const { return 0; }
+
+// The usage of getObjFileName for getLibraryName and getModuleName for getName
+// may seem backwards, but it is consistent with DIA, which is what this API
+// was modeled after. We may rename these methods later to try to eliminate
+// this potential confusion.
+
+std::string NativeCompilandSymbol::getLibraryName() const {
+ return std::string(Module.getObjFileName());
+}
+
+std::string NativeCompilandSymbol::getName() const {
+ return std::string(Module.getModuleName());
+}
+
+} // namespace pdb
+} // namespace llvm
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumGlobals.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumGlobals.cpp
new file mode 100644
index 0000000000..54646867bc
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumGlobals.cpp
@@ -0,0 +1,54 @@
+//==- NativeEnumGlobals.cpp - Native Global Enumerator impl ------*- 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/PDB/Native/NativeEnumGlobals.h"
+
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+NativeEnumGlobals::NativeEnumGlobals(NativeSession &PDBSession,
+ std::vector<codeview::SymbolKind> Kinds)
+ : Index(0), Session(PDBSession) {
+ GlobalsStream &GS = cantFail(Session.getPDBFile().getPDBGlobalsStream());
+ SymbolStream &SS = cantFail(Session.getPDBFile().getPDBSymbolStream());
+ for (uint32_t Off : GS.getGlobalsTable()) {
+ CVSymbol S = SS.readRecord(Off);
+ if (!llvm::is_contained(Kinds, S.kind()))
+ continue;
+ MatchOffsets.push_back(Off);
+ }
+}
+
+uint32_t NativeEnumGlobals::getChildCount() const {
+ return static_cast<uint32_t>(MatchOffsets.size());
+}
+
+std::unique_ptr<PDBSymbol>
+NativeEnumGlobals::getChildAtIndex(uint32_t N) const {
+ if (N >= MatchOffsets.size())
+ return nullptr;
+
+ SymIndexId Id =
+ Session.getSymbolCache().getOrCreateGlobalSymbolByOffset(MatchOffsets[N]);
+ return Session.getSymbolCache().getSymbolById(Id);
+}
+
+std::unique_ptr<PDBSymbol> NativeEnumGlobals::getNext() {
+ return getChildAtIndex(Index++);
+}
+
+void NativeEnumGlobals::reset() { Index = 0; }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumInjectedSources.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumInjectedSources.cpp
new file mode 100644
index 0000000000..5e64122750
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumInjectedSources.cpp
@@ -0,0 +1,121 @@
+//==- NativeEnumInjectedSources.cpp - Native Injected Source Enumerator --*-==//
+//
+// 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/PDB/Native/NativeEnumInjectedSources.h"
+
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
+
+namespace llvm {
+namespace pdb {
+
+namespace {
+
+Expected<std::string> readStreamData(BinaryStream &Stream, uint64_t Limit) {
+ uint64_t Offset = 0, DataLength = std::min(Limit, Stream.getLength());
+ std::string Result;
+ Result.reserve(DataLength);
+ while (Offset < DataLength) {
+ ArrayRef<uint8_t> Data;
+ if (auto E = Stream.readLongestContiguousChunk(Offset, Data))
+ return std::move(E);
+ Data = Data.take_front(DataLength - Offset);
+ Offset += Data.size();
+ Result += toStringRef(Data);
+ }
+ return Result;
+}
+
+class NativeInjectedSource final : public IPDBInjectedSource {
+ const SrcHeaderBlockEntry &Entry;
+ const PDBStringTable &Strings;
+ PDBFile &File;
+
+public:
+ NativeInjectedSource(const SrcHeaderBlockEntry &Entry,
+ PDBFile &File, const PDBStringTable &Strings)
+ : Entry(Entry), Strings(Strings), File(File) {}
+
+ uint32_t getCrc32() const override { return Entry.CRC; }
+ uint64_t getCodeByteSize() const override { return Entry.FileSize; }
+
+ std::string getFileName() const override {
+ StringRef Ret = cantFail(Strings.getStringForID(Entry.FileNI),
+ "InjectedSourceStream should have rejected this");
+ return std::string(Ret);
+ }
+
+ std::string getObjectFileName() const override {
+ StringRef Ret = cantFail(Strings.getStringForID(Entry.ObjNI),
+ "InjectedSourceStream should have rejected this");
+ return std::string(Ret);
+ }
+
+ std::string getVirtualFileName() const override {
+ StringRef Ret = cantFail(Strings.getStringForID(Entry.VFileNI),
+ "InjectedSourceStream should have rejected this");
+ return std::string(Ret);
+ }
+
+ uint32_t getCompression() const override { return Entry.Compression; }
+
+ std::string getCode() const override {
+ // Get name of stream storing the data.
+ StringRef VName =
+ cantFail(Strings.getStringForID(Entry.VFileNI),
+ "InjectedSourceStream should have rejected this");
+ std::string StreamName = ("/src/files/" + VName).str();
+
+ // Find stream with that name and read its data.
+ // FIXME: Consider validating (or even loading) all this in
+ // InjectedSourceStream so that no error can happen here.
+ auto ExpectedFileStream = File.safelyCreateNamedStream(StreamName);
+ if (!ExpectedFileStream) {
+ consumeError(ExpectedFileStream.takeError());
+ return "(failed to open data stream)";
+ }
+
+ auto Data = readStreamData(**ExpectedFileStream, Entry.FileSize);
+ if (!Data) {
+ consumeError(Data.takeError());
+ return "(failed to read data)";
+ }
+ return *Data;
+ }
+};
+
+} // namespace
+
+NativeEnumInjectedSources::NativeEnumInjectedSources(
+ PDBFile &File, const InjectedSourceStream &IJS,
+ const PDBStringTable &Strings)
+ : File(File), Stream(IJS), Strings(Strings), Cur(Stream.begin()) {}
+
+uint32_t NativeEnumInjectedSources::getChildCount() const {
+ return static_cast<uint32_t>(Stream.size());
+}
+
+std::unique_ptr<IPDBInjectedSource>
+NativeEnumInjectedSources::getChildAtIndex(uint32_t N) const {
+ if (N >= getChildCount())
+ return nullptr;
+ return std::make_unique<NativeInjectedSource>(std::next(Stream.begin(), N)->second,
+ File, Strings);
+}
+
+std::unique_ptr<IPDBInjectedSource> NativeEnumInjectedSources::getNext() {
+ if (Cur == Stream.end())
+ return nullptr;
+ return std::make_unique<NativeInjectedSource>((Cur++)->second, File, Strings);
+}
+
+void NativeEnumInjectedSources::reset() { Cur = Stream.begin(); }
+
+}
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumLineNumbers.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumLineNumbers.cpp
new file mode 100644
index 0000000000..1e4b076463
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumLineNumbers.cpp
@@ -0,0 +1,42 @@
+//==- NativeEnumLineNumbers.cpp - Native Type Enumerator impl ----*- 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/PDB/Native/NativeEnumLineNumbers.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugSubsectionRecord.h"
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/Native/NativeLineNumber.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSourceFile.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+NativeEnumLineNumbers::NativeEnumLineNumbers(
+ std::vector<NativeLineNumber> LineNums)
+ : Lines(std::move(LineNums)), Index(0) {}
+
+uint32_t NativeEnumLineNumbers::getChildCount() const {
+ return static_cast<uint32_t>(Lines.size());
+}
+
+std::unique_ptr<IPDBLineNumber>
+NativeEnumLineNumbers::getChildAtIndex(uint32_t N) const {
+ if (N >= getChildCount())
+ return nullptr;
+ return std::make_unique<NativeLineNumber>(Lines[N]);
+}
+
+std::unique_ptr<IPDBLineNumber> NativeEnumLineNumbers::getNext() {
+ return getChildAtIndex(Index++);
+}
+
+void NativeEnumLineNumbers::reset() { Index = 0; }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp
new file mode 100644
index 0000000000..c6621924b5
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumModules.cpp
@@ -0,0 +1,43 @@
+//==- NativeEnumModules.cpp - Native Symbol Enumerator impl ------*- 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/PDB/Native/NativeEnumModules.h"
+
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+
+namespace llvm {
+namespace pdb {
+
+NativeEnumModules::NativeEnumModules(NativeSession &PDBSession, uint32_t Index)
+ : Session(PDBSession), Index(Index) {}
+
+uint32_t NativeEnumModules::getChildCount() const {
+ return Session.getSymbolCache().getNumCompilands();
+}
+
+std::unique_ptr<PDBSymbol>
+NativeEnumModules::getChildAtIndex(uint32_t N) const {
+ return Session.getSymbolCache().getOrCreateCompiland(N);
+}
+
+std::unique_ptr<PDBSymbol> NativeEnumModules::getNext() {
+ if (Index >= getChildCount())
+ return nullptr;
+ return getChildAtIndex(Index++);
+}
+
+void NativeEnumModules::reset() { Index = 0; }
+
+}
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumSymbols.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumSymbols.cpp
new file mode 100644
index 0000000000..feede1dbc9
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumSymbols.cpp
@@ -0,0 +1,41 @@
+//==- NativeEnumSymbols.cpp - Native Symbol Enumerator impl ------*- 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/PDB/Native/NativeEnumSymbols.h"
+
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+NativeEnumSymbols::NativeEnumSymbols(NativeSession &PDBSession,
+ std::vector<SymIndexId> Symbols)
+ : Symbols(std::move(Symbols)), Index(0), Session(PDBSession) {}
+
+uint32_t NativeEnumSymbols::getChildCount() const {
+ return static_cast<uint32_t>(Symbols.size());
+}
+
+std::unique_ptr<PDBSymbol>
+NativeEnumSymbols::getChildAtIndex(uint32_t N) const {
+ if (N < Symbols.size()) {
+ return Session.getSymbolCache().getSymbolById(Symbols[N]);
+ }
+ return nullptr;
+}
+
+std::unique_ptr<PDBSymbol> NativeEnumSymbols::getNext() {
+ return getChildAtIndex(Index++);
+}
+
+void NativeEnumSymbols::reset() { Index = 0; }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp
new file mode 100644
index 0000000000..2524e10cb6
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeEnumTypes.cpp
@@ -0,0 +1,70 @@
+//==- NativeEnumTypes.cpp - Native Type Enumerator impl ----------*- 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/PDB/Native/NativeEnumTypes.h"
+
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession,
+ LazyRandomTypeCollection &Types,
+ std::vector<codeview::TypeLeafKind> Kinds)
+ : Index(0), Session(PDBSession) {
+ Optional<TypeIndex> TI = Types.getFirst();
+ while (TI) {
+ CVType CVT = Types.getType(*TI);
+ TypeLeafKind K = CVT.kind();
+ if (llvm::is_contained(Kinds, K)) {
+ // Don't add forward refs, we'll find those later while enumerating.
+ if (!isUdtForwardRef(CVT))
+ Matches.push_back(*TI);
+ } else if (K == TypeLeafKind::LF_MODIFIER) {
+ TypeIndex ModifiedTI = getModifiedType(CVT);
+ if (!ModifiedTI.isSimple()) {
+ CVType UnmodifiedCVT = Types.getType(ModifiedTI);
+ // LF_MODIFIERs point to forward refs, but don't worry about that
+ // here. We're pushing the TypeIndex of the LF_MODIFIER itself,
+ // so we'll worry about resolving forward refs later.
+ if (llvm::is_contained(Kinds, UnmodifiedCVT.kind()))
+ Matches.push_back(*TI);
+ }
+ }
+ TI = Types.getNext(*TI);
+ }
+}
+
+NativeEnumTypes::NativeEnumTypes(NativeSession &PDBSession,
+ std::vector<codeview::TypeIndex> Indices)
+ : Matches(std::move(Indices)), Index(0), Session(PDBSession) {}
+
+uint32_t NativeEnumTypes::getChildCount() const {
+ return static_cast<uint32_t>(Matches.size());
+}
+
+std::unique_ptr<PDBSymbol> NativeEnumTypes::getChildAtIndex(uint32_t N) const {
+ if (N < Matches.size()) {
+ SymIndexId Id = Session.getSymbolCache().findSymbolByTypeIndex(Matches[N]);
+ return Session.getSymbolCache().getSymbolById(Id);
+ }
+ return nullptr;
+}
+
+std::unique_ptr<PDBSymbol> NativeEnumTypes::getNext() {
+ return getChildAtIndex(Index++);
+}
+
+void NativeEnumTypes::reset() { Index = 0; }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp
new file mode 100644
index 0000000000..895f894315
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeExeSymbol.cpp
@@ -0,0 +1,101 @@
+//===- NativeExeSymbol.cpp - native impl for PDBSymbolExe -------*- 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/PDB/Native/NativeExeSymbol.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumModules.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolCache.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+static DbiStream *getDbiStreamPtr(NativeSession &Session) {
+ Expected<DbiStream &> DbiS = Session.getPDBFile().getPDBDbiStream();
+ if (DbiS)
+ return &DbiS.get();
+
+ consumeError(DbiS.takeError());
+ return nullptr;
+}
+
+NativeExeSymbol::NativeExeSymbol(NativeSession &Session, SymIndexId SymbolId)
+ : NativeRawSymbol(Session, PDB_SymType::Exe, SymbolId),
+ Dbi(getDbiStreamPtr(Session)) {}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeExeSymbol::findChildren(PDB_SymType Type) const {
+ switch (Type) {
+ case PDB_SymType::Compiland: {
+ return std::unique_ptr<IPDBEnumSymbols>(new NativeEnumModules(Session));
+ break;
+ }
+ case PDB_SymType::ArrayType:
+ return Session.getSymbolCache().createTypeEnumerator(codeview::LF_ARRAY);
+ case PDB_SymType::Enum:
+ return Session.getSymbolCache().createTypeEnumerator(codeview::LF_ENUM);
+ case PDB_SymType::PointerType:
+ return Session.getSymbolCache().createTypeEnumerator(codeview::LF_POINTER);
+ case PDB_SymType::UDT:
+ return Session.getSymbolCache().createTypeEnumerator(
+ {codeview::LF_STRUCTURE, codeview::LF_CLASS, codeview::LF_UNION,
+ codeview::LF_INTERFACE});
+ case PDB_SymType::VTableShape:
+ return Session.getSymbolCache().createTypeEnumerator(codeview::LF_VTSHAPE);
+ case PDB_SymType::FunctionSig:
+ return Session.getSymbolCache().createTypeEnumerator(
+ {codeview::LF_PROCEDURE, codeview::LF_MFUNCTION});
+ case PDB_SymType::Typedef:
+ return Session.getSymbolCache().createGlobalsEnumerator(codeview::S_UDT);
+
+ default:
+ break;
+ }
+ return nullptr;
+}
+
+uint32_t NativeExeSymbol::getAge() const {
+ auto IS = Session.getPDBFile().getPDBInfoStream();
+ if (IS)
+ return IS->getAge();
+ consumeError(IS.takeError());
+ return 0;
+}
+
+std::string NativeExeSymbol::getSymbolsFileName() const {
+ return std::string(Session.getPDBFile().getFilePath());
+}
+
+codeview::GUID NativeExeSymbol::getGuid() const {
+ auto IS = Session.getPDBFile().getPDBInfoStream();
+ if (IS)
+ return IS->getGuid();
+ consumeError(IS.takeError());
+ return codeview::GUID{{0}};
+}
+
+bool NativeExeSymbol::hasCTypes() const {
+ auto Dbi = Session.getPDBFile().getPDBDbiStream();
+ if (Dbi)
+ return Dbi->hasCTypes();
+ consumeError(Dbi.takeError());
+ return false;
+}
+
+bool NativeExeSymbol::hasPrivateSymbols() const {
+ auto Dbi = Session.getPDBFile().getPDBDbiStream();
+ if (Dbi)
+ return !Dbi->isStripped();
+ consumeError(Dbi.takeError());
+ return false;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeFunctionSymbol.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeFunctionSymbol.cpp
new file mode 100644
index 0000000000..7f3b35c297
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeFunctionSymbol.cpp
@@ -0,0 +1,143 @@
+//===- NativeFunctionSymbol.cpp - info about function symbols----*- 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/PDB/Native/NativeFunctionSymbol.h"
+
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbols.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+NativeFunctionSymbol::NativeFunctionSymbol(NativeSession &Session,
+ SymIndexId Id,
+ const codeview::ProcSym &Sym,
+ uint32_t Offset)
+ : NativeRawSymbol(Session, PDB_SymType::Function, Id), Sym(Sym),
+ RecordOffset(Offset) {}
+
+NativeFunctionSymbol::~NativeFunctionSymbol() {}
+
+void NativeFunctionSymbol::dump(raw_ostream &OS, int Indent,
+ PdbSymbolIdField ShowIdFields,
+ PdbSymbolIdField RecurseIdFields) const {
+ NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
+ dumpSymbolField(OS, "name", getName(), Indent);
+ dumpSymbolField(OS, "length", getLength(), Indent);
+ dumpSymbolField(OS, "offset", getAddressOffset(), Indent);
+ dumpSymbolField(OS, "section", getAddressSection(), Indent);
+}
+
+uint32_t NativeFunctionSymbol::getAddressOffset() const {
+ return Sym.CodeOffset;
+}
+
+uint32_t NativeFunctionSymbol::getAddressSection() const { return Sym.Segment; }
+std::string NativeFunctionSymbol::getName() const {
+ return std::string(Sym.Name);
+}
+
+uint64_t NativeFunctionSymbol::getLength() const { return Sym.CodeSize; }
+
+uint32_t NativeFunctionSymbol::getRelativeVirtualAddress() const {
+ return Session.getRVAFromSectOffset(Sym.Segment, Sym.CodeOffset);
+}
+
+uint64_t NativeFunctionSymbol::getVirtualAddress() const {
+ return Session.getVAFromSectOffset(Sym.Segment, Sym.CodeOffset);
+}
+
+static bool inlineSiteContainsAddress(InlineSiteSym &IS,
+ uint32_t OffsetInFunc) {
+ // Returns true if inline site contains the offset.
+ bool Found = false;
+ uint32_t CodeOffset = 0;
+ for (auto &Annot : IS.annotations()) {
+ switch (Annot.OpCode) {
+ case BinaryAnnotationsOpCode::CodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:
+ CodeOffset += Annot.U1;
+ if (OffsetInFunc >= CodeOffset)
+ Found = true;
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeLength:
+ CodeOffset += Annot.U1;
+ if (Found && OffsetInFunc < CodeOffset)
+ return true;
+ Found = false;
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:
+ CodeOffset += Annot.U2;
+ if (OffsetInFunc >= CodeOffset && OffsetInFunc < CodeOffset + Annot.U1)
+ return true;
+ Found = false;
+ break;
+ default:
+ break;
+ }
+ }
+ return false;
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeFunctionSymbol::findInlineFramesByVA(uint64_t VA) const {
+ uint16_t Modi;
+ if (!Session.moduleIndexForVA(VA, Modi))
+ return nullptr;
+
+ Expected<ModuleDebugStreamRef> ModS = Session.getModuleDebugStream(Modi);
+ if (!ModS) {
+ consumeError(ModS.takeError());
+ return nullptr;
+ }
+ CVSymbolArray Syms = ModS->getSymbolArray();
+
+ // Search for inline sites. There should be one matching top level inline
+ // site. Then search in its nested inline sites.
+ std::vector<SymIndexId> Frames;
+ uint32_t CodeOffset = VA - getVirtualAddress();
+ auto Start = Syms.at(RecordOffset);
+ auto End = Syms.at(Sym.End);
+ while (Start != End) {
+ bool Found = false;
+ // Find matching inline site within Start and End.
+ for (; Start != End; ++Start) {
+ if (Start->kind() != S_INLINESITE)
+ continue;
+
+ InlineSiteSym IS =
+ cantFail(SymbolDeserializer::deserializeAs<InlineSiteSym>(*Start));
+ if (inlineSiteContainsAddress(IS, CodeOffset)) {
+ // Insert frames in reverse order.
+ SymIndexId Id = Session.getSymbolCache().getOrCreateInlineSymbol(
+ IS, getVirtualAddress(), Modi, Start.offset());
+ Frames.insert(Frames.begin(), Id);
+
+ // Update offsets to search within this inline site.
+ ++Start;
+ End = Syms.at(IS.End);
+ Found = true;
+ break;
+ }
+
+ Start = Syms.at(IS.End);
+ if (Start == End)
+ break;
+ }
+
+ if (!Found)
+ break;
+ }
+
+ return std::make_unique<NativeEnumSymbols>(Session, std::move(Frames));
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeInlineSiteSymbol.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeInlineSiteSymbol.cpp
new file mode 100644
index 0000000000..8314353c38
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeInlineSiteSymbol.cpp
@@ -0,0 +1,177 @@
+//===- NativeInlineSiteSymbol.cpp - info about inline sites -----*- 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/PDB/Native/NativeInlineSiteSymbol.h"
+
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumLineNumbers.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+NativeInlineSiteSymbol::NativeInlineSiteSymbol(
+ NativeSession &Session, SymIndexId Id, const codeview::InlineSiteSym &Sym,
+ uint64_t ParentAddr)
+ : NativeRawSymbol(Session, PDB_SymType::InlineSite, Id), Sym(Sym),
+ ParentAddr(ParentAddr) {}
+
+NativeInlineSiteSymbol::~NativeInlineSiteSymbol() {}
+
+void NativeInlineSiteSymbol::dump(raw_ostream &OS, int Indent,
+ PdbSymbolIdField ShowIdFields,
+ PdbSymbolIdField RecurseIdFields) const {
+ NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
+ dumpSymbolField(OS, "name", getName(), Indent);
+}
+
+static Optional<InlineeSourceLine>
+findInlineeByTypeIndex(TypeIndex Id, ModuleDebugStreamRef &ModS) {
+ for (const auto &SS : ModS.getSubsectionsArray()) {
+ if (SS.kind() != DebugSubsectionKind::InlineeLines)
+ continue;
+
+ DebugInlineeLinesSubsectionRef InlineeLines;
+ BinaryStreamReader Reader(SS.getRecordData());
+ if (auto EC = InlineeLines.initialize(Reader)) {
+ consumeError(std::move(EC));
+ continue;
+ }
+
+ for (const InlineeSourceLine &Line : InlineeLines)
+ if (Line.Header->Inlinee == Id)
+ return Line;
+ }
+ return None;
+}
+
+std::string NativeInlineSiteSymbol::getName() const {
+ auto Tpi = Session.getPDBFile().getPDBTpiStream();
+ if (!Tpi) {
+ consumeError(Tpi.takeError());
+ return "";
+ }
+ auto Ipi = Session.getPDBFile().getPDBIpiStream();
+ if (!Ipi) {
+ consumeError(Ipi.takeError());
+ return "";
+ }
+
+ LazyRandomTypeCollection &Types = Tpi->typeCollection();
+ LazyRandomTypeCollection &Ids = Ipi->typeCollection();
+ CVType InlineeType = Ids.getType(Sym.Inlinee);
+ std::string QualifiedName;
+ if (InlineeType.kind() == LF_MFUNC_ID) {
+ MemberFuncIdRecord MFRecord;
+ cantFail(TypeDeserializer::deserializeAs<MemberFuncIdRecord>(InlineeType,
+ MFRecord));
+ TypeIndex ClassTy = MFRecord.getClassType();
+ QualifiedName.append(std::string(Types.getTypeName(ClassTy)));
+ QualifiedName.append("::");
+ } else if (InlineeType.kind() == LF_FUNC_ID) {
+ FuncIdRecord FRecord;
+ cantFail(
+ TypeDeserializer::deserializeAs<FuncIdRecord>(InlineeType, FRecord));
+ TypeIndex ParentScope = FRecord.getParentScope();
+ if (!ParentScope.isNoneType()) {
+ QualifiedName.append(std::string(Ids.getTypeName(ParentScope)));
+ QualifiedName.append("::");
+ }
+ }
+
+ QualifiedName.append(std::string(Ids.getTypeName(Sym.Inlinee)));
+ return QualifiedName;
+}
+
+void NativeInlineSiteSymbol::getLineOffset(uint32_t OffsetInFunc,
+ uint32_t &LineOffset,
+ uint32_t &FileOffset) const {
+ LineOffset = 0;
+ FileOffset = 0;
+ uint32_t CodeOffset = 0;
+ for (const auto &Annot : Sym.annotations()) {
+ switch (Annot.OpCode) {
+ case BinaryAnnotationsOpCode::CodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeLength:
+ CodeOffset += Annot.U1;
+ break;
+ case BinaryAnnotationsOpCode::ChangeCodeLengthAndCodeOffset:
+ CodeOffset += Annot.U2;
+ break;
+ case BinaryAnnotationsOpCode::ChangeLineOffset:
+ case BinaryAnnotationsOpCode::ChangeCodeOffsetAndLineOffset:
+ CodeOffset += Annot.U1;
+ LineOffset += Annot.S1;
+ break;
+ case BinaryAnnotationsOpCode::ChangeFile:
+ FileOffset = Annot.U1;
+ break;
+ default:
+ break;
+ }
+
+ if (CodeOffset >= OffsetInFunc)
+ return;
+ }
+}
+
+std::unique_ptr<IPDBEnumLineNumbers>
+NativeInlineSiteSymbol::findInlineeLinesByVA(uint64_t VA,
+ uint32_t Length) const {
+ uint16_t Modi;
+ if (!Session.moduleIndexForVA(VA, Modi))
+ return nullptr;
+
+ Expected<ModuleDebugStreamRef> ModS = Session.getModuleDebugStream(Modi);
+ if (!ModS) {
+ consumeError(ModS.takeError());
+ return nullptr;
+ }
+
+ Expected<DebugChecksumsSubsectionRef> Checksums =
+ ModS->findChecksumsSubsection();
+ if (!Checksums) {
+ consumeError(Checksums.takeError());
+ return nullptr;
+ }
+
+ // Get the line number offset and source file offset.
+ uint32_t SrcLineOffset;
+ uint32_t SrcFileOffset;
+ getLineOffset(VA - ParentAddr, SrcLineOffset, SrcFileOffset);
+
+ // Get line info from inlinee line table.
+ Optional<InlineeSourceLine> Inlinee =
+ findInlineeByTypeIndex(Sym.Inlinee, ModS.get());
+
+ if (!Inlinee)
+ return nullptr;
+
+ uint32_t SrcLine = Inlinee->Header->SourceLineNum + SrcLineOffset;
+ uint32_t SrcCol = 0; // Inline sites don't seem to have column info.
+ uint32_t FileChecksumOffset =
+ (SrcFileOffset == 0) ? Inlinee->Header->FileID : SrcFileOffset;
+
+ auto ChecksumIter = Checksums->getArray().at(FileChecksumOffset);
+ uint32_t SrcFileId =
+ Session.getSymbolCache().getOrCreateSourceFile(*ChecksumIter);
+
+ uint32_t LineSect, LineOff;
+ Session.addressForVA(VA, LineSect, LineOff);
+ NativeLineNumber LineNum(Session, SrcLine, SrcCol, LineSect, LineOff, Length,
+ SrcFileId, Modi);
+ auto SrcFile = Session.getSymbolCache().getSourceFileById(SrcFileId);
+ std::vector<NativeLineNumber> Lines{LineNum};
+
+ return std::make_unique<NativeEnumLineNumbers>(std::move(Lines));
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeLineNumber.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeLineNumber.cpp
new file mode 100644
index 0000000000..155ed0cdb8
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeLineNumber.cpp
@@ -0,0 +1,51 @@
+//===- NativeLineNumber.cpp - Native line number implementation -*- 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/PDB/Native/NativeLineNumber.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+NativeLineNumber::NativeLineNumber(const NativeSession &Session,
+ const codeview::LineInfo Line,
+ uint32_t ColumnNumber, uint32_t Section,
+ uint32_t Offset, uint32_t Length,
+ uint32_t SrcFileId, uint32_t CompilandId)
+ : Session(Session), Line(Line), ColumnNumber(ColumnNumber),
+ Section(Section), Offset(Offset), Length(Length), SrcFileId(SrcFileId),
+ CompilandId(CompilandId) {}
+
+uint32_t NativeLineNumber::getLineNumber() const { return Line.getStartLine(); }
+
+uint32_t NativeLineNumber::getLineNumberEnd() const {
+ return Line.getEndLine();
+}
+
+uint32_t NativeLineNumber::getColumnNumber() const { return ColumnNumber; }
+
+uint32_t NativeLineNumber::getColumnNumberEnd() const { return 0; }
+
+uint32_t NativeLineNumber::getAddressSection() const { return Section; }
+
+uint32_t NativeLineNumber::getAddressOffset() const { return Offset; }
+
+uint32_t NativeLineNumber::getRelativeVirtualAddress() const {
+ return Session.getRVAFromSectOffset(Section, Offset);
+}
+
+uint64_t NativeLineNumber::getVirtualAddress() const {
+ return Session.getVAFromSectOffset(Section, Offset);
+}
+
+uint32_t NativeLineNumber::getLength() const { return Length; }
+
+uint32_t NativeLineNumber::getSourceFileId() const { return SrcFileId; }
+
+uint32_t NativeLineNumber::getCompilandId() const { return CompilandId; }
+
+bool NativeLineNumber::isStatement() const { return Line.isStatement(); }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativePublicSymbol.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativePublicSymbol.cpp
new file mode 100644
index 0000000000..1265e688b8
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativePublicSymbol.cpp
@@ -0,0 +1,48 @@
+//===- NativePublicSymbol.cpp - info about public symbols -------*- 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/PDB/Native/NativePublicSymbol.h"
+
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+NativePublicSymbol::NativePublicSymbol(NativeSession &Session, SymIndexId Id,
+ const codeview::PublicSym32 &Sym)
+ : NativeRawSymbol(Session, PDB_SymType::PublicSymbol, Id), Sym(Sym) {}
+
+NativePublicSymbol::~NativePublicSymbol() {}
+
+void NativePublicSymbol::dump(raw_ostream &OS, int Indent,
+ PdbSymbolIdField ShowIdFields,
+ PdbSymbolIdField RecurseIdFields) const {
+ NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
+ dumpSymbolField(OS, "name", getName(), Indent);
+ dumpSymbolField(OS, "offset", getAddressOffset(), Indent);
+ dumpSymbolField(OS, "section", getAddressSection(), Indent);
+}
+
+uint32_t NativePublicSymbol::getAddressOffset() const { return Sym.Offset; }
+
+uint32_t NativePublicSymbol::getAddressSection() const { return Sym.Segment; }
+
+std::string NativePublicSymbol::getName() const {
+ return std::string(Sym.Name);
+}
+
+uint32_t NativePublicSymbol::getRelativeVirtualAddress() const {
+ return Session.getRVAFromSectOffset(Sym.Segment, Sym.Offset);
+}
+
+uint64_t NativePublicSymbol::getVirtualAddress() const {
+ return Session.getVAFromSectOffset(Sym.Segment, Sym.Offset);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp
new file mode 100644
index 0000000000..2ad552470b
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeRawSymbol.cpp
@@ -0,0 +1,734 @@
+//===- NativeRawSymbol.cpp - Native implementation of IPDBRawSymbol -------===//
+//
+// 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/PDB/Native/NativeRawSymbol.h"
+#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+NativeRawSymbol::NativeRawSymbol(NativeSession &PDBSession, PDB_SymType Tag,
+ SymIndexId SymbolId)
+ : Session(PDBSession), Tag(Tag), SymbolId(SymbolId) {}
+
+void NativeRawSymbol::dump(raw_ostream &OS, int Indent,
+ PdbSymbolIdField ShowIdFields,
+ PdbSymbolIdField RecurseIdFields) const {
+ dumpSymbolIdField(OS, "symIndexId", SymbolId, Indent, Session,
+ PdbSymbolIdField::SymIndexId, ShowIdFields,
+ RecurseIdFields);
+ dumpSymbolField(OS, "symTag", Tag, Indent);
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeRawSymbol::findChildren(PDB_SymType Type) const {
+ return std::make_unique<NullEnumerator<PDBSymbol>>();
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeRawSymbol::findChildren(PDB_SymType Type, StringRef Name,
+ PDB_NameSearchFlags Flags) const {
+ return std::make_unique<NullEnumerator<PDBSymbol>>();
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeRawSymbol::findChildrenByAddr(PDB_SymType Type, StringRef Name,
+ PDB_NameSearchFlags Flags, uint32_t Section, uint32_t Offset) const {
+ return std::make_unique<NullEnumerator<PDBSymbol>>();
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeRawSymbol::findChildrenByVA(PDB_SymType Type, StringRef Name,
+ PDB_NameSearchFlags Flags, uint64_t VA) const {
+ return std::make_unique<NullEnumerator<PDBSymbol>>();
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeRawSymbol::findChildrenByRVA(PDB_SymType Type, StringRef Name,
+ PDB_NameSearchFlags Flags, uint32_t RVA) const {
+ return std::make_unique<NullEnumerator<PDBSymbol>>();
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeRawSymbol::findInlineFramesByAddr(uint32_t Section,
+ uint32_t Offset) const {
+ return std::make_unique<NullEnumerator<PDBSymbol>>();
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeRawSymbol::findInlineFramesByRVA(uint32_t RVA) const {
+ return std::make_unique<NullEnumerator<PDBSymbol>>();
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeRawSymbol::findInlineFramesByVA(uint64_t VA) const {
+ return std::make_unique<NullEnumerator<PDBSymbol>>();
+}
+
+std::unique_ptr<IPDBEnumLineNumbers>
+NativeRawSymbol::findInlineeLines() const {
+ return std::make_unique<NullEnumerator<IPDBLineNumber>>();
+}
+
+std::unique_ptr<IPDBEnumLineNumbers>
+NativeRawSymbol::findInlineeLinesByAddr(uint32_t Section, uint32_t Offset,
+ uint32_t Length) const {
+ return std::make_unique<NullEnumerator<IPDBLineNumber>>();
+}
+
+std::unique_ptr<IPDBEnumLineNumbers>
+NativeRawSymbol::findInlineeLinesByRVA(uint32_t RVA, uint32_t Length) const {
+ return std::make_unique<NullEnumerator<IPDBLineNumber>>();
+}
+
+std::unique_ptr<IPDBEnumLineNumbers>
+NativeRawSymbol::findInlineeLinesByVA(uint64_t VA, uint32_t Length) const {
+ return std::make_unique<NullEnumerator<IPDBLineNumber>>();
+}
+
+void NativeRawSymbol::getDataBytes(SmallVector<uint8_t, 32> &bytes) const {
+ bytes.clear();
+}
+
+PDB_MemberAccess NativeRawSymbol::getAccess() const {
+ return PDB_MemberAccess::Private;
+}
+
+uint32_t NativeRawSymbol::getAddressOffset() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getAddressSection() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getAge() const {
+ return 0;
+}
+
+SymIndexId NativeRawSymbol::getArrayIndexTypeId() const { return 0; }
+
+void NativeRawSymbol::getBackEndVersion(VersionInfo &Version) const {
+ Version.Major = 0;
+ Version.Minor = 0;
+ Version.Build = 0;
+ Version.QFE = 0;
+}
+
+uint32_t NativeRawSymbol::getBaseDataOffset() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getBaseDataSlot() const {
+ return 0;
+}
+
+SymIndexId NativeRawSymbol::getBaseSymbolId() const { return 0; }
+
+PDB_BuiltinType NativeRawSymbol::getBuiltinType() const {
+ return PDB_BuiltinType::None;
+}
+
+uint32_t NativeRawSymbol::getBitPosition() const {
+ return 0;
+}
+
+PDB_CallingConv NativeRawSymbol::getCallingConvention() const {
+ return PDB_CallingConv::FarStdCall;
+}
+
+SymIndexId NativeRawSymbol::getClassParentId() const { return 0; }
+
+std::string NativeRawSymbol::getCompilerName() const {
+ return {};
+}
+
+uint32_t NativeRawSymbol::getCount() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getCountLiveRanges() const {
+ return 0;
+}
+
+void NativeRawSymbol::getFrontEndVersion(VersionInfo &Version) const {
+ Version.Major = 0;
+ Version.Minor = 0;
+ Version.Build = 0;
+ Version.QFE = 0;
+}
+
+PDB_Lang NativeRawSymbol::getLanguage() const {
+ return PDB_Lang::Cobol;
+}
+
+SymIndexId NativeRawSymbol::getLexicalParentId() const { return 0; }
+
+std::string NativeRawSymbol::getLibraryName() const {
+ return {};
+}
+
+uint32_t NativeRawSymbol::getLiveRangeStartAddressOffset() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getLiveRangeStartAddressSection() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getLiveRangeStartRelativeVirtualAddress() const {
+ return 0;
+}
+
+codeview::RegisterId NativeRawSymbol::getLocalBasePointerRegisterId() const {
+ return codeview::RegisterId::EAX;
+}
+
+SymIndexId NativeRawSymbol::getLowerBoundId() const { return 0; }
+
+uint32_t NativeRawSymbol::getMemorySpaceKind() const {
+ return 0;
+}
+
+std::string NativeRawSymbol::getName() const {
+ return {};
+}
+
+uint32_t NativeRawSymbol::getNumberOfAcceleratorPointerTags() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getNumberOfColumns() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getNumberOfModifiers() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getNumberOfRegisterIndices() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getNumberOfRows() const {
+ return 0;
+}
+
+std::string NativeRawSymbol::getObjectFileName() const {
+ return {};
+}
+
+uint32_t NativeRawSymbol::getOemId() const {
+ return 0;
+}
+
+SymIndexId NativeRawSymbol::getOemSymbolId() const { return 0; }
+
+uint32_t NativeRawSymbol::getOffsetInUdt() const {
+ return 0;
+}
+
+PDB_Cpu NativeRawSymbol::getPlatform() const {
+ return PDB_Cpu::Intel8080;
+}
+
+uint32_t NativeRawSymbol::getRank() const {
+ return 0;
+}
+
+codeview::RegisterId NativeRawSymbol::getRegisterId() const {
+ return codeview::RegisterId::EAX;
+}
+
+uint32_t NativeRawSymbol::getRegisterType() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getRelativeVirtualAddress() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getSamplerSlot() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getSignature() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getSizeInUdt() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getSlot() const {
+ return 0;
+}
+
+std::string NativeRawSymbol::getSourceFileName() const {
+ return {};
+}
+
+std::unique_ptr<IPDBLineNumber>
+NativeRawSymbol::getSrcLineOnTypeDefn() const {
+ return nullptr;
+}
+
+uint32_t NativeRawSymbol::getStride() const {
+ return 0;
+}
+
+SymIndexId NativeRawSymbol::getSubTypeId() const { return 0; }
+
+std::string NativeRawSymbol::getSymbolsFileName() const { return {}; }
+
+SymIndexId NativeRawSymbol::getSymIndexId() const { return SymbolId; }
+
+uint32_t NativeRawSymbol::getTargetOffset() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getTargetRelativeVirtualAddress() const {
+ return 0;
+}
+
+uint64_t NativeRawSymbol::getTargetVirtualAddress() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getTargetSection() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getTextureSlot() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getTimeStamp() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getToken() const {
+ return 0;
+}
+
+SymIndexId NativeRawSymbol::getTypeId() const { return 0; }
+
+uint32_t NativeRawSymbol::getUavSlot() const {
+ return 0;
+}
+
+std::string NativeRawSymbol::getUndecoratedName() const {
+ return {};
+}
+
+std::string NativeRawSymbol::getUndecoratedNameEx(
+ PDB_UndnameFlags Flags) const {
+ return {};
+}
+
+SymIndexId NativeRawSymbol::getUnmodifiedTypeId() const { return 0; }
+
+SymIndexId NativeRawSymbol::getUpperBoundId() const { return 0; }
+
+Variant NativeRawSymbol::getValue() const {
+ return Variant();
+}
+
+uint32_t NativeRawSymbol::getVirtualBaseDispIndex() const {
+ return 0;
+}
+
+uint32_t NativeRawSymbol::getVirtualBaseOffset() const {
+ return 0;
+}
+
+SymIndexId NativeRawSymbol::getVirtualTableShapeId() const { return 0; }
+
+std::unique_ptr<PDBSymbolTypeBuiltin>
+NativeRawSymbol::getVirtualBaseTableType() const {
+ return nullptr;
+}
+
+PDB_DataKind NativeRawSymbol::getDataKind() const {
+ return PDB_DataKind::Unknown;
+}
+
+PDB_SymType NativeRawSymbol::getSymTag() const { return Tag; }
+
+codeview::GUID NativeRawSymbol::getGuid() const { return codeview::GUID{{0}}; }
+
+int32_t NativeRawSymbol::getOffset() const {
+ return 0;
+}
+
+int32_t NativeRawSymbol::getThisAdjust() const {
+ return 0;
+}
+
+int32_t NativeRawSymbol::getVirtualBasePointerOffset() const {
+ return 0;
+}
+
+PDB_LocType NativeRawSymbol::getLocationType() const {
+ return PDB_LocType::Null;
+}
+
+PDB_Machine NativeRawSymbol::getMachineType() const {
+ return PDB_Machine::Invalid;
+}
+
+codeview::ThunkOrdinal NativeRawSymbol::getThunkOrdinal() const {
+ return codeview::ThunkOrdinal::Standard;
+}
+
+uint64_t NativeRawSymbol::getLength() const {
+ return 0;
+}
+
+uint64_t NativeRawSymbol::getLiveRangeLength() const {
+ return 0;
+}
+
+uint64_t NativeRawSymbol::getVirtualAddress() const {
+ return 0;
+}
+
+PDB_UdtType NativeRawSymbol::getUdtKind() const {
+ return PDB_UdtType::Struct;
+}
+
+bool NativeRawSymbol::hasConstructor() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasCustomCallingConvention() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasFarReturn() const {
+ return false;
+}
+
+bool NativeRawSymbol::isCode() const {
+ return false;
+}
+
+bool NativeRawSymbol::isCompilerGenerated() const {
+ return false;
+}
+
+bool NativeRawSymbol::isConstType() const {
+ return false;
+}
+
+bool NativeRawSymbol::isEditAndContinueEnabled() const {
+ return false;
+}
+
+bool NativeRawSymbol::isFunction() const {
+ return false;
+}
+
+bool NativeRawSymbol::getAddressTaken() const {
+ return false;
+}
+
+bool NativeRawSymbol::getNoStackOrdering() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasAlloca() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasAssignmentOperator() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasCTypes() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasCastOperator() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasDebugInfo() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasEH() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasEHa() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasInlAsm() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasInlineAttribute() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasInterruptReturn() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasFramePointer() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasLongJump() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasManagedCode() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasNestedTypes() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasNoInlineAttribute() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasNoReturnAttribute() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasOptimizedCodeDebugInfo() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasOverloadedOperator() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasSEH() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasSecurityChecks() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasSetJump() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasStrictGSCheck() const {
+ return false;
+}
+
+bool NativeRawSymbol::isAcceleratorGroupSharedLocal() const {
+ return false;
+}
+
+bool NativeRawSymbol::isAcceleratorPointerTagLiveRange() const {
+ return false;
+}
+
+bool NativeRawSymbol::isAcceleratorStubFunction() const {
+ return false;
+}
+
+bool NativeRawSymbol::isAggregated() const {
+ return false;
+}
+
+bool NativeRawSymbol::isIntroVirtualFunction() const {
+ return false;
+}
+
+bool NativeRawSymbol::isCVTCIL() const {
+ return false;
+}
+
+bool NativeRawSymbol::isConstructorVirtualBase() const {
+ return false;
+}
+
+bool NativeRawSymbol::isCxxReturnUdt() const {
+ return false;
+}
+
+bool NativeRawSymbol::isDataAligned() const {
+ return false;
+}
+
+bool NativeRawSymbol::isHLSLData() const {
+ return false;
+}
+
+bool NativeRawSymbol::isHotpatchable() const {
+ return false;
+}
+
+bool NativeRawSymbol::isIndirectVirtualBaseClass() const {
+ return false;
+}
+
+bool NativeRawSymbol::isInterfaceUdt() const {
+ return false;
+}
+
+bool NativeRawSymbol::isIntrinsic() const {
+ return false;
+}
+
+bool NativeRawSymbol::isLTCG() const {
+ return false;
+}
+
+bool NativeRawSymbol::isLocationControlFlowDependent() const {
+ return false;
+}
+
+bool NativeRawSymbol::isMSILNetmodule() const {
+ return false;
+}
+
+bool NativeRawSymbol::isMatrixRowMajor() const {
+ return false;
+}
+
+bool NativeRawSymbol::isManagedCode() const {
+ return false;
+}
+
+bool NativeRawSymbol::isMSILCode() const {
+ return false;
+}
+
+bool NativeRawSymbol::isMultipleInheritance() const {
+ return false;
+}
+
+bool NativeRawSymbol::isNaked() const {
+ return false;
+}
+
+bool NativeRawSymbol::isNested() const {
+ return false;
+}
+
+bool NativeRawSymbol::isOptimizedAway() const {
+ return false;
+}
+
+bool NativeRawSymbol::isPacked() const {
+ return false;
+}
+
+bool NativeRawSymbol::isPointerBasedOnSymbolValue() const {
+ return false;
+}
+
+bool NativeRawSymbol::isPointerToDataMember() const {
+ return false;
+}
+
+bool NativeRawSymbol::isPointerToMemberFunction() const {
+ return false;
+}
+
+bool NativeRawSymbol::isPureVirtual() const {
+ return false;
+}
+
+bool NativeRawSymbol::isRValueReference() const {
+ return false;
+}
+
+bool NativeRawSymbol::isRefUdt() const {
+ return false;
+}
+
+bool NativeRawSymbol::isReference() const {
+ return false;
+}
+
+bool NativeRawSymbol::isRestrictedType() const {
+ return false;
+}
+
+bool NativeRawSymbol::isReturnValue() const {
+ return false;
+}
+
+bool NativeRawSymbol::isSafeBuffers() const {
+ return false;
+}
+
+bool NativeRawSymbol::isScoped() const {
+ return false;
+}
+
+bool NativeRawSymbol::isSdl() const {
+ return false;
+}
+
+bool NativeRawSymbol::isSingleInheritance() const {
+ return false;
+}
+
+bool NativeRawSymbol::isSplitted() const {
+ return false;
+}
+
+bool NativeRawSymbol::isStatic() const {
+ return false;
+}
+
+bool NativeRawSymbol::hasPrivateSymbols() const {
+ return false;
+}
+
+bool NativeRawSymbol::isUnalignedType() const {
+ return false;
+}
+
+bool NativeRawSymbol::isUnreached() const {
+ return false;
+}
+
+bool NativeRawSymbol::isValueUdt() const {
+ return false;
+}
+
+bool NativeRawSymbol::isVirtual() const {
+ return false;
+}
+
+bool NativeRawSymbol::isVirtualBaseClass() const {
+ return false;
+}
+
+bool NativeRawSymbol::isVirtualInheritance() const {
+ return false;
+}
+
+bool NativeRawSymbol::isVolatileType() const {
+ return false;
+}
+
+bool NativeRawSymbol::wasInlined() const {
+ return false;
+}
+
+std::string NativeRawSymbol::getUnused() const {
+ return {};
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeSession.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeSession.cpp
new file mode 100644
index 0000000000..7212a0e650
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeSession.cpp
@@ -0,0 +1,463 @@
+//===- NativeSession.cpp - Native implementation of IPDBSession -*- 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/PDB/Native/NativeSession.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
+#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumInjectedSources.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
+#include "llvm/DebugInfo/PDB/Native/NativeExeSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolCache.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+
+#include <algorithm>
+#include <cassert>
+#include <memory>
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+static DbiStream *getDbiStreamPtr(PDBFile &File) {
+ Expected<DbiStream &> DbiS = File.getPDBDbiStream();
+ if (DbiS)
+ return &DbiS.get();
+
+ consumeError(DbiS.takeError());
+ return nullptr;
+}
+
+NativeSession::NativeSession(std::unique_ptr<PDBFile> PdbFile,
+ std::unique_ptr<BumpPtrAllocator> Allocator)
+ : Pdb(std::move(PdbFile)), Allocator(std::move(Allocator)),
+ Cache(*this, getDbiStreamPtr(*Pdb)), AddrToModuleIndex(IMapAllocator) {}
+
+NativeSession::~NativeSession() = default;
+
+Error NativeSession::createFromPdb(std::unique_ptr<MemoryBuffer> Buffer,
+ std::unique_ptr<IPDBSession> &Session) {
+ StringRef Path = Buffer->getBufferIdentifier();
+ auto Stream = std::make_unique<MemoryBufferByteStream>(
+ std::move(Buffer), llvm::support::little);
+
+ auto Allocator = std::make_unique<BumpPtrAllocator>();
+ auto File = std::make_unique<PDBFile>(Path, std::move(Stream), *Allocator);
+ if (auto EC = File->parseFileHeaders())
+ return EC;
+ if (auto EC = File->parseStreamData())
+ return EC;
+
+ Session =
+ std::make_unique<NativeSession>(std::move(File), std::move(Allocator));
+
+ return Error::success();
+}
+
+static Expected<std::unique_ptr<PDBFile>>
+loadPdbFile(StringRef PdbPath, std::unique_ptr<BumpPtrAllocator> &Allocator) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> ErrorOrBuffer =
+ MemoryBuffer::getFile(PdbPath, /*IsText=*/false,
+ /*RequiresNullTerminator=*/false);
+ if (!ErrorOrBuffer)
+ return make_error<RawError>(ErrorOrBuffer.getError());
+ std::unique_ptr<llvm::MemoryBuffer> Buffer = std::move(*ErrorOrBuffer);
+
+ PdbPath = Buffer->getBufferIdentifier();
+ file_magic Magic;
+ auto EC = identify_magic(PdbPath, Magic);
+ if (EC || Magic != file_magic::pdb)
+ return make_error<RawError>(EC);
+
+ auto Stream = std::make_unique<MemoryBufferByteStream>(std::move(Buffer),
+ llvm::support::little);
+
+ auto File = std::make_unique<PDBFile>(PdbPath, std::move(Stream), *Allocator);
+ if (auto EC = File->parseFileHeaders())
+ return std::move(EC);
+
+ if (auto EC = File->parseStreamData())
+ return std::move(EC);
+
+ return std::move(File);
+}
+
+Error NativeSession::createFromPdbPath(StringRef PdbPath,
+ std::unique_ptr<IPDBSession> &Session) {
+ auto Allocator = std::make_unique<BumpPtrAllocator>();
+ auto PdbFile = loadPdbFile(PdbPath, Allocator);
+ if (!PdbFile)
+ return PdbFile.takeError();
+
+ Session = std::make_unique<NativeSession>(std::move(PdbFile.get()),
+ std::move(Allocator));
+ return Error::success();
+}
+
+static Expected<std::string> getPdbPathFromExe(StringRef ExePath) {
+ Expected<object::OwningBinary<object::Binary>> BinaryFile =
+ object::createBinary(ExePath);
+ if (!BinaryFile)
+ return BinaryFile.takeError();
+
+ const object::COFFObjectFile *ObjFile =
+ dyn_cast<object::COFFObjectFile>(BinaryFile->getBinary());
+ if (!ObjFile)
+ return make_error<RawError>(raw_error_code::invalid_format);
+
+ StringRef PdbPath;
+ const llvm::codeview::DebugInfo *PdbInfo = nullptr;
+ if (Error E = ObjFile->getDebugPDBInfo(PdbInfo, PdbPath))
+ return std::move(E);
+
+ return std::string(PdbPath);
+}
+
+Error NativeSession::createFromExe(StringRef ExePath,
+ std::unique_ptr<IPDBSession> &Session) {
+ Expected<std::string> PdbPath = getPdbPathFromExe(ExePath);
+ if (!PdbPath)
+ return PdbPath.takeError();
+
+ file_magic Magic;
+ auto EC = identify_magic(PdbPath.get(), Magic);
+ if (EC || Magic != file_magic::pdb)
+ return make_error<RawError>(EC);
+
+ auto Allocator = std::make_unique<BumpPtrAllocator>();
+ auto File = loadPdbFile(PdbPath.get(), Allocator);
+ if (!File)
+ return File.takeError();
+
+ Session = std::make_unique<NativeSession>(std::move(File.get()),
+ std::move(Allocator));
+
+ return Error::success();
+}
+
+Expected<std::string>
+NativeSession::searchForPdb(const PdbSearchOptions &Opts) {
+ Expected<std::string> PathOrErr = getPdbPathFromExe(Opts.ExePath);
+ if (!PathOrErr)
+ return PathOrErr.takeError();
+ StringRef PathFromExe = PathOrErr.get();
+ sys::path::Style Style = PathFromExe.startswith("/")
+ ? sys::path::Style::posix
+ : sys::path::Style::windows;
+ StringRef PdbName = sys::path::filename(PathFromExe, Style);
+
+ // Check if pdb exists in the executable directory.
+ SmallString<128> PdbPath = StringRef(Opts.ExePath);
+ sys::path::remove_filename(PdbPath);
+ sys::path::append(PdbPath, PdbName);
+
+ auto Allocator = std::make_unique<BumpPtrAllocator>();
+
+ if (auto File = loadPdbFile(PdbPath, Allocator))
+ return std::string(PdbPath);
+ else
+ consumeError(File.takeError());
+
+ // Check path that was in the executable.
+ if (auto File = loadPdbFile(PathFromExe, Allocator))
+ return std::string(PathFromExe);
+ else
+ return File.takeError();
+
+ return make_error<RawError>("PDB not found");
+}
+
+uint64_t NativeSession::getLoadAddress() const { return LoadAddress; }
+
+bool NativeSession::setLoadAddress(uint64_t Address) {
+ LoadAddress = Address;
+ return true;
+}
+
+std::unique_ptr<PDBSymbolExe> NativeSession::getGlobalScope() {
+ return PDBSymbol::createAs<PDBSymbolExe>(*this, getNativeGlobalScope());
+}
+
+std::unique_ptr<PDBSymbol>
+NativeSession::getSymbolById(SymIndexId SymbolId) const {
+ return Cache.getSymbolById(SymbolId);
+}
+
+bool NativeSession::addressForVA(uint64_t VA, uint32_t &Section,
+ uint32_t &Offset) const {
+ uint32_t RVA = VA - getLoadAddress();
+ return addressForRVA(RVA, Section, Offset);
+}
+
+bool NativeSession::addressForRVA(uint32_t RVA, uint32_t &Section,
+ uint32_t &Offset) const {
+ Section = 0;
+ Offset = 0;
+
+ auto Dbi = Pdb->getPDBDbiStream();
+ if (!Dbi)
+ return false;
+
+ if ((int32_t)RVA < 0)
+ return true;
+
+ Offset = RVA;
+ for (; Section < Dbi->getSectionHeaders().size(); ++Section) {
+ auto &Sec = Dbi->getSectionHeaders()[Section];
+ if (RVA < Sec.VirtualAddress)
+ return true;
+ Offset = RVA - Sec.VirtualAddress;
+ }
+ return true;
+}
+
+std::unique_ptr<PDBSymbol>
+NativeSession::findSymbolByAddress(uint64_t Address, PDB_SymType Type) {
+ uint32_t Section;
+ uint32_t Offset;
+ addressForVA(Address, Section, Offset);
+ return findSymbolBySectOffset(Section, Offset, Type);
+}
+
+std::unique_ptr<PDBSymbol> NativeSession::findSymbolByRVA(uint32_t RVA,
+ PDB_SymType Type) {
+ uint32_t Section;
+ uint32_t Offset;
+ addressForRVA(RVA, Section, Offset);
+ return findSymbolBySectOffset(Section, Offset, Type);
+}
+
+std::unique_ptr<PDBSymbol>
+NativeSession::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset,
+ PDB_SymType Type) {
+ if (AddrToModuleIndex.empty())
+ parseSectionContribs();
+
+ return Cache.findSymbolBySectOffset(Sect, Offset, Type);
+}
+
+std::unique_ptr<IPDBEnumLineNumbers>
+NativeSession::findLineNumbers(const PDBSymbolCompiland &Compiland,
+ const IPDBSourceFile &File) const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBEnumLineNumbers>
+NativeSession::findLineNumbersByAddress(uint64_t Address,
+ uint32_t Length) const {
+ return Cache.findLineNumbersByVA(Address, Length);
+}
+
+std::unique_ptr<IPDBEnumLineNumbers>
+NativeSession::findLineNumbersByRVA(uint32_t RVA, uint32_t Length) const {
+ return Cache.findLineNumbersByVA(getLoadAddress() + RVA, Length);
+}
+
+std::unique_ptr<IPDBEnumLineNumbers>
+NativeSession::findLineNumbersBySectOffset(uint32_t Section, uint32_t Offset,
+ uint32_t Length) const {
+ uint64_t VA = getVAFromSectOffset(Section, Offset);
+ return Cache.findLineNumbersByVA(VA, Length);
+}
+
+std::unique_ptr<IPDBEnumSourceFiles>
+NativeSession::findSourceFiles(const PDBSymbolCompiland *Compiland,
+ StringRef Pattern,
+ PDB_NameSearchFlags Flags) const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBSourceFile>
+NativeSession::findOneSourceFile(const PDBSymbolCompiland *Compiland,
+ StringRef Pattern,
+ PDB_NameSearchFlags Flags) const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
+NativeSession::findCompilandsForSourceFile(StringRef Pattern,
+ PDB_NameSearchFlags Flags) const {
+ return nullptr;
+}
+
+std::unique_ptr<PDBSymbolCompiland>
+NativeSession::findOneCompilandForSourceFile(StringRef Pattern,
+ PDB_NameSearchFlags Flags) const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getAllSourceFiles() const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBEnumSourceFiles> NativeSession::getSourceFilesForCompiland(
+ const PDBSymbolCompiland &Compiland) const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBSourceFile>
+NativeSession::getSourceFileById(uint32_t FileId) const {
+ return Cache.getSourceFileById(FileId);
+}
+
+std::unique_ptr<IPDBEnumDataStreams> NativeSession::getDebugStreams() const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBEnumTables> NativeSession::getEnumTables() const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBEnumInjectedSources>
+NativeSession::getInjectedSources() const {
+ auto ISS = Pdb->getInjectedSourceStream();
+ if (!ISS) {
+ consumeError(ISS.takeError());
+ return nullptr;
+ }
+ auto Strings = Pdb->getStringTable();
+ if (!Strings) {
+ consumeError(Strings.takeError());
+ return nullptr;
+ }
+ return std::make_unique<NativeEnumInjectedSources>(*Pdb, *ISS, *Strings);
+}
+
+std::unique_ptr<IPDBEnumSectionContribs>
+NativeSession::getSectionContribs() const {
+ return nullptr;
+}
+
+std::unique_ptr<IPDBEnumFrameData>
+NativeSession::getFrameData() const {
+ return nullptr;
+}
+
+void NativeSession::initializeExeSymbol() {
+ if (ExeSymbol == 0)
+ ExeSymbol = Cache.createSymbol<NativeExeSymbol>();
+}
+
+NativeExeSymbol &NativeSession::getNativeGlobalScope() const {
+ const_cast<NativeSession &>(*this).initializeExeSymbol();
+
+ return Cache.getNativeSymbolById<NativeExeSymbol>(ExeSymbol);
+}
+
+uint32_t NativeSession::getRVAFromSectOffset(uint32_t Section,
+ uint32_t Offset) const {
+ if (Section <= 0)
+ return 0;
+
+ auto Dbi = getDbiStreamPtr(*Pdb);
+ if (!Dbi)
+ return 0;
+
+ uint32_t MaxSection = Dbi->getSectionHeaders().size();
+ if (Section > MaxSection + 1)
+ Section = MaxSection + 1;
+ auto &Sec = Dbi->getSectionHeaders()[Section - 1];
+ return Sec.VirtualAddress + Offset;
+}
+
+uint64_t NativeSession::getVAFromSectOffset(uint32_t Section,
+ uint32_t Offset) const {
+ return LoadAddress + getRVAFromSectOffset(Section, Offset);
+}
+
+bool NativeSession::moduleIndexForVA(uint64_t VA, uint16_t &ModuleIndex) const {
+ ModuleIndex = 0;
+ auto Iter = AddrToModuleIndex.find(VA);
+ if (Iter == AddrToModuleIndex.end())
+ return false;
+ ModuleIndex = Iter.value();
+ return true;
+}
+
+bool NativeSession::moduleIndexForSectOffset(uint32_t Sect, uint32_t Offset,
+ uint16_t &ModuleIndex) const {
+ ModuleIndex = 0;
+ auto Iter = AddrToModuleIndex.find(getVAFromSectOffset(Sect, Offset));
+ if (Iter == AddrToModuleIndex.end())
+ return false;
+ ModuleIndex = Iter.value();
+ return true;
+}
+
+void NativeSession::parseSectionContribs() {
+ auto Dbi = Pdb->getPDBDbiStream();
+ if (!Dbi)
+ return;
+
+ class Visitor : public ISectionContribVisitor {
+ NativeSession &Session;
+ IMap &AddrMap;
+
+ public:
+ Visitor(NativeSession &Session, IMap &AddrMap)
+ : Session(Session), AddrMap(AddrMap) {}
+ void visit(const SectionContrib &C) override {
+ if (C.Size == 0)
+ return;
+
+ uint64_t VA = Session.getVAFromSectOffset(C.ISect, C.Off);
+ uint64_t End = VA + C.Size;
+
+ // Ignore overlapping sections based on the assumption that a valid
+ // PDB file should not have overlaps.
+ if (!AddrMap.overlaps(VA, End))
+ AddrMap.insert(VA, End, C.Imod);
+ }
+ void visit(const SectionContrib2 &C) override { visit(C.Base); }
+ };
+
+ Visitor V(*this, AddrToModuleIndex);
+ Dbi->visitSectionContributions(V);
+}
+
+Expected<ModuleDebugStreamRef>
+NativeSession::getModuleDebugStream(uint32_t Index) const {
+ auto *Dbi = getDbiStreamPtr(*Pdb);
+ assert(Dbi && "Dbi stream not present");
+
+ DbiModuleDescriptor Modi = Dbi->modules().getModuleDescriptor(Index);
+
+ uint16_t ModiStream = Modi.getModuleStreamIndex();
+ if (ModiStream == kInvalidStreamIndex)
+ return make_error<RawError>("Module stream not present");
+
+ std::unique_ptr<msf::MappedBlockStream> ModStreamData =
+ Pdb->createIndexedStream(ModiStream);
+
+ ModuleDebugStreamRef ModS(Modi, std::move(ModStreamData));
+ if (auto EC = ModS.reload())
+ return std::move(EC);
+
+ return std::move(ModS);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeSourceFile.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeSourceFile.cpp
new file mode 100644
index 0000000000..fd813dee6b
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeSourceFile.cpp
@@ -0,0 +1,47 @@
+//===- NativeSourceFile.cpp - Native line number implementation -*- 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/PDB/Native/NativeSourceFile.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+NativeSourceFile::NativeSourceFile(NativeSession &Session, uint32_t FileId,
+ const codeview::FileChecksumEntry &Checksum)
+ : Session(Session), FileId(FileId), Checksum(Checksum) {}
+
+std::string NativeSourceFile::getFileName() const {
+ auto ST = Session.getPDBFile().getStringTable();
+ if (!ST) {
+ consumeError(ST.takeError());
+ return "";
+ }
+ auto FileName = ST->getStringTable().getString(Checksum.FileNameOffset);
+ if (!FileName) {
+ consumeError(FileName.takeError());
+ return "";
+ }
+
+ return std::string(FileName.get());
+}
+
+uint32_t NativeSourceFile::getUniqueId() const { return FileId; }
+
+std::string NativeSourceFile::getChecksum() const {
+ return toStringRef(Checksum.Checksum).str();
+}
+
+PDB_Checksum NativeSourceFile::getChecksumType() const {
+ return static_cast<PDB_Checksum>(Checksum.Kind);
+}
+
+std::unique_ptr<IPDBEnumChildren<PDBSymbolCompiland>>
+NativeSourceFile::getCompilands() const {
+ return nullptr;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp
new file mode 100644
index 0000000000..e5f1dcaf80
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeSymbolEnumerator.cpp
@@ -0,0 +1,124 @@
+//===- NativeSymbolEnumerator.cpp - info about enumerators ------*- 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/PDB/Native/NativeSymbolEnumerator.h"
+
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+NativeSymbolEnumerator::NativeSymbolEnumerator(
+ NativeSession &Session, SymIndexId Id, const NativeTypeEnum &Parent,
+ codeview::EnumeratorRecord Record)
+ : NativeRawSymbol(Session, PDB_SymType::Data, Id), Parent(Parent),
+ Record(std::move(Record)) {}
+
+NativeSymbolEnumerator::~NativeSymbolEnumerator() {}
+
+void NativeSymbolEnumerator::dump(raw_ostream &OS, int Indent,
+ PdbSymbolIdField ShowIdFields,
+ PdbSymbolIdField RecurseIdFields) const {
+ NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
+ dumpSymbolIdField(OS, "classParentId", getClassParentId(), Indent, Session,
+ PdbSymbolIdField::ClassParent, ShowIdFields,
+ RecurseIdFields);
+ dumpSymbolIdField(OS, "lexicalParentId", getLexicalParentId(), Indent,
+ Session, PdbSymbolIdField::LexicalParent, ShowIdFields,
+ RecurseIdFields);
+ dumpSymbolField(OS, "name", getName(), Indent);
+ dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session,
+ PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields);
+ dumpSymbolField(OS, "dataKind", getDataKind(), Indent);
+ dumpSymbolField(OS, "locationType", getLocationType(), Indent);
+ dumpSymbolField(OS, "constType", isConstType(), Indent);
+ dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent);
+ dumpSymbolField(OS, "volatileType", isVolatileType(), Indent);
+ dumpSymbolField(OS, "value", getValue(), Indent);
+}
+
+SymIndexId NativeSymbolEnumerator::getClassParentId() const {
+ return Parent.getSymIndexId();
+}
+
+SymIndexId NativeSymbolEnumerator::getLexicalParentId() const { return 0; }
+
+std::string NativeSymbolEnumerator::getName() const {
+ return std::string(Record.Name);
+}
+
+SymIndexId NativeSymbolEnumerator::getTypeId() const {
+ return Parent.getTypeId();
+}
+
+PDB_DataKind NativeSymbolEnumerator::getDataKind() const {
+ return PDB_DataKind::Constant;
+}
+
+PDB_LocType NativeSymbolEnumerator::getLocationType() const {
+ return PDB_LocType::Constant;
+}
+
+bool NativeSymbolEnumerator::isConstType() const { return false; }
+
+bool NativeSymbolEnumerator::isVolatileType() const { return false; }
+
+bool NativeSymbolEnumerator::isUnalignedType() const { return false; }
+
+Variant NativeSymbolEnumerator::getValue() const {
+ const NativeTypeBuiltin &BT = Parent.getUnderlyingBuiltinType();
+
+ switch (BT.getBuiltinType()) {
+ case PDB_BuiltinType::Int:
+ case PDB_BuiltinType::Long:
+ case PDB_BuiltinType::Char: {
+ assert(Record.Value.isSignedIntN(BT.getLength() * 8));
+ int64_t N = Record.Value.getSExtValue();
+ switch (BT.getLength()) {
+ case 1:
+ return Variant{static_cast<int8_t>(N)};
+ case 2:
+ return Variant{static_cast<int16_t>(N)};
+ case 4:
+ return Variant{static_cast<int32_t>(N)};
+ case 8:
+ return Variant{static_cast<int64_t>(N)};
+ }
+ break;
+ }
+ case PDB_BuiltinType::UInt:
+ case PDB_BuiltinType::ULong: {
+ assert(Record.Value.isIntN(BT.getLength() * 8));
+ uint64_t U = Record.Value.getZExtValue();
+ switch (BT.getLength()) {
+ case 1:
+ return Variant{static_cast<uint8_t>(U)};
+ case 2:
+ return Variant{static_cast<uint16_t>(U)};
+ case 4:
+ return Variant{static_cast<uint32_t>(U)};
+ case 8:
+ return Variant{static_cast<uint64_t>(U)};
+ }
+ break;
+ }
+ case PDB_BuiltinType::Bool: {
+ assert(Record.Value.isIntN(BT.getLength() * 8));
+ uint64_t U = Record.Value.getZExtValue();
+ return Variant{static_cast<bool>(U)};
+ }
+ default:
+ assert(false && "Invalid enumeration type");
+ break;
+ }
+
+ return Variant{Record.Value.getSExtValue()};
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeArray.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeArray.cpp
new file mode 100644
index 0000000000..63ac9fae0e
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeArray.cpp
@@ -0,0 +1,66 @@
+//===- NativeTypeArray.cpp - info about arrays ------------------*- 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/PDB/Native/NativeTypeArray.h"
+
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+NativeTypeArray::NativeTypeArray(NativeSession &Session, SymIndexId Id,
+ codeview::TypeIndex TI,
+ codeview::ArrayRecord Record)
+ : NativeRawSymbol(Session, PDB_SymType::ArrayType, Id), Record(Record),
+ Index(TI) {}
+NativeTypeArray::~NativeTypeArray() {}
+
+void NativeTypeArray::dump(raw_ostream &OS, int Indent,
+ PdbSymbolIdField ShowIdFields,
+ PdbSymbolIdField RecurseIdFields) const {
+ NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
+
+ dumpSymbolField(OS, "arrayIndexTypeId", getArrayIndexTypeId(), Indent);
+ dumpSymbolIdField(OS, "elementTypeId", getTypeId(), Indent, Session,
+ PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields);
+
+ dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session,
+ PdbSymbolIdField::LexicalParent, ShowIdFields,
+ RecurseIdFields);
+ dumpSymbolField(OS, "length", getLength(), Indent);
+ dumpSymbolField(OS, "count", getCount(), Indent);
+ dumpSymbolField(OS, "constType", isConstType(), Indent);
+ dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent);
+ dumpSymbolField(OS, "volatileType", isVolatileType(), Indent);
+}
+
+SymIndexId NativeTypeArray::getArrayIndexTypeId() const {
+ return Session.getSymbolCache().findSymbolByTypeIndex(Record.getIndexType());
+}
+
+bool NativeTypeArray::isConstType() const { return false; }
+
+bool NativeTypeArray::isUnalignedType() const { return false; }
+
+bool NativeTypeArray::isVolatileType() const { return false; }
+
+uint32_t NativeTypeArray::getCount() const {
+ NativeRawSymbol &Element =
+ Session.getSymbolCache().getNativeSymbolById(getTypeId());
+ return getLength() / Element.getLength();
+}
+
+SymIndexId NativeTypeArray::getTypeId() const {
+ return Session.getSymbolCache().findSymbolByTypeIndex(
+ Record.getElementType());
+}
+
+uint64_t NativeTypeArray::getLength() const { return Record.Size; }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp
new file mode 100644
index 0000000000..a08663aa91
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeBuiltin.cpp
@@ -0,0 +1,46 @@
+//===- NativeTypeBuiltin.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/PDB/Native/NativeTypeBuiltin.h"
+#include "llvm/Support/FormatVariadic.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+NativeTypeBuiltin::NativeTypeBuiltin(NativeSession &PDBSession, SymIndexId Id,
+ ModifierOptions Mods, PDB_BuiltinType T,
+ uint64_t L)
+ : NativeRawSymbol(PDBSession, PDB_SymType::BuiltinType, Id),
+ Session(PDBSession), Mods(Mods), Type(T), Length(L) {}
+
+NativeTypeBuiltin::~NativeTypeBuiltin() {}
+
+void NativeTypeBuiltin::dump(raw_ostream &OS, int Indent,
+ PdbSymbolIdField ShowIdFields,
+ PdbSymbolIdField RecurseIdFields) const {}
+
+PDB_SymType NativeTypeBuiltin::getSymTag() const {
+ return PDB_SymType::BuiltinType;
+}
+
+PDB_BuiltinType NativeTypeBuiltin::getBuiltinType() const { return Type; }
+
+bool NativeTypeBuiltin::isConstType() const {
+ return (Mods & ModifierOptions::Const) != ModifierOptions::None;
+}
+
+uint64_t NativeTypeBuiltin::getLength() const { return Length; }
+
+bool NativeTypeBuiltin::isUnalignedType() const {
+ return (Mods & ModifierOptions::Unaligned) != ModifierOptions::None;
+}
+
+bool NativeTypeBuiltin::isVolatileType() const {
+ return (Mods & ModifierOptions::Volatile) != ModifierOptions::None;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp
new file mode 100644
index 0000000000..aaec3a5e7c
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeEnum.cpp
@@ -0,0 +1,381 @@
+//===- NativeTypeEnum.cpp - info about enum type ----------------*- 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/PDB/Native/NativeTypeEnum.h"
+
+#include "llvm/DebugInfo/CodeView/CVTypeVisitor.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSymbolEnumerator.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolCache.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+
+#include "llvm/Support/FormatVariadic.h"
+
+#include <cassert>
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+namespace {
+// Yea, this is a pretty terrible class name. But if we have an enum:
+//
+// enum Foo {
+// A,
+// B
+// };
+//
+// then A and B are the "enumerators" of the "enum" Foo. And we need
+// to enumerate them.
+class NativeEnumEnumEnumerators : public IPDBEnumSymbols, TypeVisitorCallbacks {
+public:
+ NativeEnumEnumEnumerators(NativeSession &Session,
+ const NativeTypeEnum &ClassParent);
+
+ uint32_t getChildCount() const override;
+ std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override;
+ std::unique_ptr<PDBSymbol> getNext() override;
+ void reset() override;
+
+private:
+ Error visitKnownMember(CVMemberRecord &CVM,
+ EnumeratorRecord &Record) override;
+ Error visitKnownMember(CVMemberRecord &CVM,
+ ListContinuationRecord &Record) override;
+
+ NativeSession &Session;
+ const NativeTypeEnum &ClassParent;
+ std::vector<EnumeratorRecord> Enumerators;
+ Optional<TypeIndex> ContinuationIndex;
+ uint32_t Index = 0;
+};
+} // namespace
+
+NativeEnumEnumEnumerators::NativeEnumEnumEnumerators(
+ NativeSession &Session, const NativeTypeEnum &ClassParent)
+ : Session(Session), ClassParent(ClassParent) {
+ TpiStream &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream());
+ LazyRandomTypeCollection &Types = Tpi.typeCollection();
+
+ ContinuationIndex = ClassParent.getEnumRecord().FieldList;
+ while (ContinuationIndex) {
+ CVType FieldList = Types.getType(*ContinuationIndex);
+ assert(FieldList.kind() == LF_FIELDLIST);
+ ContinuationIndex.reset();
+ cantFail(visitMemberRecordStream(FieldList.data(), *this));
+ }
+}
+
+Error NativeEnumEnumEnumerators::visitKnownMember(CVMemberRecord &CVM,
+ EnumeratorRecord &Record) {
+ Enumerators.push_back(Record);
+ return Error::success();
+}
+
+Error NativeEnumEnumEnumerators::visitKnownMember(
+ CVMemberRecord &CVM, ListContinuationRecord &Record) {
+ ContinuationIndex = Record.ContinuationIndex;
+ return Error::success();
+}
+
+uint32_t NativeEnumEnumEnumerators::getChildCount() const {
+ return Enumerators.size();
+}
+
+std::unique_ptr<PDBSymbol>
+NativeEnumEnumEnumerators::getChildAtIndex(uint32_t Index) const {
+ if (Index >= getChildCount())
+ return nullptr;
+
+ SymIndexId Id = Session.getSymbolCache()
+ .getOrCreateFieldListMember<NativeSymbolEnumerator>(
+ ClassParent.getEnumRecord().FieldList, Index,
+ ClassParent, Enumerators[Index]);
+ return Session.getSymbolCache().getSymbolById(Id);
+}
+
+std::unique_ptr<PDBSymbol> NativeEnumEnumEnumerators::getNext() {
+ if (Index >= getChildCount())
+ return nullptr;
+
+ return getChildAtIndex(Index++);
+}
+
+void NativeEnumEnumEnumerators::reset() { Index = 0; }
+
+NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id,
+ TypeIndex Index, EnumRecord Record)
+ : NativeRawSymbol(Session, PDB_SymType::Enum, Id), Index(Index),
+ Record(std::move(Record)) {}
+
+NativeTypeEnum::NativeTypeEnum(NativeSession &Session, SymIndexId Id,
+ NativeTypeEnum &UnmodifiedType,
+ codeview::ModifierRecord Modifier)
+ : NativeRawSymbol(Session, PDB_SymType::Enum, Id),
+ UnmodifiedType(&UnmodifiedType), Modifiers(std::move(Modifier)) {}
+
+NativeTypeEnum::~NativeTypeEnum() {}
+
+void NativeTypeEnum::dump(raw_ostream &OS, int Indent,
+ PdbSymbolIdField ShowIdFields,
+ PdbSymbolIdField RecurseIdFields) const {
+ NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
+
+ dumpSymbolField(OS, "baseType", static_cast<uint32_t>(getBuiltinType()),
+ Indent);
+ dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session,
+ PdbSymbolIdField::LexicalParent, ShowIdFields,
+ RecurseIdFields);
+ dumpSymbolField(OS, "name", getName(), Indent);
+ dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session,
+ PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields);
+ if (Modifiers.hasValue())
+ dumpSymbolIdField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent,
+ Session, PdbSymbolIdField::UnmodifiedType, ShowIdFields,
+ RecurseIdFields);
+ dumpSymbolField(OS, "length", getLength(), Indent);
+ dumpSymbolField(OS, "constructor", hasConstructor(), Indent);
+ dumpSymbolField(OS, "constType", isConstType(), Indent);
+ dumpSymbolField(OS, "hasAssignmentOperator", hasAssignmentOperator(), Indent);
+ dumpSymbolField(OS, "hasCastOperator", hasCastOperator(), Indent);
+ dumpSymbolField(OS, "hasNestedTypes", hasNestedTypes(), Indent);
+ dumpSymbolField(OS, "overloadedOperator", hasOverloadedOperator(), Indent);
+ dumpSymbolField(OS, "isInterfaceUdt", isInterfaceUdt(), Indent);
+ dumpSymbolField(OS, "intrinsic", isIntrinsic(), Indent);
+ dumpSymbolField(OS, "nested", isNested(), Indent);
+ dumpSymbolField(OS, "packed", isPacked(), Indent);
+ dumpSymbolField(OS, "isRefUdt", isRefUdt(), Indent);
+ dumpSymbolField(OS, "scoped", isScoped(), Indent);
+ dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent);
+ dumpSymbolField(OS, "isValueUdt", isValueUdt(), Indent);
+ dumpSymbolField(OS, "volatileType", isVolatileType(), Indent);
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeTypeEnum::findChildren(PDB_SymType Type) const {
+ if (Type != PDB_SymType::Data)
+ return std::make_unique<NullEnumerator<PDBSymbol>>();
+
+ const NativeTypeEnum *ClassParent = nullptr;
+ if (!Modifiers)
+ ClassParent = this;
+ else
+ ClassParent = UnmodifiedType;
+ return std::make_unique<NativeEnumEnumEnumerators>(Session, *ClassParent);
+}
+
+PDB_SymType NativeTypeEnum::getSymTag() const { return PDB_SymType::Enum; }
+
+PDB_BuiltinType NativeTypeEnum::getBuiltinType() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->getBuiltinType();
+
+ Session.getSymbolCache().findSymbolByTypeIndex(Record->getUnderlyingType());
+
+ codeview::TypeIndex Underlying = Record->getUnderlyingType();
+
+ // This indicates a corrupt record.
+ if (!Underlying.isSimple() ||
+ Underlying.getSimpleMode() != SimpleTypeMode::Direct) {
+ return PDB_BuiltinType::None;
+ }
+
+ switch (Underlying.getSimpleKind()) {
+ case SimpleTypeKind::Boolean128:
+ case SimpleTypeKind::Boolean64:
+ case SimpleTypeKind::Boolean32:
+ case SimpleTypeKind::Boolean16:
+ case SimpleTypeKind::Boolean8:
+ return PDB_BuiltinType::Bool;
+ case SimpleTypeKind::NarrowCharacter:
+ case SimpleTypeKind::UnsignedCharacter:
+ case SimpleTypeKind::SignedCharacter:
+ return PDB_BuiltinType::Char;
+ case SimpleTypeKind::WideCharacter:
+ return PDB_BuiltinType::WCharT;
+ case SimpleTypeKind::Character16:
+ return PDB_BuiltinType::Char16;
+ case SimpleTypeKind::Character32:
+ return PDB_BuiltinType::Char32;
+ case SimpleTypeKind::Int128:
+ case SimpleTypeKind::Int128Oct:
+ case SimpleTypeKind::Int16:
+ case SimpleTypeKind::Int16Short:
+ case SimpleTypeKind::Int32:
+ case SimpleTypeKind::Int32Long:
+ case SimpleTypeKind::Int64:
+ case SimpleTypeKind::Int64Quad:
+ return PDB_BuiltinType::Int;
+ case SimpleTypeKind::UInt128:
+ case SimpleTypeKind::UInt128Oct:
+ case SimpleTypeKind::UInt16:
+ case SimpleTypeKind::UInt16Short:
+ case SimpleTypeKind::UInt32:
+ case SimpleTypeKind::UInt32Long:
+ case SimpleTypeKind::UInt64:
+ case SimpleTypeKind::UInt64Quad:
+ return PDB_BuiltinType::UInt;
+ case SimpleTypeKind::HResult:
+ return PDB_BuiltinType::HResult;
+ case SimpleTypeKind::Complex16:
+ case SimpleTypeKind::Complex32:
+ case SimpleTypeKind::Complex32PartialPrecision:
+ case SimpleTypeKind::Complex64:
+ case SimpleTypeKind::Complex80:
+ case SimpleTypeKind::Complex128:
+ return PDB_BuiltinType::Complex;
+ case SimpleTypeKind::Float16:
+ case SimpleTypeKind::Float32:
+ case SimpleTypeKind::Float32PartialPrecision:
+ case SimpleTypeKind::Float48:
+ case SimpleTypeKind::Float64:
+ case SimpleTypeKind::Float80:
+ case SimpleTypeKind::Float128:
+ return PDB_BuiltinType::Float;
+ default:
+ return PDB_BuiltinType::None;
+ }
+ llvm_unreachable("Unreachable");
+}
+
+SymIndexId NativeTypeEnum::getUnmodifiedTypeId() const {
+ return UnmodifiedType ? UnmodifiedType->getSymIndexId() : 0;
+}
+
+bool NativeTypeEnum::hasConstructor() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->hasConstructor();
+
+ return bool(Record->getOptions() &
+ codeview::ClassOptions::HasConstructorOrDestructor);
+}
+
+bool NativeTypeEnum::hasAssignmentOperator() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->hasAssignmentOperator();
+
+ return bool(Record->getOptions() &
+ codeview::ClassOptions::HasOverloadedAssignmentOperator);
+}
+
+bool NativeTypeEnum::hasNestedTypes() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->hasNestedTypes();
+
+ return bool(Record->getOptions() &
+ codeview::ClassOptions::ContainsNestedClass);
+}
+
+bool NativeTypeEnum::isIntrinsic() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->isIntrinsic();
+
+ return bool(Record->getOptions() & codeview::ClassOptions::Intrinsic);
+}
+
+bool NativeTypeEnum::hasCastOperator() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->hasCastOperator();
+
+ return bool(Record->getOptions() &
+ codeview::ClassOptions::HasConversionOperator);
+}
+
+uint64_t NativeTypeEnum::getLength() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->getLength();
+
+ const auto Id = Session.getSymbolCache().findSymbolByTypeIndex(
+ Record->getUnderlyingType());
+ const auto UnderlyingType =
+ Session.getConcreteSymbolById<PDBSymbolTypeBuiltin>(Id);
+ return UnderlyingType ? UnderlyingType->getLength() : 0;
+}
+
+std::string NativeTypeEnum::getName() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->getName();
+
+ return std::string(Record->getName());
+}
+
+bool NativeTypeEnum::isNested() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->isNested();
+
+ return bool(Record->getOptions() & codeview::ClassOptions::Nested);
+}
+
+bool NativeTypeEnum::hasOverloadedOperator() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->hasOverloadedOperator();
+
+ return bool(Record->getOptions() &
+ codeview::ClassOptions::HasOverloadedOperator);
+}
+
+bool NativeTypeEnum::isPacked() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->isPacked();
+
+ return bool(Record->getOptions() & codeview::ClassOptions::Packed);
+}
+
+bool NativeTypeEnum::isScoped() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->isScoped();
+
+ return bool(Record->getOptions() & codeview::ClassOptions::Scoped);
+}
+
+SymIndexId NativeTypeEnum::getTypeId() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->getTypeId();
+
+ return Session.getSymbolCache().findSymbolByTypeIndex(
+ Record->getUnderlyingType());
+}
+
+bool NativeTypeEnum::isRefUdt() const { return false; }
+
+bool NativeTypeEnum::isValueUdt() const { return false; }
+
+bool NativeTypeEnum::isInterfaceUdt() const { return false; }
+
+bool NativeTypeEnum::isConstType() const {
+ if (!Modifiers)
+ return false;
+ return ((Modifiers->getModifiers() & ModifierOptions::Const) !=
+ ModifierOptions::None);
+}
+
+bool NativeTypeEnum::isVolatileType() const {
+ if (!Modifiers)
+ return false;
+ return ((Modifiers->getModifiers() & ModifierOptions::Volatile) !=
+ ModifierOptions::None);
+}
+
+bool NativeTypeEnum::isUnalignedType() const {
+ if (!Modifiers)
+ return false;
+ return ((Modifiers->getModifiers() & ModifierOptions::Unaligned) !=
+ ModifierOptions::None);
+}
+
+const NativeTypeBuiltin &NativeTypeEnum::getUnderlyingBuiltinType() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->getUnderlyingBuiltinType();
+
+ return Session.getSymbolCache().getNativeSymbolById<NativeTypeBuiltin>(
+ getTypeId());
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp
new file mode 100644
index 0000000000..f98a4c3043
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeFunctionSig.cpp
@@ -0,0 +1,199 @@
+//===- NativeTypeFunctionSig.cpp - info about function signature -*- 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/PDB/Native/NativeTypeFunctionSig.h"
+
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
+#include "llvm/DebugInfo/PDB/PDBExtras.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+namespace {
+// This is kind of a silly class, hence why we keep it private to the file.
+// It's only purpose is to wrap the real type record. I guess this is so that
+// we can have the lexical parent point to the function instead of the global
+// scope.
+class NativeTypeFunctionArg : public NativeRawSymbol {
+public:
+ NativeTypeFunctionArg(NativeSession &Session,
+ std::unique_ptr<PDBSymbol> RealType)
+ : NativeRawSymbol(Session, PDB_SymType::FunctionArg, 0),
+ RealType(std::move(RealType)) {}
+
+ void dump(raw_ostream &OS, int Indent, PdbSymbolIdField ShowIdFields,
+ PdbSymbolIdField RecurseIdFields) const override {
+ NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
+
+ dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session,
+ PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields);
+ }
+
+ SymIndexId getTypeId() const override { return RealType->getSymIndexId(); }
+
+ std::unique_ptr<PDBSymbol> RealType;
+};
+
+class NativeEnumFunctionArgs : public IPDBEnumChildren<PDBSymbol> {
+public:
+ NativeEnumFunctionArgs(NativeSession &Session,
+ std::unique_ptr<NativeEnumTypes> TypeEnumerator)
+ : Session(Session), TypeEnumerator(std::move(TypeEnumerator)) {}
+
+ uint32_t getChildCount() const override {
+ return TypeEnumerator->getChildCount();
+ }
+ std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override {
+ return wrap(TypeEnumerator->getChildAtIndex(Index));
+ }
+ std::unique_ptr<PDBSymbol> getNext() override {
+ return wrap(TypeEnumerator->getNext());
+ }
+
+ void reset() override { TypeEnumerator->reset(); }
+
+private:
+ std::unique_ptr<PDBSymbol> wrap(std::unique_ptr<PDBSymbol> S) const {
+ if (!S)
+ return nullptr;
+ auto NTFA = std::make_unique<NativeTypeFunctionArg>(Session, std::move(S));
+ return PDBSymbol::create(Session, std::move(NTFA));
+ }
+ NativeSession &Session;
+ std::unique_ptr<NativeEnumTypes> TypeEnumerator;
+};
+} // namespace
+
+NativeTypeFunctionSig::NativeTypeFunctionSig(NativeSession &Session,
+ SymIndexId Id,
+ codeview::TypeIndex Index,
+ codeview::ProcedureRecord Proc)
+ : NativeRawSymbol(Session, PDB_SymType::FunctionSig, Id),
+ Proc(std::move(Proc)), Index(Index), IsMemberFunction(false) {}
+
+NativeTypeFunctionSig::NativeTypeFunctionSig(
+ NativeSession &Session, SymIndexId Id, codeview::TypeIndex Index,
+ codeview::MemberFunctionRecord MemberFunc)
+ : NativeRawSymbol(Session, PDB_SymType::FunctionSig, Id),
+ MemberFunc(std::move(MemberFunc)), Index(Index), IsMemberFunction(true) {}
+
+void NativeTypeFunctionSig::initialize() {
+ if (IsMemberFunction) {
+ ClassParentId =
+ Session.getSymbolCache().findSymbolByTypeIndex(MemberFunc.ClassType);
+ initializeArgList(MemberFunc.ArgumentList);
+ } else {
+ initializeArgList(Proc.ArgumentList);
+ }
+}
+
+NativeTypeFunctionSig::~NativeTypeFunctionSig() {}
+
+void NativeTypeFunctionSig::initializeArgList(codeview::TypeIndex ArgListTI) {
+ TpiStream &Tpi = cantFail(Session.getPDBFile().getPDBTpiStream());
+ CVType CVT = Tpi.typeCollection().getType(ArgListTI);
+
+ cantFail(TypeDeserializer::deserializeAs<ArgListRecord>(CVT, ArgList));
+}
+
+void NativeTypeFunctionSig::dump(raw_ostream &OS, int Indent,
+ PdbSymbolIdField ShowIdFields,
+ PdbSymbolIdField RecurseIdFields) const {
+
+ NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
+
+ dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session,
+ PdbSymbolIdField::LexicalParent, ShowIdFields,
+ RecurseIdFields);
+
+ dumpSymbolField(OS, "callingConvention", getCallingConvention(), Indent);
+ dumpSymbolField(OS, "count", getCount(), Indent);
+ dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session,
+ PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields);
+ if (IsMemberFunction)
+ dumpSymbolField(OS, "thisAdjust", getThisAdjust(), Indent);
+ dumpSymbolField(OS, "constructor", hasConstructor(), Indent);
+ dumpSymbolField(OS, "constType", isConstType(), Indent);
+ dumpSymbolField(OS, "isConstructorVirtualBase", isConstructorVirtualBase(),
+ Indent);
+ dumpSymbolField(OS, "isCxxReturnUdt", isCxxReturnUdt(), Indent);
+ dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent);
+ dumpSymbolField(OS, "volatileType", isVolatileType(), Indent);
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+NativeTypeFunctionSig::findChildren(PDB_SymType Type) const {
+ if (Type != PDB_SymType::FunctionArg)
+ return std::make_unique<NullEnumerator<PDBSymbol>>();
+
+ auto NET = std::make_unique<NativeEnumTypes>(Session,
+ /* copy */ ArgList.ArgIndices);
+ return std::unique_ptr<IPDBEnumSymbols>(
+ new NativeEnumFunctionArgs(Session, std::move(NET)));
+}
+
+SymIndexId NativeTypeFunctionSig::getClassParentId() const {
+ if (!IsMemberFunction)
+ return 0;
+
+ return ClassParentId;
+}
+
+PDB_CallingConv NativeTypeFunctionSig::getCallingConvention() const {
+ return IsMemberFunction ? MemberFunc.CallConv : Proc.CallConv;
+}
+
+uint32_t NativeTypeFunctionSig::getCount() const {
+ return IsMemberFunction ? (1 + MemberFunc.getParameterCount())
+ : Proc.getParameterCount();
+}
+
+SymIndexId NativeTypeFunctionSig::getTypeId() const {
+ TypeIndex ReturnTI =
+ IsMemberFunction ? MemberFunc.getReturnType() : Proc.getReturnType();
+
+ SymIndexId Result = Session.getSymbolCache().findSymbolByTypeIndex(ReturnTI);
+ return Result;
+}
+
+int32_t NativeTypeFunctionSig::getThisAdjust() const {
+ return IsMemberFunction ? MemberFunc.getThisPointerAdjustment() : 0;
+}
+
+bool NativeTypeFunctionSig::hasConstructor() const {
+ if (!IsMemberFunction)
+ return false;
+
+ return (MemberFunc.getOptions() & FunctionOptions::Constructor) !=
+ FunctionOptions::None;
+}
+
+bool NativeTypeFunctionSig::isConstType() const { return false; }
+
+bool NativeTypeFunctionSig::isConstructorVirtualBase() const {
+ if (!IsMemberFunction)
+ return false;
+
+ return (MemberFunc.getOptions() &
+ FunctionOptions::ConstructorWithVirtualBases) !=
+ FunctionOptions::None;
+}
+
+bool NativeTypeFunctionSig::isCxxReturnUdt() const {
+ FunctionOptions Options =
+ IsMemberFunction ? MemberFunc.getOptions() : Proc.getOptions();
+ return (Options & FunctionOptions::CxxReturnUdt) != FunctionOptions::None;
+}
+
+bool NativeTypeFunctionSig::isUnalignedType() const { return false; }
+
+bool NativeTypeFunctionSig::isVolatileType() const { return false; }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp
new file mode 100644
index 0000000000..32dcfc2359
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypePointer.cpp
@@ -0,0 +1,193 @@
+//===- NativeTypePointer.cpp - info about pointer type ----------*- 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/PDB/Native/NativeTypePointer.h"
+
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+
+#include <cassert>
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+NativeTypePointer::NativeTypePointer(NativeSession &Session, SymIndexId Id,
+ codeview::TypeIndex TI)
+ : NativeRawSymbol(Session, PDB_SymType::PointerType, Id), TI(TI) {
+ assert(TI.isSimple());
+ assert(TI.getSimpleMode() != SimpleTypeMode::Direct);
+}
+
+NativeTypePointer::NativeTypePointer(NativeSession &Session, SymIndexId Id,
+ codeview::TypeIndex TI,
+ codeview::PointerRecord Record)
+ : NativeRawSymbol(Session, PDB_SymType::PointerType, Id), TI(TI),
+ Record(std::move(Record)) {}
+
+NativeTypePointer::~NativeTypePointer() {}
+
+void NativeTypePointer::dump(raw_ostream &OS, int Indent,
+ PdbSymbolIdField ShowIdFields,
+ PdbSymbolIdField RecurseIdFields) const {
+ NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
+
+ if (isMemberPointer()) {
+ dumpSymbolIdField(OS, "classParentId", getClassParentId(), Indent, Session,
+ PdbSymbolIdField::ClassParent, ShowIdFields,
+ RecurseIdFields);
+ }
+ dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session,
+ PdbSymbolIdField::LexicalParent, ShowIdFields,
+ RecurseIdFields);
+ dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session,
+ PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields);
+ dumpSymbolField(OS, "length", getLength(), Indent);
+ dumpSymbolField(OS, "constType", isConstType(), Indent);
+ dumpSymbolField(OS, "isPointerToDataMember", isPointerToDataMember(), Indent);
+ dumpSymbolField(OS, "isPointerToMemberFunction", isPointerToMemberFunction(),
+ Indent);
+ dumpSymbolField(OS, "RValueReference", isRValueReference(), Indent);
+ dumpSymbolField(OS, "reference", isReference(), Indent);
+ dumpSymbolField(OS, "restrictedType", isRestrictedType(), Indent);
+ if (isMemberPointer()) {
+ if (isSingleInheritance())
+ dumpSymbolField(OS, "isSingleInheritance", 1, Indent);
+ else if (isMultipleInheritance())
+ dumpSymbolField(OS, "isMultipleInheritance", 1, Indent);
+ else if (isVirtualInheritance())
+ dumpSymbolField(OS, "isVirtualInheritance", 1, Indent);
+ }
+ dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent);
+ dumpSymbolField(OS, "volatileType", isVolatileType(), Indent);
+}
+
+SymIndexId NativeTypePointer::getClassParentId() const {
+ if (!isMemberPointer())
+ return 0;
+
+ assert(Record);
+ const MemberPointerInfo &MPI = Record->getMemberInfo();
+ return Session.getSymbolCache().findSymbolByTypeIndex(MPI.ContainingType);
+}
+
+uint64_t NativeTypePointer::getLength() const {
+ if (Record)
+ return Record->getSize();
+
+ switch (TI.getSimpleMode()) {
+ case SimpleTypeMode::NearPointer:
+ case SimpleTypeMode::FarPointer:
+ case SimpleTypeMode::HugePointer:
+ return 2;
+ case SimpleTypeMode::NearPointer32:
+ case SimpleTypeMode::FarPointer32:
+ return 4;
+ case SimpleTypeMode::NearPointer64:
+ return 8;
+ case SimpleTypeMode::NearPointer128:
+ return 16;
+ default:
+ assert(false && "invalid simple type mode!");
+ }
+ return 0;
+}
+
+SymIndexId NativeTypePointer::getTypeId() const {
+ // This is the pointee SymIndexId.
+ TypeIndex Referent = Record ? Record->ReferentType : TI.makeDirect();
+
+ return Session.getSymbolCache().findSymbolByTypeIndex(Referent);
+}
+
+bool NativeTypePointer::isReference() const {
+ if (!Record)
+ return false;
+ return Record->getMode() == PointerMode::LValueReference;
+}
+
+bool NativeTypePointer::isRValueReference() const {
+ if (!Record)
+ return false;
+ return Record->getMode() == PointerMode::RValueReference;
+}
+
+bool NativeTypePointer::isPointerToDataMember() const {
+ if (!Record)
+ return false;
+ return Record->getMode() == PointerMode::PointerToDataMember;
+}
+
+bool NativeTypePointer::isPointerToMemberFunction() const {
+ if (!Record)
+ return false;
+ return Record->getMode() == PointerMode::PointerToMemberFunction;
+}
+
+bool NativeTypePointer::isConstType() const {
+ if (!Record)
+ return false;
+ return (Record->getOptions() & PointerOptions::Const) != PointerOptions::None;
+}
+
+bool NativeTypePointer::isRestrictedType() const {
+ if (!Record)
+ return false;
+ return (Record->getOptions() & PointerOptions::Restrict) !=
+ PointerOptions::None;
+}
+
+bool NativeTypePointer::isVolatileType() const {
+ if (!Record)
+ return false;
+ return (Record->getOptions() & PointerOptions::Volatile) !=
+ PointerOptions::None;
+}
+
+bool NativeTypePointer::isUnalignedType() const {
+ if (!Record)
+ return false;
+ return (Record->getOptions() & PointerOptions::Unaligned) !=
+ PointerOptions::None;
+}
+
+static inline bool isInheritanceKind(const MemberPointerInfo &MPI,
+ PointerToMemberRepresentation P1,
+ PointerToMemberRepresentation P2) {
+ return (MPI.getRepresentation() == P1 || MPI.getRepresentation() == P2);
+}
+
+bool NativeTypePointer::isSingleInheritance() const {
+ if (!isMemberPointer())
+ return false;
+ return isInheritanceKind(
+ Record->getMemberInfo(),
+ PointerToMemberRepresentation::SingleInheritanceData,
+ PointerToMemberRepresentation::SingleInheritanceFunction);
+}
+
+bool NativeTypePointer::isMultipleInheritance() const {
+ if (!isMemberPointer())
+ return false;
+ return isInheritanceKind(
+ Record->getMemberInfo(),
+ PointerToMemberRepresentation::MultipleInheritanceData,
+ PointerToMemberRepresentation::MultipleInheritanceFunction);
+}
+
+bool NativeTypePointer::isVirtualInheritance() const {
+ if (!isMemberPointer())
+ return false;
+ return isInheritanceKind(
+ Record->getMemberInfo(),
+ PointerToMemberRepresentation::VirtualInheritanceData,
+ PointerToMemberRepresentation::VirtualInheritanceFunction);
+}
+
+bool NativeTypePointer::isMemberPointer() const {
+ return isPointerToDataMember() || isPointerToMemberFunction();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeTypedef.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeTypedef.cpp
new file mode 100644
index 0000000000..72964a9e0d
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeTypedef.cpp
@@ -0,0 +1,29 @@
+#include "llvm/DebugInfo/PDB/Native/NativeTypeTypedef.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+NativeTypeTypedef::NativeTypeTypedef(NativeSession &Session, SymIndexId Id,
+ codeview::UDTSym Typedef)
+ : NativeRawSymbol(Session, PDB_SymType::Typedef, Id),
+ Record(std::move(Typedef)) {}
+
+NativeTypeTypedef::~NativeTypeTypedef() {}
+
+void NativeTypeTypedef::dump(raw_ostream &OS, int Indent,
+ PdbSymbolIdField ShowIdFields,
+ PdbSymbolIdField RecurseIdFields) const {
+ NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
+ dumpSymbolField(OS, "name", getName(), Indent);
+ dumpSymbolIdField(OS, "typeId", getTypeId(), Indent, Session,
+ PdbSymbolIdField::Type, ShowIdFields, RecurseIdFields);
+}
+
+std::string NativeTypeTypedef::getName() const {
+ return std::string(Record.Name);
+}
+
+SymIndexId NativeTypeTypedef::getTypeId() const {
+ return Session.getSymbolCache().findSymbolByTypeIndex(Record.Type);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp
new file mode 100644
index 0000000000..917ec14e58
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeUDT.cpp
@@ -0,0 +1,220 @@
+//===- NativeTypeUDT.cpp - info about class/struct type ---------*- 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/PDB/Native/NativeTypeUDT.h"
+
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+
+#include <cassert>
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id,
+ codeview::TypeIndex TI, codeview::ClassRecord CR)
+ : NativeRawSymbol(Session, PDB_SymType::UDT, Id), Index(TI),
+ Class(std::move(CR)), Tag(Class.getPointer()) {}
+
+NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id,
+ codeview::TypeIndex TI, codeview::UnionRecord UR)
+ : NativeRawSymbol(Session, PDB_SymType::UDT, Id), Index(TI),
+ Union(std::move(UR)), Tag(Union.getPointer()) {}
+
+NativeTypeUDT::NativeTypeUDT(NativeSession &Session, SymIndexId Id,
+ NativeTypeUDT &UnmodifiedType,
+ codeview::ModifierRecord Modifier)
+ : NativeRawSymbol(Session, PDB_SymType::UDT, Id),
+ UnmodifiedType(&UnmodifiedType), Modifiers(std::move(Modifier)) {}
+
+NativeTypeUDT::~NativeTypeUDT() {}
+
+void NativeTypeUDT::dump(raw_ostream &OS, int Indent,
+ PdbSymbolIdField ShowIdFields,
+ PdbSymbolIdField RecurseIdFields) const {
+
+ NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
+
+ dumpSymbolField(OS, "name", getName(), Indent);
+ dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session,
+ PdbSymbolIdField::LexicalParent, ShowIdFields,
+ RecurseIdFields);
+ if (Modifiers.hasValue())
+ dumpSymbolIdField(OS, "unmodifiedTypeId", getUnmodifiedTypeId(), Indent,
+ Session, PdbSymbolIdField::UnmodifiedType, ShowIdFields,
+ RecurseIdFields);
+ if (getUdtKind() != PDB_UdtType::Union)
+ dumpSymbolField(OS, "virtualTableShapeId", getVirtualTableShapeId(),
+ Indent);
+ dumpSymbolField(OS, "length", getLength(), Indent);
+ dumpSymbolField(OS, "udtKind", getUdtKind(), Indent);
+ dumpSymbolField(OS, "constructor", hasConstructor(), Indent);
+ dumpSymbolField(OS, "constType", isConstType(), Indent);
+ dumpSymbolField(OS, "hasAssignmentOperator", hasAssignmentOperator(), Indent);
+ dumpSymbolField(OS, "hasCastOperator", hasCastOperator(), Indent);
+ dumpSymbolField(OS, "hasNestedTypes", hasNestedTypes(), Indent);
+ dumpSymbolField(OS, "overloadedOperator", hasOverloadedOperator(), Indent);
+ dumpSymbolField(OS, "isInterfaceUdt", isInterfaceUdt(), Indent);
+ dumpSymbolField(OS, "intrinsic", isIntrinsic(), Indent);
+ dumpSymbolField(OS, "nested", isNested(), Indent);
+ dumpSymbolField(OS, "packed", isPacked(), Indent);
+ dumpSymbolField(OS, "isRefUdt", isRefUdt(), Indent);
+ dumpSymbolField(OS, "scoped", isScoped(), Indent);
+ dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent);
+ dumpSymbolField(OS, "isValueUdt", isValueUdt(), Indent);
+ dumpSymbolField(OS, "volatileType", isVolatileType(), Indent);
+}
+
+std::string NativeTypeUDT::getName() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->getName();
+
+ return std::string(Tag->getName());
+}
+
+SymIndexId NativeTypeUDT::getLexicalParentId() const { return 0; }
+
+SymIndexId NativeTypeUDT::getUnmodifiedTypeId() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->getSymIndexId();
+
+ return 0;
+}
+
+SymIndexId NativeTypeUDT::getVirtualTableShapeId() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->getVirtualTableShapeId();
+
+ if (Class)
+ return Session.getSymbolCache().findSymbolByTypeIndex(Class->VTableShape);
+
+ return 0;
+}
+
+uint64_t NativeTypeUDT::getLength() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->getLength();
+
+ if (Class)
+ return Class->getSize();
+
+ return Union->getSize();
+}
+
+PDB_UdtType NativeTypeUDT::getUdtKind() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->getUdtKind();
+
+ switch (Tag->Kind) {
+ case TypeRecordKind::Class:
+ return PDB_UdtType::Class;
+ case TypeRecordKind::Union:
+ return PDB_UdtType::Union;
+ case TypeRecordKind::Struct:
+ return PDB_UdtType::Struct;
+ case TypeRecordKind::Interface:
+ return PDB_UdtType::Interface;
+ default:
+ llvm_unreachable("Unexpected udt kind");
+ }
+}
+
+bool NativeTypeUDT::hasConstructor() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->hasConstructor();
+
+ return (Tag->Options & ClassOptions::HasConstructorOrDestructor) !=
+ ClassOptions::None;
+}
+
+bool NativeTypeUDT::isConstType() const {
+ if (!Modifiers)
+ return false;
+ return (Modifiers->Modifiers & ModifierOptions::Const) !=
+ ModifierOptions::None;
+}
+
+bool NativeTypeUDT::hasAssignmentOperator() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->hasAssignmentOperator();
+
+ return (Tag->Options & ClassOptions::HasOverloadedAssignmentOperator) !=
+ ClassOptions::None;
+}
+
+bool NativeTypeUDT::hasCastOperator() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->hasCastOperator();
+
+ return (Tag->Options & ClassOptions::HasConversionOperator) !=
+ ClassOptions::None;
+}
+
+bool NativeTypeUDT::hasNestedTypes() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->hasNestedTypes();
+
+ return (Tag->Options & ClassOptions::ContainsNestedClass) !=
+ ClassOptions::None;
+}
+
+bool NativeTypeUDT::hasOverloadedOperator() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->hasOverloadedOperator();
+
+ return (Tag->Options & ClassOptions::HasOverloadedOperator) !=
+ ClassOptions::None;
+}
+
+bool NativeTypeUDT::isInterfaceUdt() const { return false; }
+
+bool NativeTypeUDT::isIntrinsic() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->isIntrinsic();
+
+ return (Tag->Options & ClassOptions::Intrinsic) != ClassOptions::None;
+}
+
+bool NativeTypeUDT::isNested() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->isNested();
+
+ return (Tag->Options & ClassOptions::Nested) != ClassOptions::None;
+}
+
+bool NativeTypeUDT::isPacked() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->isPacked();
+
+ return (Tag->Options & ClassOptions::Packed) != ClassOptions::None;
+}
+
+bool NativeTypeUDT::isRefUdt() const { return false; }
+
+bool NativeTypeUDT::isScoped() const {
+ if (UnmodifiedType)
+ return UnmodifiedType->isScoped();
+
+ return (Tag->Options & ClassOptions::Scoped) != ClassOptions::None;
+}
+
+bool NativeTypeUDT::isValueUdt() const { return false; }
+
+bool NativeTypeUDT::isUnalignedType() const {
+ if (!Modifiers)
+ return false;
+ return (Modifiers->Modifiers & ModifierOptions::Unaligned) !=
+ ModifierOptions::None;
+}
+
+bool NativeTypeUDT::isVolatileType() const {
+ if (!Modifiers)
+ return false;
+ return (Modifiers->Modifiers & ModifierOptions::Volatile) !=
+ ModifierOptions::None;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeVTShape.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeVTShape.cpp
new file mode 100644
index 0000000000..837fe19ec8
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/NativeTypeVTShape.cpp
@@ -0,0 +1,35 @@
+#include "llvm/DebugInfo/PDB/Native/NativeTypeVTShape.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+// Create a pointer record for a non-simple type.
+NativeTypeVTShape::NativeTypeVTShape(NativeSession &Session, SymIndexId Id,
+ codeview::TypeIndex TI,
+ codeview::VFTableShapeRecord SR)
+ : NativeRawSymbol(Session, PDB_SymType::VTableShape, Id), TI(TI),
+ Record(std::move(SR)) {}
+
+NativeTypeVTShape::~NativeTypeVTShape() {}
+
+void NativeTypeVTShape::dump(raw_ostream &OS, int Indent,
+ PdbSymbolIdField ShowIdFields,
+ PdbSymbolIdField RecurseIdFields) const {
+ NativeRawSymbol::dump(OS, Indent, ShowIdFields, RecurseIdFields);
+
+ dumpSymbolIdField(OS, "lexicalParentId", 0, Indent, Session,
+ PdbSymbolIdField::LexicalParent, ShowIdFields,
+ RecurseIdFields);
+ dumpSymbolField(OS, "count", getCount(), Indent);
+ dumpSymbolField(OS, "constType", isConstType(), Indent);
+ dumpSymbolField(OS, "unalignedType", isUnalignedType(), Indent);
+ dumpSymbolField(OS, "volatileType", isVolatileType(), Indent);
+}
+
+bool NativeTypeVTShape::isConstType() const { return false; }
+
+bool NativeTypeVTShape::isVolatileType() const { return false; }
+
+bool NativeTypeVTShape::isUnalignedType() const { return false; }
+
+uint32_t NativeTypeVTShape::getCount() const { return Record.Slots.size(); }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PDBFile.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PDBFile.cpp
new file mode 100644
index 0000000000..5c61530c47
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PDBFile.cpp
@@ -0,0 +1,508 @@
+//===- PDBFile.cpp - Low level interface to a PDB file ----------*- 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/PDB/Native/PDBFile.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/MSF/MSFCommon.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/InjectedSourceStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBStringTable.h"
+#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/Support/BinaryStream.h"
+#include "llvm/Support/BinaryStreamArray.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/Path.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+namespace {
+typedef FixedStreamArray<support::ulittle32_t> ulittle_array;
+} // end anonymous namespace
+
+PDBFile::PDBFile(StringRef Path, std::unique_ptr<BinaryStream> PdbFileBuffer,
+ BumpPtrAllocator &Allocator)
+ : FilePath(std::string(Path)), Allocator(Allocator),
+ Buffer(std::move(PdbFileBuffer)) {}
+
+PDBFile::~PDBFile() = default;
+
+StringRef PDBFile::getFilePath() const { return FilePath; }
+
+StringRef PDBFile::getFileDirectory() const {
+ return sys::path::parent_path(FilePath);
+}
+
+uint32_t PDBFile::getBlockSize() const { return ContainerLayout.SB->BlockSize; }
+
+uint32_t PDBFile::getFreeBlockMapBlock() const {
+ return ContainerLayout.SB->FreeBlockMapBlock;
+}
+
+uint32_t PDBFile::getBlockCount() const {
+ return ContainerLayout.SB->NumBlocks;
+}
+
+uint32_t PDBFile::getNumDirectoryBytes() const {
+ return ContainerLayout.SB->NumDirectoryBytes;
+}
+
+uint32_t PDBFile::getBlockMapIndex() const {
+ return ContainerLayout.SB->BlockMapAddr;
+}
+
+uint32_t PDBFile::getUnknown1() const { return ContainerLayout.SB->Unknown1; }
+
+uint32_t PDBFile::getNumDirectoryBlocks() const {
+ return msf::bytesToBlocks(ContainerLayout.SB->NumDirectoryBytes,
+ ContainerLayout.SB->BlockSize);
+}
+
+uint64_t PDBFile::getBlockMapOffset() const {
+ return (uint64_t)ContainerLayout.SB->BlockMapAddr *
+ ContainerLayout.SB->BlockSize;
+}
+
+uint32_t PDBFile::getNumStreams() const {
+ return ContainerLayout.StreamSizes.size();
+}
+
+uint32_t PDBFile::getMaxStreamSize() const {
+ return *std::max_element(ContainerLayout.StreamSizes.begin(),
+ ContainerLayout.StreamSizes.end());
+}
+
+uint32_t PDBFile::getStreamByteSize(uint32_t StreamIndex) const {
+ return ContainerLayout.StreamSizes[StreamIndex];
+}
+
+ArrayRef<support::ulittle32_t>
+PDBFile::getStreamBlockList(uint32_t StreamIndex) const {
+ return ContainerLayout.StreamMap[StreamIndex];
+}
+
+uint64_t PDBFile::getFileSize() const { return Buffer->getLength(); }
+
+Expected<ArrayRef<uint8_t>> PDBFile::getBlockData(uint32_t BlockIndex,
+ uint32_t NumBytes) const {
+ uint64_t StreamBlockOffset = msf::blockToOffset(BlockIndex, getBlockSize());
+
+ ArrayRef<uint8_t> Result;
+ if (auto EC = Buffer->readBytes(StreamBlockOffset, NumBytes, Result))
+ return std::move(EC);
+ return Result;
+}
+
+Error PDBFile::setBlockData(uint32_t BlockIndex, uint32_t Offset,
+ ArrayRef<uint8_t> Data) const {
+ return make_error<RawError>(raw_error_code::not_writable,
+ "PDBFile is immutable");
+}
+
+Error PDBFile::parseFileHeaders() {
+ BinaryStreamReader Reader(*Buffer);
+
+ // Initialize SB.
+ const msf::SuperBlock *SB = nullptr;
+ if (auto EC = Reader.readObject(SB)) {
+ consumeError(std::move(EC));
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "MSF superblock is missing");
+ }
+
+ if (auto EC = msf::validateSuperBlock(*SB))
+ return EC;
+
+ if (Buffer->getLength() % SB->BlockSize != 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "File size is not a multiple of block size");
+ ContainerLayout.SB = SB;
+
+ // Initialize Free Page Map.
+ ContainerLayout.FreePageMap.resize(SB->NumBlocks);
+ // The Fpm exists either at block 1 or block 2 of the MSF. However, this
+ // allows for a maximum of getBlockSize() * 8 blocks bits in the Fpm, and
+ // thusly an equal number of total blocks in the file. For a block size
+ // of 4KiB (very common), this would yield 32KiB total blocks in file, for a
+ // maximum file size of 32KiB * 4KiB = 128MiB. Obviously this won't do, so
+ // the Fpm is split across the file at `getBlockSize()` intervals. As a
+ // result, every block whose index is of the form |{1,2} + getBlockSize() * k|
+ // for any non-negative integer k is an Fpm block. In theory, we only really
+ // need to reserve blocks of the form |{1,2} + getBlockSize() * 8 * k|, but
+ // current versions of the MSF format already expect the Fpm to be arranged
+ // at getBlockSize() intervals, so we have to be compatible.
+ // See the function fpmPn() for more information:
+ // https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/msf/msf.cpp#L489
+ auto FpmStream =
+ MappedBlockStream::createFpmStream(ContainerLayout, *Buffer, Allocator);
+ BinaryStreamReader FpmReader(*FpmStream);
+ ArrayRef<uint8_t> FpmBytes;
+ if (auto EC = FpmReader.readBytes(FpmBytes, FpmReader.bytesRemaining()))
+ return EC;
+ uint32_t BlocksRemaining = getBlockCount();
+ uint32_t BI = 0;
+ for (auto Byte : FpmBytes) {
+ uint32_t BlocksThisByte = std::min(BlocksRemaining, 8U);
+ for (uint32_t I = 0; I < BlocksThisByte; ++I) {
+ if (Byte & (1 << I))
+ ContainerLayout.FreePageMap[BI] = true;
+ --BlocksRemaining;
+ ++BI;
+ }
+ }
+
+ Reader.setOffset(getBlockMapOffset());
+ if (auto EC = Reader.readArray(ContainerLayout.DirectoryBlocks,
+ getNumDirectoryBlocks()))
+ return EC;
+
+ return Error::success();
+}
+
+Error PDBFile::parseStreamData() {
+ assert(ContainerLayout.SB);
+ if (DirectoryStream)
+ return Error::success();
+
+ uint32_t NumStreams = 0;
+
+ // Normally you can't use a MappedBlockStream without having fully parsed the
+ // PDB file, because it accesses the directory and various other things, which
+ // is exactly what we are attempting to parse. By specifying a custom
+ // subclass of IPDBStreamData which only accesses the fields that have already
+ // been parsed, we can avoid this and reuse MappedBlockStream.
+ auto DS = MappedBlockStream::createDirectoryStream(ContainerLayout, *Buffer,
+ Allocator);
+ BinaryStreamReader Reader(*DS);
+ if (auto EC = Reader.readInteger(NumStreams))
+ return EC;
+
+ if (auto EC = Reader.readArray(ContainerLayout.StreamSizes, NumStreams))
+ return EC;
+ for (uint32_t I = 0; I < NumStreams; ++I) {
+ uint32_t StreamSize = getStreamByteSize(I);
+ // FIXME: What does StreamSize ~0U mean?
+ uint64_t NumExpectedStreamBlocks =
+ StreamSize == UINT32_MAX
+ ? 0
+ : msf::bytesToBlocks(StreamSize, ContainerLayout.SB->BlockSize);
+
+ // For convenience, we store the block array contiguously. This is because
+ // if someone calls setStreamMap(), it is more convenient to be able to call
+ // it with an ArrayRef instead of setting up a StreamRef. Since the
+ // DirectoryStream is cached in the class and thus lives for the life of the
+ // class, we can be guaranteed that readArray() will return a stable
+ // reference, even if it has to allocate from its internal pool.
+ ArrayRef<support::ulittle32_t> Blocks;
+ if (auto EC = Reader.readArray(Blocks, NumExpectedStreamBlocks))
+ return EC;
+ for (uint32_t Block : Blocks) {
+ uint64_t BlockEndOffset =
+ (uint64_t)(Block + 1) * ContainerLayout.SB->BlockSize;
+ if (BlockEndOffset > getFileSize())
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Stream block map is corrupt.");
+ }
+ ContainerLayout.StreamMap.push_back(Blocks);
+ }
+
+ // We should have read exactly SB->NumDirectoryBytes bytes.
+ assert(Reader.bytesRemaining() == 0);
+ DirectoryStream = std::move(DS);
+ return Error::success();
+}
+
+ArrayRef<support::ulittle32_t> PDBFile::getDirectoryBlockArray() const {
+ return ContainerLayout.DirectoryBlocks;
+}
+
+std::unique_ptr<MappedBlockStream>
+PDBFile::createIndexedStream(uint16_t SN) const {
+ if (SN == kInvalidStreamIndex)
+ return nullptr;
+ return MappedBlockStream::createIndexedStream(ContainerLayout, *Buffer, SN,
+ Allocator);
+}
+
+MSFStreamLayout PDBFile::getStreamLayout(uint32_t StreamIdx) const {
+ MSFStreamLayout Result;
+ auto Blocks = getStreamBlockList(StreamIdx);
+ Result.Blocks.assign(Blocks.begin(), Blocks.end());
+ Result.Length = getStreamByteSize(StreamIdx);
+ return Result;
+}
+
+msf::MSFStreamLayout PDBFile::getFpmStreamLayout() const {
+ return msf::getFpmStreamLayout(ContainerLayout);
+}
+
+Expected<GlobalsStream &> PDBFile::getPDBGlobalsStream() {
+ if (!Globals) {
+ auto DbiS = getPDBDbiStream();
+ if (!DbiS)
+ return DbiS.takeError();
+
+ auto GlobalS =
+ safelyCreateIndexedStream(DbiS->getGlobalSymbolStreamIndex());
+ if (!GlobalS)
+ return GlobalS.takeError();
+ auto TempGlobals = std::make_unique<GlobalsStream>(std::move(*GlobalS));
+ if (auto EC = TempGlobals->reload())
+ return std::move(EC);
+ Globals = std::move(TempGlobals);
+ }
+ return *Globals;
+}
+
+Expected<InfoStream &> PDBFile::getPDBInfoStream() {
+ if (!Info) {
+ auto InfoS = safelyCreateIndexedStream(StreamPDB);
+ if (!InfoS)
+ return InfoS.takeError();
+ auto TempInfo = std::make_unique<InfoStream>(std::move(*InfoS));
+ if (auto EC = TempInfo->reload())
+ return std::move(EC);
+ Info = std::move(TempInfo);
+ }
+ return *Info;
+}
+
+Expected<DbiStream &> PDBFile::getPDBDbiStream() {
+ if (!Dbi) {
+ auto DbiS = safelyCreateIndexedStream(StreamDBI);
+ if (!DbiS)
+ return DbiS.takeError();
+ auto TempDbi = std::make_unique<DbiStream>(std::move(*DbiS));
+ if (auto EC = TempDbi->reload(this))
+ return std::move(EC);
+ Dbi = std::move(TempDbi);
+ }
+ return *Dbi;
+}
+
+Expected<TpiStream &> PDBFile::getPDBTpiStream() {
+ if (!Tpi) {
+ auto TpiS = safelyCreateIndexedStream(StreamTPI);
+ if (!TpiS)
+ return TpiS.takeError();
+ auto TempTpi = std::make_unique<TpiStream>(*this, std::move(*TpiS));
+ if (auto EC = TempTpi->reload())
+ return std::move(EC);
+ Tpi = std::move(TempTpi);
+ }
+ return *Tpi;
+}
+
+Expected<TpiStream &> PDBFile::getPDBIpiStream() {
+ if (!Ipi) {
+ if (!hasPDBIpiStream())
+ return make_error<RawError>(raw_error_code::no_stream);
+
+ auto IpiS = safelyCreateIndexedStream(StreamIPI);
+ if (!IpiS)
+ return IpiS.takeError();
+ auto TempIpi = std::make_unique<TpiStream>(*this, std::move(*IpiS));
+ if (auto EC = TempIpi->reload())
+ return std::move(EC);
+ Ipi = std::move(TempIpi);
+ }
+ return *Ipi;
+}
+
+Expected<PublicsStream &> PDBFile::getPDBPublicsStream() {
+ if (!Publics) {
+ auto DbiS = getPDBDbiStream();
+ if (!DbiS)
+ return DbiS.takeError();
+
+ auto PublicS =
+ safelyCreateIndexedStream(DbiS->getPublicSymbolStreamIndex());
+ if (!PublicS)
+ return PublicS.takeError();
+ auto TempPublics = std::make_unique<PublicsStream>(std::move(*PublicS));
+ if (auto EC = TempPublics->reload())
+ return std::move(EC);
+ Publics = std::move(TempPublics);
+ }
+ return *Publics;
+}
+
+Expected<SymbolStream &> PDBFile::getPDBSymbolStream() {
+ if (!Symbols) {
+ auto DbiS = getPDBDbiStream();
+ if (!DbiS)
+ return DbiS.takeError();
+
+ uint32_t SymbolStreamNum = DbiS->getSymRecordStreamIndex();
+ auto SymbolS = safelyCreateIndexedStream(SymbolStreamNum);
+ if (!SymbolS)
+ return SymbolS.takeError();
+
+ auto TempSymbols = std::make_unique<SymbolStream>(std::move(*SymbolS));
+ if (auto EC = TempSymbols->reload())
+ return std::move(EC);
+ Symbols = std::move(TempSymbols);
+ }
+ return *Symbols;
+}
+
+Expected<PDBStringTable &> PDBFile::getStringTable() {
+ if (!Strings) {
+ auto NS = safelyCreateNamedStream("/names");
+ if (!NS)
+ return NS.takeError();
+
+ auto N = std::make_unique<PDBStringTable>();
+ BinaryStreamReader Reader(**NS);
+ if (auto EC = N->reload(Reader))
+ return std::move(EC);
+ assert(Reader.bytesRemaining() == 0);
+ StringTableStream = std::move(*NS);
+ Strings = std::move(N);
+ }
+ return *Strings;
+}
+
+Expected<InjectedSourceStream &> PDBFile::getInjectedSourceStream() {
+ if (!InjectedSources) {
+ auto IJS = safelyCreateNamedStream("/src/headerblock");
+ if (!IJS)
+ return IJS.takeError();
+
+ auto Strings = getStringTable();
+ if (!Strings)
+ return Strings.takeError();
+
+ auto IJ = std::make_unique<InjectedSourceStream>(std::move(*IJS));
+ if (auto EC = IJ->reload(*Strings))
+ return std::move(EC);
+ InjectedSources = std::move(IJ);
+ }
+ return *InjectedSources;
+}
+
+uint32_t PDBFile::getPointerSize() {
+ auto DbiS = getPDBDbiStream();
+ if (!DbiS)
+ return 0;
+ PDB_Machine Machine = DbiS->getMachineType();
+ if (Machine == PDB_Machine::Amd64)
+ return 8;
+ return 4;
+}
+
+bool PDBFile::hasPDBDbiStream() const {
+ return StreamDBI < getNumStreams() && getStreamByteSize(StreamDBI) > 0;
+}
+
+bool PDBFile::hasPDBGlobalsStream() {
+ auto DbiS = getPDBDbiStream();
+ if (!DbiS) {
+ consumeError(DbiS.takeError());
+ return false;
+ }
+
+ return DbiS->getGlobalSymbolStreamIndex() < getNumStreams();
+}
+
+bool PDBFile::hasPDBInfoStream() const { return StreamPDB < getNumStreams(); }
+
+bool PDBFile::hasPDBIpiStream() const {
+ if (!hasPDBInfoStream())
+ return false;
+
+ if (StreamIPI >= getNumStreams())
+ return false;
+
+ auto &InfoStream = cantFail(const_cast<PDBFile *>(this)->getPDBInfoStream());
+ return InfoStream.containsIdStream();
+}
+
+bool PDBFile::hasPDBPublicsStream() {
+ auto DbiS = getPDBDbiStream();
+ if (!DbiS) {
+ consumeError(DbiS.takeError());
+ return false;
+ }
+ return DbiS->getPublicSymbolStreamIndex() < getNumStreams();
+}
+
+bool PDBFile::hasPDBSymbolStream() {
+ auto DbiS = getPDBDbiStream();
+ if (!DbiS)
+ return false;
+ return DbiS->getSymRecordStreamIndex() < getNumStreams();
+}
+
+bool PDBFile::hasPDBTpiStream() const { return StreamTPI < getNumStreams(); }
+
+bool PDBFile::hasPDBStringTable() {
+ auto IS = getPDBInfoStream();
+ if (!IS)
+ return false;
+ Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/names");
+ if (!ExpectedNSI) {
+ consumeError(ExpectedNSI.takeError());
+ return false;
+ }
+ assert(*ExpectedNSI < getNumStreams());
+ return true;
+}
+
+bool PDBFile::hasPDBInjectedSourceStream() {
+ auto IS = getPDBInfoStream();
+ if (!IS)
+ return false;
+ Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex("/src/headerblock");
+ if (!ExpectedNSI) {
+ consumeError(ExpectedNSI.takeError());
+ return false;
+ }
+ assert(*ExpectedNSI < getNumStreams());
+ return true;
+}
+
+/// Wrapper around MappedBlockStream::createIndexedStream() that checks if a
+/// stream with that index actually exists. If it does not, the return value
+/// will have an MSFError with code msf_error_code::no_stream. Else, the return
+/// value will contain the stream returned by createIndexedStream().
+Expected<std::unique_ptr<MappedBlockStream>>
+PDBFile::safelyCreateIndexedStream(uint32_t StreamIndex) const {
+ if (StreamIndex >= getNumStreams())
+ // This rejects kInvalidStreamIndex with an error as well.
+ return make_error<RawError>(raw_error_code::no_stream);
+ return createIndexedStream(StreamIndex);
+}
+
+Expected<std::unique_ptr<MappedBlockStream>>
+PDBFile::safelyCreateNamedStream(StringRef Name) {
+ auto IS = getPDBInfoStream();
+ if (!IS)
+ return IS.takeError();
+
+ Expected<uint32_t> ExpectedNSI = IS->getNamedStreamIndex(Name);
+ if (!ExpectedNSI)
+ return ExpectedNSI.takeError();
+ uint32_t NameStreamIndex = *ExpectedNSI;
+
+ return safelyCreateIndexedStream(NameStreamIndex);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
new file mode 100644
index 0000000000..f33125474e
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PDBFileBuilder.cpp
@@ -0,0 +1,355 @@
+//===- PDBFileBuilder.cpp - PDB File Creation -------------------*- 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/PDB/Native/PDBFileBuilder.h"
+#include "llvm/DebugInfo/MSF/MSFBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/GSIStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStream.h"
+#include "llvm/DebugInfo/PDB/Native/InfoStreamBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/PDBStringTableBuilder.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStreamBuilder.h"
+#include "llvm/Support/BinaryStream.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/CRC.h"
+#include "llvm/Support/Chrono.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/xxhash.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+using namespace llvm::support;
+
+PDBFileBuilder::PDBFileBuilder(BumpPtrAllocator &Allocator)
+ : Allocator(Allocator), InjectedSourceHashTraits(Strings),
+ InjectedSourceTable(2) {}
+
+PDBFileBuilder::~PDBFileBuilder() {}
+
+Error PDBFileBuilder::initialize(uint32_t BlockSize) {
+ auto ExpectedMsf = MSFBuilder::create(Allocator, BlockSize);
+ if (!ExpectedMsf)
+ return ExpectedMsf.takeError();
+ Msf = std::make_unique<MSFBuilder>(std::move(*ExpectedMsf));
+ return Error::success();
+}
+
+MSFBuilder &PDBFileBuilder::getMsfBuilder() { return *Msf; }
+
+InfoStreamBuilder &PDBFileBuilder::getInfoBuilder() {
+ if (!Info)
+ Info = std::make_unique<InfoStreamBuilder>(*Msf, NamedStreams);
+ return *Info;
+}
+
+DbiStreamBuilder &PDBFileBuilder::getDbiBuilder() {
+ if (!Dbi)
+ Dbi = std::make_unique<DbiStreamBuilder>(*Msf);
+ return *Dbi;
+}
+
+TpiStreamBuilder &PDBFileBuilder::getTpiBuilder() {
+ if (!Tpi)
+ Tpi = std::make_unique<TpiStreamBuilder>(*Msf, StreamTPI);
+ return *Tpi;
+}
+
+TpiStreamBuilder &PDBFileBuilder::getIpiBuilder() {
+ if (!Ipi)
+ Ipi = std::make_unique<TpiStreamBuilder>(*Msf, StreamIPI);
+ return *Ipi;
+}
+
+PDBStringTableBuilder &PDBFileBuilder::getStringTableBuilder() {
+ return Strings;
+}
+
+GSIStreamBuilder &PDBFileBuilder::getGsiBuilder() {
+ if (!Gsi)
+ Gsi = std::make_unique<GSIStreamBuilder>(*Msf);
+ return *Gsi;
+}
+
+Expected<uint32_t> PDBFileBuilder::allocateNamedStream(StringRef Name,
+ uint32_t Size) {
+ auto ExpectedStream = Msf->addStream(Size);
+ if (ExpectedStream)
+ NamedStreams.set(Name, *ExpectedStream);
+ return ExpectedStream;
+}
+
+Error PDBFileBuilder::addNamedStream(StringRef Name, StringRef Data) {
+ Expected<uint32_t> ExpectedIndex = allocateNamedStream(Name, Data.size());
+ if (!ExpectedIndex)
+ return ExpectedIndex.takeError();
+ assert(NamedStreamData.count(*ExpectedIndex) == 0);
+ NamedStreamData[*ExpectedIndex] = std::string(Data);
+ return Error::success();
+}
+
+void PDBFileBuilder::addInjectedSource(StringRef Name,
+ std::unique_ptr<MemoryBuffer> Buffer) {
+ // Stream names must be exact matches, since they get looked up in a hash
+ // table and the hash value is dependent on the exact contents of the string.
+ // link.exe lowercases a path and converts / to \, so we must do the same.
+ SmallString<64> VName;
+ sys::path::native(Name.lower(), VName, sys::path::Style::windows_backslash);
+
+ uint32_t NI = getStringTableBuilder().insert(Name);
+ uint32_t VNI = getStringTableBuilder().insert(VName);
+
+ InjectedSourceDescriptor Desc;
+ Desc.Content = std::move(Buffer);
+ Desc.NameIndex = NI;
+ Desc.VNameIndex = VNI;
+ Desc.StreamName = "/src/files/";
+
+ Desc.StreamName += VName;
+
+ InjectedSources.push_back(std::move(Desc));
+}
+
+Error PDBFileBuilder::finalizeMsfLayout() {
+
+ if (Ipi && Ipi->getRecordCount() > 0) {
+ // In theory newer PDBs always have an ID stream, but by saying that we're
+ // only going to *really* have an ID stream if there is at least one ID
+ // record, we leave open the opportunity to test older PDBs such as those
+ // that don't have an ID stream.
+ auto &Info = getInfoBuilder();
+ Info.addFeature(PdbRaw_FeatureSig::VC140);
+ }
+
+ uint32_t StringsLen = Strings.calculateSerializedSize();
+
+ Expected<uint32_t> SN = allocateNamedStream("/LinkInfo", 0);
+ if (!SN)
+ return SN.takeError();
+
+ if (Gsi) {
+ if (auto EC = Gsi->finalizeMsfLayout())
+ return EC;
+ if (Dbi) {
+ Dbi->setPublicsStreamIndex(Gsi->getPublicsStreamIndex());
+ Dbi->setGlobalsStreamIndex(Gsi->getGlobalsStreamIndex());
+ Dbi->setSymbolRecordStreamIndex(Gsi->getRecordStreamIndex());
+ }
+ }
+ if (Tpi) {
+ if (auto EC = Tpi->finalizeMsfLayout())
+ return EC;
+ }
+ if (Dbi) {
+ if (auto EC = Dbi->finalizeMsfLayout())
+ return EC;
+ }
+ SN = allocateNamedStream("/names", StringsLen);
+ if (!SN)
+ return SN.takeError();
+
+ if (Ipi) {
+ if (auto EC = Ipi->finalizeMsfLayout())
+ return EC;
+ }
+
+ // Do this last, since it relies on the named stream map being complete, and
+ // that can be updated by previous steps in the finalization.
+ if (Info) {
+ if (auto EC = Info->finalizeMsfLayout())
+ return EC;
+ }
+
+ if (!InjectedSources.empty()) {
+ for (const auto &IS : InjectedSources) {
+ JamCRC CRC(0);
+ CRC.update(arrayRefFromStringRef(IS.Content->getBuffer()));
+
+ SrcHeaderBlockEntry Entry;
+ ::memset(&Entry, 0, sizeof(SrcHeaderBlockEntry));
+ Entry.Size = sizeof(SrcHeaderBlockEntry);
+ Entry.FileSize = IS.Content->getBufferSize();
+ Entry.FileNI = IS.NameIndex;
+ Entry.VFileNI = IS.VNameIndex;
+ Entry.ObjNI = 1;
+ Entry.IsVirtual = 0;
+ Entry.Version =
+ static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
+ Entry.CRC = CRC.getCRC();
+ StringRef VName = getStringTableBuilder().getStringForId(IS.VNameIndex);
+ InjectedSourceTable.set_as(VName, std::move(Entry),
+ InjectedSourceHashTraits);
+ }
+
+ uint32_t SrcHeaderBlockSize =
+ sizeof(SrcHeaderBlockHeader) +
+ InjectedSourceTable.calculateSerializedLength();
+ SN = allocateNamedStream("/src/headerblock", SrcHeaderBlockSize);
+ if (!SN)
+ return SN.takeError();
+ for (const auto &IS : InjectedSources) {
+ SN = allocateNamedStream(IS.StreamName, IS.Content->getBufferSize());
+ if (!SN)
+ return SN.takeError();
+ }
+ }
+
+ // Do this last, since it relies on the named stream map being complete, and
+ // that can be updated by previous steps in the finalization.
+ if (Info) {
+ if (auto EC = Info->finalizeMsfLayout())
+ return EC;
+ }
+
+ return Error::success();
+}
+
+Expected<uint32_t> PDBFileBuilder::getNamedStreamIndex(StringRef Name) const {
+ uint32_t SN = 0;
+ if (!NamedStreams.get(Name, SN))
+ return llvm::make_error<pdb::RawError>(raw_error_code::no_stream);
+ return SN;
+}
+
+void PDBFileBuilder::commitSrcHeaderBlock(WritableBinaryStream &MsfBuffer,
+ const msf::MSFLayout &Layout) {
+ assert(!InjectedSourceTable.empty());
+
+ uint32_t SN = cantFail(getNamedStreamIndex("/src/headerblock"));
+ auto Stream = WritableMappedBlockStream::createIndexedStream(
+ Layout, MsfBuffer, SN, Allocator);
+ BinaryStreamWriter Writer(*Stream);
+
+ SrcHeaderBlockHeader Header;
+ ::memset(&Header, 0, sizeof(Header));
+ Header.Version = static_cast<uint32_t>(PdbRaw_SrcHeaderBlockVer::SrcVerOne);
+ Header.Size = Writer.bytesRemaining();
+
+ cantFail(Writer.writeObject(Header));
+ cantFail(InjectedSourceTable.commit(Writer));
+
+ assert(Writer.bytesRemaining() == 0);
+}
+
+void PDBFileBuilder::commitInjectedSources(WritableBinaryStream &MsfBuffer,
+ const msf::MSFLayout &Layout) {
+ if (InjectedSourceTable.empty())
+ return;
+
+ commitSrcHeaderBlock(MsfBuffer, Layout);
+
+ for (const auto &IS : InjectedSources) {
+ uint32_t SN = cantFail(getNamedStreamIndex(IS.StreamName));
+
+ auto SourceStream = WritableMappedBlockStream::createIndexedStream(
+ Layout, MsfBuffer, SN, Allocator);
+ BinaryStreamWriter SourceWriter(*SourceStream);
+ assert(SourceWriter.bytesRemaining() == IS.Content->getBufferSize());
+ cantFail(SourceWriter.writeBytes(
+ arrayRefFromStringRef(IS.Content->getBuffer())));
+ }
+}
+
+Error PDBFileBuilder::commit(StringRef Filename, codeview::GUID *Guid) {
+ assert(!Filename.empty());
+ if (auto EC = finalizeMsfLayout())
+ return EC;
+
+ MSFLayout Layout;
+ Expected<FileBufferByteStream> ExpectedMsfBuffer =
+ Msf->commit(Filename, Layout);
+ if (!ExpectedMsfBuffer)
+ return ExpectedMsfBuffer.takeError();
+ FileBufferByteStream Buffer = std::move(*ExpectedMsfBuffer);
+
+ auto ExpectedSN = getNamedStreamIndex("/names");
+ if (!ExpectedSN)
+ return ExpectedSN.takeError();
+
+ auto NS = WritableMappedBlockStream::createIndexedStream(
+ Layout, Buffer, *ExpectedSN, Allocator);
+ BinaryStreamWriter NSWriter(*NS);
+ if (auto EC = Strings.commit(NSWriter))
+ return EC;
+
+ for (const auto &NSE : NamedStreamData) {
+ if (NSE.second.empty())
+ continue;
+
+ auto NS = WritableMappedBlockStream::createIndexedStream(
+ Layout, Buffer, NSE.first, Allocator);
+ BinaryStreamWriter NSW(*NS);
+ if (auto EC = NSW.writeBytes(arrayRefFromStringRef(NSE.second)))
+ return EC;
+ }
+
+ if (Info) {
+ if (auto EC = Info->commit(Layout, Buffer))
+ return EC;
+ }
+
+ if (Dbi) {
+ if (auto EC = Dbi->commit(Layout, Buffer))
+ return EC;
+ }
+
+ if (Tpi) {
+ if (auto EC = Tpi->commit(Layout, Buffer))
+ return EC;
+ }
+
+ if (Ipi) {
+ if (auto EC = Ipi->commit(Layout, Buffer))
+ return EC;
+ }
+
+ if (Gsi) {
+ if (auto EC = Gsi->commit(Layout, Buffer))
+ return EC;
+ }
+
+ auto InfoStreamBlocks = Layout.StreamMap[StreamPDB];
+ assert(!InfoStreamBlocks.empty());
+ uint64_t InfoStreamFileOffset =
+ blockToOffset(InfoStreamBlocks.front(), Layout.SB->BlockSize);
+ InfoStreamHeader *H = reinterpret_cast<InfoStreamHeader *>(
+ Buffer.getBufferStart() + InfoStreamFileOffset);
+
+ commitInjectedSources(Buffer, Layout);
+
+ // Set the build id at the very end, after every other byte of the PDB
+ // has been written.
+ if (Info->hashPDBContentsToGUID()) {
+ // Compute a hash of all sections of the output file.
+ uint64_t Digest =
+ xxHash64({Buffer.getBufferStart(), Buffer.getBufferEnd()});
+
+ H->Age = 1;
+
+ memcpy(H->Guid.Guid, &Digest, 8);
+ // xxhash only gives us 8 bytes, so put some fixed data in the other half.
+ memcpy(H->Guid.Guid + 8, "LLD PDB.", 8);
+
+ // Put the hash in the Signature field too.
+ H->Signature = static_cast<uint32_t>(Digest);
+
+ // Return GUID to caller.
+ memcpy(Guid, H->Guid.Guid, 16);
+ } else {
+ H->Age = Info->getAge();
+ H->Guid = Info->getGuid();
+ Optional<uint32_t> Sig = Info->getSignature();
+ H->Signature = Sig.hasValue() ? *Sig : time(nullptr);
+ }
+
+ return Buffer.commit();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PDBStringTable.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PDBStringTable.cpp
new file mode 100644
index 0000000000..2be1656e06
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PDBStringTable.cpp
@@ -0,0 +1,140 @@
+//===- PDBStringTable.cpp - PDB String Table ---------------------*- 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/PDB/Native/PDBStringTable.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/PDB/Native/Hash.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::support;
+using namespace llvm::pdb;
+
+uint32_t PDBStringTable::getByteSize() const { return Header->ByteSize; }
+uint32_t PDBStringTable::getNameCount() const { return NameCount; }
+uint32_t PDBStringTable::getHashVersion() const { return Header->HashVersion; }
+uint32_t PDBStringTable::getSignature() const { return Header->Signature; }
+
+Error PDBStringTable::readHeader(BinaryStreamReader &Reader) {
+ if (auto EC = Reader.readObject(Header))
+ return EC;
+
+ if (Header->Signature != PDBStringTableSignature)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid hash table signature");
+ if (Header->HashVersion != 1 && Header->HashVersion != 2)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Unsupported hash version");
+
+ assert(Reader.bytesRemaining() == 0);
+ return Error::success();
+}
+
+Error PDBStringTable::readStrings(BinaryStreamReader &Reader) {
+ BinaryStreamRef Stream;
+ if (auto EC = Reader.readStreamRef(Stream))
+ return EC;
+
+ if (auto EC = Strings.initialize(Stream)) {
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid hash table byte length"));
+ }
+
+ assert(Reader.bytesRemaining() == 0);
+ return Error::success();
+}
+
+const codeview::DebugStringTableSubsectionRef &
+PDBStringTable::getStringTable() const {
+ return Strings;
+}
+
+Error PDBStringTable::readHashTable(BinaryStreamReader &Reader) {
+ const support::ulittle32_t *HashCount;
+ if (auto EC = Reader.readObject(HashCount))
+ return EC;
+
+ if (auto EC = Reader.readArray(IDs, *HashCount)) {
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not read bucket array"));
+ }
+
+ return Error::success();
+}
+
+Error PDBStringTable::readEpilogue(BinaryStreamReader &Reader) {
+ if (auto EC = Reader.readInteger(NameCount))
+ return EC;
+
+ assert(Reader.bytesRemaining() == 0);
+ return Error::success();
+}
+
+Error PDBStringTable::reload(BinaryStreamReader &Reader) {
+
+ BinaryStreamReader SectionReader;
+
+ std::tie(SectionReader, Reader) = Reader.split(sizeof(PDBStringTableHeader));
+ if (auto EC = readHeader(SectionReader))
+ return EC;
+
+ std::tie(SectionReader, Reader) = Reader.split(Header->ByteSize);
+ if (auto EC = readStrings(SectionReader))
+ return EC;
+
+ // We don't know how long the hash table is until we parse it, so let the
+ // function responsible for doing that figure it out.
+ if (auto EC = readHashTable(Reader))
+ return EC;
+
+ std::tie(SectionReader, Reader) = Reader.split(sizeof(uint32_t));
+ if (auto EC = readEpilogue(SectionReader))
+ return EC;
+
+ assert(Reader.bytesRemaining() == 0);
+ return Error::success();
+}
+
+Expected<StringRef> PDBStringTable::getStringForID(uint32_t ID) const {
+ return Strings.getString(ID);
+}
+
+Expected<uint32_t> PDBStringTable::getIDForString(StringRef Str) const {
+ uint32_t Hash =
+ (Header->HashVersion == 1) ? hashStringV1(Str) : hashStringV2(Str);
+ size_t Count = IDs.size();
+ uint32_t Start = Hash % Count;
+ for (size_t I = 0; I < Count; ++I) {
+ // The hash is just a starting point for the search, but if it
+ // doesn't work we should find the string no matter what, because
+ // we iterate the entire array.
+ uint32_t Index = (Start + I) % Count;
+
+ // If we find 0, it means the item isn't in the hash table.
+ uint32_t ID = IDs[Index];
+ if (ID == 0)
+ return make_error<RawError>(raw_error_code::no_entry);
+ auto ExpectedStr = getStringForID(ID);
+ if (!ExpectedStr)
+ return ExpectedStr.takeError();
+
+ if (*ExpectedStr == Str)
+ return ID;
+ }
+ return make_error<RawError>(raw_error_code::no_entry);
+}
+
+FixedStreamArray<support::ulittle32_t> PDBStringTable::name_ids() const {
+ return IDs;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp
new file mode 100644
index 0000000000..f7f36901e4
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PDBStringTableBuilder.cpp
@@ -0,0 +1,229 @@
+//===- PDBStringTableBuilder.cpp - PDB String Table -------------*- 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/PDB/Native/PDBStringTableBuilder.h"
+
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/DebugInfo/PDB/Native/Hash.h"
+#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Endian.h"
+
+#include <map>
+
+using namespace llvm;
+using namespace llvm::msf;
+using namespace llvm::support;
+using namespace llvm::support::endian;
+using namespace llvm::pdb;
+
+StringTableHashTraits::StringTableHashTraits(PDBStringTableBuilder &Table)
+ : Table(&Table) {}
+
+uint32_t StringTableHashTraits::hashLookupKey(StringRef S) const {
+ // The reference implementation doesn't include code for /src/headerblock
+ // handling, but it can only read natvis entries lld's PDB files if
+ // this hash function truncates the hash to 16 bit.
+ // PDB/include/misc.h in the reference implementation has a hashSz() function
+ // that returns an unsigned short, that seems what's being used for
+ // /src/headerblock.
+ return static_cast<uint16_t>(Table->getIdForString(S));
+}
+
+StringRef StringTableHashTraits::storageKeyToLookupKey(uint32_t Offset) const {
+ return Table->getStringForId(Offset);
+}
+
+uint32_t StringTableHashTraits::lookupKeyToStorageKey(StringRef S) {
+ return Table->insert(S);
+}
+
+uint32_t PDBStringTableBuilder::insert(StringRef S) {
+ return Strings.insert(S);
+}
+
+uint32_t PDBStringTableBuilder::getIdForString(StringRef S) const {
+ return Strings.getIdForString(S);
+}
+
+StringRef PDBStringTableBuilder::getStringForId(uint32_t Id) const {
+ return Strings.getStringForId(Id);
+}
+
+static uint32_t computeBucketCount(uint32_t NumStrings) {
+ // This is a precomputed list of Buckets given the specified number of
+ // strings. Matching the reference algorithm exactly is not strictly
+ // necessary for correctness, but it helps when comparing LLD's PDBs with
+ // Microsoft's PDBs so as to eliminate superfluous differences.
+ // The reference implementation does (in nmt.h, NMT::grow()):
+ // unsigned StringCount = 0;
+ // unsigned BucketCount = 1;
+ // fn insert() {
+ // ++StringCount;
+ // if (BucketCount * 3 / 4 < StringCount)
+ // BucketCount = BucketCount * 3 / 2 + 1;
+ // }
+ // This list contains all StringCount, BucketCount pairs where BucketCount was
+ // just incremented. It ends before the first BucketCount entry where
+ // BucketCount * 3 would overflow a 32-bit unsigned int.
+ static std::map<uint32_t, uint32_t> StringsToBuckets = {
+ {0, 1},
+ {1, 2},
+ {2, 4},
+ {4, 7},
+ {6, 11},
+ {9, 17},
+ {13, 26},
+ {20, 40},
+ {31, 61},
+ {46, 92},
+ {70, 139},
+ {105, 209},
+ {157, 314},
+ {236, 472},
+ {355, 709},
+ {532, 1064},
+ {799, 1597},
+ {1198, 2396},
+ {1798, 3595},
+ {2697, 5393},
+ {4045, 8090},
+ {6068, 12136},
+ {9103, 18205},
+ {13654, 27308},
+ {20482, 40963},
+ {30723, 61445},
+ {46084, 92168},
+ {69127, 138253},
+ {103690, 207380},
+ {155536, 311071},
+ {233304, 466607},
+ {349956, 699911},
+ {524934, 1049867},
+ {787401, 1574801},
+ {1181101, 2362202},
+ {1771652, 3543304},
+ {2657479, 5314957},
+ {3986218, 7972436},
+ {5979328, 11958655},
+ {8968992, 17937983},
+ {13453488, 26906975},
+ {20180232, 40360463},
+ {30270348, 60540695},
+ {45405522, 90811043},
+ {68108283, 136216565},
+ {102162424, 204324848},
+ {153243637, 306487273},
+ {229865455, 459730910},
+ {344798183, 689596366},
+ {517197275, 1034394550},
+ {775795913, 1551591826},
+ {1163693870, 2327387740}};
+ auto Entry = StringsToBuckets.lower_bound(NumStrings);
+ assert(Entry != StringsToBuckets.end());
+ return Entry->second;
+}
+
+uint32_t PDBStringTableBuilder::calculateHashTableSize() const {
+ uint32_t Size = sizeof(uint32_t); // Hash table begins with 4-byte size field.
+ Size += sizeof(uint32_t) * computeBucketCount(Strings.size());
+
+ return Size;
+}
+
+uint32_t PDBStringTableBuilder::calculateSerializedSize() const {
+ uint32_t Size = 0;
+ Size += sizeof(PDBStringTableHeader);
+ Size += Strings.calculateSerializedSize();
+ Size += calculateHashTableSize();
+ Size += sizeof(uint32_t); // The /names stream ends with the string count.
+ return Size;
+}
+
+void PDBStringTableBuilder::setStrings(
+ const codeview::DebugStringTableSubsection &Strings) {
+ this->Strings = Strings;
+}
+
+Error PDBStringTableBuilder::writeHeader(BinaryStreamWriter &Writer) const {
+ // Write a header
+ PDBStringTableHeader H;
+ H.Signature = PDBStringTableSignature;
+ H.HashVersion = 1;
+ H.ByteSize = Strings.calculateSerializedSize();
+ if (auto EC = Writer.writeObject(H))
+ return EC;
+ assert(Writer.bytesRemaining() == 0);
+ return Error::success();
+}
+
+Error PDBStringTableBuilder::writeStrings(BinaryStreamWriter &Writer) const {
+ if (auto EC = Strings.commit(Writer))
+ return EC;
+
+ assert(Writer.bytesRemaining() == 0);
+ return Error::success();
+}
+
+Error PDBStringTableBuilder::writeHashTable(BinaryStreamWriter &Writer) const {
+ // Write a hash table.
+ uint32_t BucketCount = computeBucketCount(Strings.size());
+ if (auto EC = Writer.writeInteger(BucketCount))
+ return EC;
+ std::vector<ulittle32_t> Buckets(BucketCount);
+
+ for (auto &Pair : Strings) {
+ StringRef S = Pair.getKey();
+ uint32_t Offset = Pair.getValue();
+ uint32_t Hash = hashStringV1(S);
+
+ for (uint32_t I = 0; I != BucketCount; ++I) {
+ uint32_t Slot = (Hash + I) % BucketCount;
+ if (Buckets[Slot] != 0)
+ continue;
+ Buckets[Slot] = Offset;
+ break;
+ }
+ }
+
+ if (auto EC = Writer.writeArray(ArrayRef<ulittle32_t>(Buckets)))
+ return EC;
+
+ assert(Writer.bytesRemaining() == 0);
+ return Error::success();
+}
+
+Error PDBStringTableBuilder::writeEpilogue(BinaryStreamWriter &Writer) const {
+ if (auto EC = Writer.writeInteger<uint32_t>(Strings.size()))
+ return EC;
+ assert(Writer.bytesRemaining() == 0);
+ return Error::success();
+}
+
+Error PDBStringTableBuilder::commit(BinaryStreamWriter &Writer) const {
+ BinaryStreamWriter SectionWriter;
+
+ std::tie(SectionWriter, Writer) = Writer.split(sizeof(PDBStringTableHeader));
+ if (auto EC = writeHeader(SectionWriter))
+ return EC;
+
+ std::tie(SectionWriter, Writer) =
+ Writer.split(Strings.calculateSerializedSize());
+ if (auto EC = writeStrings(SectionWriter))
+ return EC;
+
+ std::tie(SectionWriter, Writer) = Writer.split(calculateHashTableSize());
+ if (auto EC = writeHashTable(SectionWriter))
+ return EC;
+
+ std::tie(SectionWriter, Writer) = Writer.split(sizeof(uint32_t));
+ if (auto EC = writeEpilogue(SectionWriter))
+ return EC;
+
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PublicsStream.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PublicsStream.cpp
new file mode 100644
index 0000000000..a33bf03bf8
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/PublicsStream.cpp
@@ -0,0 +1,101 @@
+//===- PublicsStream.cpp - PDB Public Symbol Stream -----------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// The data structures defined in this file are based on the reference
+// implementation which is available at
+// https://github.com/Microsoft/microsoft-pdb/blob/master/PDB/dbi/gsi.h
+//
+// When you are reading the reference source code, you'd find the
+// information below useful.
+//
+// - ppdb1->m_fMinimalDbgInfo seems to be always true.
+// - SMALLBUCKETS macro is defined.
+//
+// The reference doesn't compile, so I learned just by reading code.
+// It's not guaranteed to be correct.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cstdint>
+
+using namespace llvm;
+using namespace llvm::msf;
+using namespace llvm::support;
+using namespace llvm::pdb;
+
+PublicsStream::PublicsStream(std::unique_ptr<MappedBlockStream> Stream)
+ : Stream(std::move(Stream)) {}
+
+PublicsStream::~PublicsStream() = default;
+
+uint32_t PublicsStream::getSymHash() const { return Header->SymHash; }
+uint16_t PublicsStream::getThunkTableSection() const {
+ return Header->ISectThunkTable;
+}
+uint32_t PublicsStream::getThunkTableOffset() const {
+ return Header->OffThunkTable;
+}
+
+// Publics stream contains fixed-size headers and a serialized hash table.
+// This implementation is not complete yet. It reads till the end of the
+// stream so that we verify the stream is at least not corrupted. However,
+// we skip over the hash table which we believe contains information about
+// public symbols.
+Error PublicsStream::reload() {
+ BinaryStreamReader Reader(*Stream);
+
+ // Check stream size.
+ if (Reader.bytesRemaining() <
+ sizeof(PublicsStreamHeader) + sizeof(GSIHashHeader))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Publics Stream does not contain a header.");
+
+ // Read PSGSIHDR struct.
+ if (Reader.readObject(Header))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Publics Stream does not contain a header.");
+
+ // Read the hash table.
+ if (auto E = PublicsTable.read(Reader))
+ return E;
+
+ // Something called "address map" follows.
+ uint32_t NumAddressMapEntries = Header->AddrMap / sizeof(uint32_t);
+ if (auto EC = Reader.readArray(AddressMap, NumAddressMapEntries))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not read an address map."));
+
+ // Something called "thunk map" follows.
+ if (auto EC = Reader.readArray(ThunkMap, Header->NumThunks))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not read a thunk map."));
+
+ // Something called "section map" follows.
+ if (Reader.bytesRemaining() > 0) {
+ if (auto EC = Reader.readArray(SectionOffsets, Header->NumSections))
+ return joinErrors(std::move(EC),
+ make_error<RawError>(raw_error_code::corrupt_file,
+ "Could not read a section map."));
+ }
+
+ if (Reader.bytesRemaining() > 0)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Corrupted publics stream.");
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/RawError.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/RawError.cpp
new file mode 100644
index 0000000000..ed6cf08396
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/RawError.cpp
@@ -0,0 +1,53 @@
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/Support/ErrorHandling.h"
+#include "llvm/Support/ManagedStatic.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+namespace {
+// FIXME: This class is only here to support the transition to llvm::Error. It
+// will be removed once this transition is complete. Clients should prefer to
+// deal with the Error value directly, rather than converting to error_code.
+class RawErrorCategory : public std::error_category {
+public:
+ const char *name() const noexcept override { return "llvm.pdb.raw"; }
+ std::string message(int Condition) const override {
+ switch (static_cast<raw_error_code>(Condition)) {
+ case raw_error_code::unspecified:
+ return "An unknown error has occurred.";
+ case raw_error_code::feature_unsupported:
+ return "The feature is unsupported by the implementation.";
+ case raw_error_code::invalid_format:
+ return "The record is in an unexpected format.";
+ case raw_error_code::corrupt_file:
+ return "The PDB file is corrupt.";
+ case raw_error_code::insufficient_buffer:
+ return "The buffer is not large enough to read the requested number of "
+ "bytes.";
+ case raw_error_code::no_stream:
+ return "The specified stream could not be loaded.";
+ case raw_error_code::index_out_of_bounds:
+ return "The specified item does not exist in the array.";
+ case raw_error_code::invalid_block_address:
+ return "The specified block address is not valid.";
+ case raw_error_code::duplicate_entry:
+ return "The entry already exists.";
+ case raw_error_code::no_entry:
+ return "The entry does not exist.";
+ case raw_error_code::not_writable:
+ return "The PDB does not support writing.";
+ case raw_error_code::stream_too_long:
+ return "The stream was longer than expected.";
+ case raw_error_code::invalid_tpi_hash:
+ return "The Type record has an invalid hash value.";
+ }
+ llvm_unreachable("Unrecognized raw_error_code");
+ }
+};
+} // namespace
+
+static llvm::ManagedStatic<RawErrorCategory> RawCategory;
+const std::error_category &llvm::pdb::RawErrCategory() { return *RawCategory; }
+
+char RawError::ID;
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/SymbolCache.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/SymbolCache.cpp
new file mode 100644
index 0000000000..f9e6701447
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/SymbolCache.cpp
@@ -0,0 +1,633 @@
+#include "llvm/DebugInfo/PDB/Native/SymbolCache.h"
+
+#include "llvm/DebugInfo/CodeView/DebugInlineeLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/DebugLinesSubsection.h"
+#include "llvm/DebugInfo/CodeView/SymbolDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
+#include "llvm/DebugInfo/PDB/Native/DbiStream.h"
+#include "llvm/DebugInfo/PDB/Native/GlobalsStream.h"
+#include "llvm/DebugInfo/PDB/Native/ISectionContribVisitor.h"
+#include "llvm/DebugInfo/PDB/Native/NativeCompilandSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumGlobals.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumLineNumbers.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumSymbols.h"
+#include "llvm/DebugInfo/PDB/Native/NativeEnumTypes.h"
+#include "llvm/DebugInfo/PDB/Native/NativeFunctionSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeInlineSiteSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativePublicSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeRawSymbol.h"
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeArray.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeEnum.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeFunctionSig.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypePointer.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeTypedef.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeUDT.h"
+#include "llvm/DebugInfo/PDB/Native/NativeTypeVTShape.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/PublicsStream.h"
+#include "llvm/DebugInfo/PDB/Native/SymbolStream.h"
+#include "llvm/DebugInfo/PDB/Native/TpiStream.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+// Maps codeview::SimpleTypeKind of a built-in type to the parameters necessary
+// to instantiate a NativeBuiltinSymbol for that type.
+static const struct BuiltinTypeEntry {
+ codeview::SimpleTypeKind Kind;
+ PDB_BuiltinType Type;
+ uint32_t Size;
+} BuiltinTypes[] = {
+ {codeview::SimpleTypeKind::None, PDB_BuiltinType::None, 0},
+ {codeview::SimpleTypeKind::Void, PDB_BuiltinType::Void, 0},
+ {codeview::SimpleTypeKind::HResult, PDB_BuiltinType::HResult, 4},
+ {codeview::SimpleTypeKind::Int16Short, PDB_BuiltinType::Int, 2},
+ {codeview::SimpleTypeKind::UInt16Short, PDB_BuiltinType::UInt, 2},
+ {codeview::SimpleTypeKind::Int32, PDB_BuiltinType::Int, 4},
+ {codeview::SimpleTypeKind::UInt32, PDB_BuiltinType::UInt, 4},
+ {codeview::SimpleTypeKind::Int32Long, PDB_BuiltinType::Int, 4},
+ {codeview::SimpleTypeKind::UInt32Long, PDB_BuiltinType::UInt, 4},
+ {codeview::SimpleTypeKind::Int64Quad, PDB_BuiltinType::Int, 8},
+ {codeview::SimpleTypeKind::UInt64Quad, PDB_BuiltinType::UInt, 8},
+ {codeview::SimpleTypeKind::NarrowCharacter, PDB_BuiltinType::Char, 1},
+ {codeview::SimpleTypeKind::WideCharacter, PDB_BuiltinType::WCharT, 2},
+ {codeview::SimpleTypeKind::Character16, PDB_BuiltinType::Char16, 2},
+ {codeview::SimpleTypeKind::Character32, PDB_BuiltinType::Char32, 4},
+ {codeview::SimpleTypeKind::SignedCharacter, PDB_BuiltinType::Char, 1},
+ {codeview::SimpleTypeKind::UnsignedCharacter, PDB_BuiltinType::UInt, 1},
+ {codeview::SimpleTypeKind::Float32, PDB_BuiltinType::Float, 4},
+ {codeview::SimpleTypeKind::Float64, PDB_BuiltinType::Float, 8},
+ {codeview::SimpleTypeKind::Float80, PDB_BuiltinType::Float, 10},
+ {codeview::SimpleTypeKind::Boolean8, PDB_BuiltinType::Bool, 1},
+ // This table can be grown as necessary, but these are the only types we've
+ // needed so far.
+};
+
+SymbolCache::SymbolCache(NativeSession &Session, DbiStream *Dbi)
+ : Session(Session), Dbi(Dbi) {
+ // Id 0 is reserved for the invalid symbol.
+ Cache.push_back(nullptr);
+ SourceFiles.push_back(nullptr);
+
+ if (Dbi)
+ Compilands.resize(Dbi->modules().getModuleCount());
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+SymbolCache::createTypeEnumerator(TypeLeafKind Kind) {
+ return createTypeEnumerator(std::vector<TypeLeafKind>{Kind});
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+SymbolCache::createTypeEnumerator(std::vector<TypeLeafKind> Kinds) {
+ auto Tpi = Session.getPDBFile().getPDBTpiStream();
+ if (!Tpi) {
+ consumeError(Tpi.takeError());
+ return nullptr;
+ }
+ auto &Types = Tpi->typeCollection();
+ return std::unique_ptr<IPDBEnumSymbols>(
+ new NativeEnumTypes(Session, Types, std::move(Kinds)));
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+SymbolCache::createGlobalsEnumerator(codeview::SymbolKind Kind) {
+ return std::unique_ptr<IPDBEnumSymbols>(
+ new NativeEnumGlobals(Session, {Kind}));
+}
+
+SymIndexId SymbolCache::createSimpleType(TypeIndex Index,
+ ModifierOptions Mods) const {
+ if (Index.getSimpleMode() != codeview::SimpleTypeMode::Direct)
+ return createSymbol<NativeTypePointer>(Index);
+
+ const auto Kind = Index.getSimpleKind();
+ const auto It =
+ llvm::find_if(BuiltinTypes, [Kind](const BuiltinTypeEntry &Builtin) {
+ return Builtin.Kind == Kind;
+ });
+ if (It == std::end(BuiltinTypes))
+ return 0;
+ return createSymbol<NativeTypeBuiltin>(Mods, It->Type, It->Size);
+}
+
+SymIndexId
+SymbolCache::createSymbolForModifiedType(codeview::TypeIndex ModifierTI,
+ codeview::CVType CVT) const {
+ ModifierRecord Record;
+ if (auto EC = TypeDeserializer::deserializeAs<ModifierRecord>(CVT, Record)) {
+ consumeError(std::move(EC));
+ return 0;
+ }
+
+ if (Record.ModifiedType.isSimple())
+ return createSimpleType(Record.ModifiedType, Record.Modifiers);
+
+ // Make sure we create and cache a record for the unmodified type.
+ SymIndexId UnmodifiedId = findSymbolByTypeIndex(Record.ModifiedType);
+ NativeRawSymbol &UnmodifiedNRS = *Cache[UnmodifiedId];
+
+ switch (UnmodifiedNRS.getSymTag()) {
+ case PDB_SymType::Enum:
+ return createSymbol<NativeTypeEnum>(
+ static_cast<NativeTypeEnum &>(UnmodifiedNRS), std::move(Record));
+ case PDB_SymType::UDT:
+ return createSymbol<NativeTypeUDT>(
+ static_cast<NativeTypeUDT &>(UnmodifiedNRS), std::move(Record));
+ default:
+ // No other types can be modified. (LF_POINTER, for example, records
+ // its modifiers a different way.
+ assert(false && "Invalid LF_MODIFIER record");
+ break;
+ }
+ return 0;
+}
+
+SymIndexId SymbolCache::findSymbolByTypeIndex(codeview::TypeIndex Index) const {
+ // First see if it's already in our cache.
+ const auto Entry = TypeIndexToSymbolId.find(Index);
+ if (Entry != TypeIndexToSymbolId.end())
+ return Entry->second;
+
+ // Symbols for built-in types are created on the fly.
+ if (Index.isSimple()) {
+ SymIndexId Result = createSimpleType(Index, ModifierOptions::None);
+ assert(TypeIndexToSymbolId.count(Index) == 0);
+ TypeIndexToSymbolId[Index] = Result;
+ return Result;
+ }
+
+ // We need to instantiate and cache the desired type symbol.
+ auto Tpi = Session.getPDBFile().getPDBTpiStream();
+ if (!Tpi) {
+ consumeError(Tpi.takeError());
+ return 0;
+ }
+ codeview::LazyRandomTypeCollection &Types = Tpi->typeCollection();
+ codeview::CVType CVT = Types.getType(Index);
+
+ if (isUdtForwardRef(CVT)) {
+ Expected<TypeIndex> EFD = Tpi->findFullDeclForForwardRef(Index);
+
+ if (!EFD)
+ consumeError(EFD.takeError());
+ else if (*EFD != Index) {
+ assert(!isUdtForwardRef(Types.getType(*EFD)));
+ SymIndexId Result = findSymbolByTypeIndex(*EFD);
+ // Record a mapping from ForwardRef -> SymIndex of complete type so that
+ // we'll take the fast path next time.
+ assert(TypeIndexToSymbolId.count(Index) == 0);
+ TypeIndexToSymbolId[Index] = Result;
+ return Result;
+ }
+ }
+
+ // At this point if we still have a forward ref udt it means the full decl was
+ // not in the PDB. We just have to deal with it and use the forward ref.
+ SymIndexId Id = 0;
+ switch (CVT.kind()) {
+ case codeview::LF_ENUM:
+ Id = createSymbolForType<NativeTypeEnum, EnumRecord>(Index, std::move(CVT));
+ break;
+ case codeview::LF_ARRAY:
+ Id = createSymbolForType<NativeTypeArray, ArrayRecord>(Index,
+ std::move(CVT));
+ break;
+ case codeview::LF_CLASS:
+ case codeview::LF_STRUCTURE:
+ case codeview::LF_INTERFACE:
+ Id = createSymbolForType<NativeTypeUDT, ClassRecord>(Index, std::move(CVT));
+ break;
+ case codeview::LF_UNION:
+ Id = createSymbolForType<NativeTypeUDT, UnionRecord>(Index, std::move(CVT));
+ break;
+ case codeview::LF_POINTER:
+ Id = createSymbolForType<NativeTypePointer, PointerRecord>(Index,
+ std::move(CVT));
+ break;
+ case codeview::LF_MODIFIER:
+ Id = createSymbolForModifiedType(Index, std::move(CVT));
+ break;
+ case codeview::LF_PROCEDURE:
+ Id = createSymbolForType<NativeTypeFunctionSig, ProcedureRecord>(
+ Index, std::move(CVT));
+ break;
+ case codeview::LF_MFUNCTION:
+ Id = createSymbolForType<NativeTypeFunctionSig, MemberFunctionRecord>(
+ Index, std::move(CVT));
+ break;
+ case codeview::LF_VTSHAPE:
+ Id = createSymbolForType<NativeTypeVTShape, VFTableShapeRecord>(
+ Index, std::move(CVT));
+ break;
+ default:
+ Id = createSymbolPlaceholder();
+ break;
+ }
+ if (Id != 0) {
+ assert(TypeIndexToSymbolId.count(Index) == 0);
+ TypeIndexToSymbolId[Index] = Id;
+ }
+ return Id;
+}
+
+std::unique_ptr<PDBSymbol>
+SymbolCache::getSymbolById(SymIndexId SymbolId) const {
+ assert(SymbolId < Cache.size());
+
+ // Id 0 is reserved.
+ if (SymbolId == 0 || SymbolId >= Cache.size())
+ return nullptr;
+
+ // Make sure to handle the case where we've inserted a placeholder symbol
+ // for types we don't yet support.
+ NativeRawSymbol *NRS = Cache[SymbolId].get();
+ if (!NRS)
+ return nullptr;
+
+ return PDBSymbol::create(Session, *NRS);
+}
+
+NativeRawSymbol &SymbolCache::getNativeSymbolById(SymIndexId SymbolId) const {
+ return *Cache[SymbolId];
+}
+
+uint32_t SymbolCache::getNumCompilands() const {
+ if (!Dbi)
+ return 0;
+
+ return Dbi->modules().getModuleCount();
+}
+
+SymIndexId SymbolCache::getOrCreateGlobalSymbolByOffset(uint32_t Offset) {
+ auto Iter = GlobalOffsetToSymbolId.find(Offset);
+ if (Iter != GlobalOffsetToSymbolId.end())
+ return Iter->second;
+
+ SymbolStream &SS = cantFail(Session.getPDBFile().getPDBSymbolStream());
+ CVSymbol CVS = SS.readRecord(Offset);
+ SymIndexId Id = 0;
+ switch (CVS.kind()) {
+ case SymbolKind::S_UDT: {
+ UDTSym US = cantFail(SymbolDeserializer::deserializeAs<UDTSym>(CVS));
+ Id = createSymbol<NativeTypeTypedef>(std::move(US));
+ break;
+ }
+ default:
+ Id = createSymbolPlaceholder();
+ break;
+ }
+ if (Id != 0) {
+ assert(GlobalOffsetToSymbolId.count(Offset) == 0);
+ GlobalOffsetToSymbolId[Offset] = Id;
+ }
+
+ return Id;
+}
+
+SymIndexId SymbolCache::getOrCreateInlineSymbol(InlineSiteSym Sym,
+ uint64_t ParentAddr,
+ uint16_t Modi,
+ uint32_t RecordOffset) const {
+ auto Iter = SymTabOffsetToSymbolId.find({Modi, RecordOffset});
+ if (Iter != SymTabOffsetToSymbolId.end())
+ return Iter->second;
+
+ SymIndexId Id = createSymbol<NativeInlineSiteSymbol>(Sym, ParentAddr);
+ SymTabOffsetToSymbolId.insert({{Modi, RecordOffset}, Id});
+ return Id;
+}
+
+std::unique_ptr<PDBSymbol>
+SymbolCache::findSymbolBySectOffset(uint32_t Sect, uint32_t Offset,
+ PDB_SymType Type) {
+ switch (Type) {
+ case PDB_SymType::Function:
+ return findFunctionSymbolBySectOffset(Sect, Offset);
+ case PDB_SymType::PublicSymbol:
+ return findPublicSymbolBySectOffset(Sect, Offset);
+ case PDB_SymType::Compiland: {
+ uint16_t Modi;
+ if (!Session.moduleIndexForSectOffset(Sect, Offset, Modi))
+ return nullptr;
+ return getOrCreateCompiland(Modi);
+ }
+ case PDB_SymType::None: {
+ // FIXME: Implement for PDB_SymType::Data. The symbolizer calls this but
+ // only uses it to find the symbol length.
+ if (auto Sym = findFunctionSymbolBySectOffset(Sect, Offset))
+ return Sym;
+ return nullptr;
+ }
+ default:
+ return nullptr;
+ }
+}
+
+std::unique_ptr<PDBSymbol>
+SymbolCache::findFunctionSymbolBySectOffset(uint32_t Sect, uint32_t Offset) {
+ auto Iter = AddressToSymbolId.find({Sect, Offset});
+ if (Iter != AddressToSymbolId.end())
+ return getSymbolById(Iter->second);
+
+ if (!Dbi)
+ return nullptr;
+
+ uint16_t Modi;
+ if (!Session.moduleIndexForSectOffset(Sect, Offset, Modi))
+ return nullptr;
+
+ Expected<ModuleDebugStreamRef> ExpectedModS =
+ Session.getModuleDebugStream(Modi);
+ if (!ExpectedModS) {
+ consumeError(ExpectedModS.takeError());
+ return nullptr;
+ }
+ CVSymbolArray Syms = ExpectedModS->getSymbolArray();
+
+ // Search for the symbol in this module.
+ for (auto I = Syms.begin(), E = Syms.end(); I != E; ++I) {
+ if (I->kind() != S_LPROC32 && I->kind() != S_GPROC32)
+ continue;
+ auto PS = cantFail(SymbolDeserializer::deserializeAs<ProcSym>(*I));
+ if (Sect == PS.Segment && Offset >= PS.CodeOffset &&
+ Offset < PS.CodeOffset + PS.CodeSize) {
+ // Check if the symbol is already cached.
+ auto Found = AddressToSymbolId.find({PS.Segment, PS.CodeOffset});
+ if (Found != AddressToSymbolId.end())
+ return getSymbolById(Found->second);
+
+ // Otherwise, create a new symbol.
+ SymIndexId Id = createSymbol<NativeFunctionSymbol>(PS, I.offset());
+ AddressToSymbolId.insert({{PS.Segment, PS.CodeOffset}, Id});
+ return getSymbolById(Id);
+ }
+
+ // Jump to the end of this ProcSym.
+ I = Syms.at(PS.End);
+ }
+ return nullptr;
+}
+
+std::unique_ptr<PDBSymbol>
+SymbolCache::findPublicSymbolBySectOffset(uint32_t Sect, uint32_t Offset) {
+ auto Iter = AddressToPublicSymId.find({Sect, Offset});
+ if (Iter != AddressToPublicSymId.end())
+ return getSymbolById(Iter->second);
+
+ auto Publics = Session.getPDBFile().getPDBPublicsStream();
+ if (!Publics)
+ return nullptr;
+
+ auto ExpectedSyms = Session.getPDBFile().getPDBSymbolStream();
+ if (!ExpectedSyms)
+ return nullptr;
+ BinaryStreamRef SymStream =
+ ExpectedSyms->getSymbolArray().getUnderlyingStream();
+
+ // Use binary search to find the first public symbol with an address greater
+ // than or equal to Sect, Offset.
+ auto AddrMap = Publics->getAddressMap();
+ auto First = AddrMap.begin();
+ auto It = AddrMap.begin();
+ size_t Count = AddrMap.size();
+ size_t Half;
+ while (Count > 0) {
+ It = First;
+ Half = Count / 2;
+ It += Half;
+ Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, *It);
+ if (!Sym) {
+ consumeError(Sym.takeError());
+ return nullptr;
+ }
+
+ auto PS =
+ cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(Sym.get()));
+ if (PS.Segment < Sect || (PS.Segment == Sect && PS.Offset <= Offset)) {
+ First = ++It;
+ Count -= Half + 1;
+ } else
+ Count = Half;
+ }
+ if (It == AddrMap.begin())
+ return nullptr;
+ --It;
+
+ Expected<CVSymbol> Sym = readSymbolFromStream(SymStream, *It);
+ if (!Sym) {
+ consumeError(Sym.takeError());
+ return nullptr;
+ }
+
+ // Check if the symbol is already cached.
+ auto PS = cantFail(SymbolDeserializer::deserializeAs<PublicSym32>(Sym.get()));
+ auto Found = AddressToPublicSymId.find({PS.Segment, PS.Offset});
+ if (Found != AddressToPublicSymId.end())
+ return getSymbolById(Found->second);
+
+ // Otherwise, create a new symbol.
+ SymIndexId Id = createSymbol<NativePublicSymbol>(PS);
+ AddressToPublicSymId.insert({{PS.Segment, PS.Offset}, Id});
+ return getSymbolById(Id);
+}
+
+std::vector<SymbolCache::LineTableEntry>
+SymbolCache::findLineTable(uint16_t Modi) const {
+ // Check if this module has already been added.
+ auto LineTableIter = LineTable.find(Modi);
+ if (LineTableIter != LineTable.end())
+ return LineTableIter->second;
+
+ std::vector<LineTableEntry> &ModuleLineTable = LineTable[Modi];
+
+ // If there is an error or there are no lines, just return the
+ // empty vector.
+ Expected<ModuleDebugStreamRef> ExpectedModS =
+ Session.getModuleDebugStream(Modi);
+ if (!ExpectedModS) {
+ consumeError(ExpectedModS.takeError());
+ return ModuleLineTable;
+ }
+
+ std::vector<std::vector<LineTableEntry>> EntryList;
+ for (const auto &SS : ExpectedModS->getSubsectionsArray()) {
+ if (SS.kind() != DebugSubsectionKind::Lines)
+ continue;
+
+ DebugLinesSubsectionRef Lines;
+ BinaryStreamReader Reader(SS.getRecordData());
+ if (auto EC = Lines.initialize(Reader)) {
+ consumeError(std::move(EC));
+ continue;
+ }
+
+ uint32_t RelocSegment = Lines.header()->RelocSegment;
+ uint32_t RelocOffset = Lines.header()->RelocOffset;
+ for (const LineColumnEntry &Group : Lines) {
+ if (Group.LineNumbers.empty())
+ continue;
+
+ std::vector<LineTableEntry> Entries;
+
+ // If there are column numbers, then they should be in a parallel stream
+ // to the line numbers.
+ auto ColIt = Group.Columns.begin();
+ auto ColsEnd = Group.Columns.end();
+
+ // Add a line to mark the beginning of this section.
+ uint64_t StartAddr =
+ Session.getVAFromSectOffset(RelocSegment, RelocOffset);
+ LineInfo FirstLine(Group.LineNumbers.front().Flags);
+ uint32_t ColNum =
+ (Lines.hasColumnInfo()) ? Group.Columns.front().StartColumn : 0;
+ Entries.push_back({StartAddr, FirstLine, ColNum, Group.NameIndex, false});
+
+ for (const LineNumberEntry &LN : Group.LineNumbers) {
+ uint64_t VA =
+ Session.getVAFromSectOffset(RelocSegment, RelocOffset + LN.Offset);
+ LineInfo Line(LN.Flags);
+ ColNum = 0;
+
+ if (Lines.hasColumnInfo() && ColIt != ColsEnd) {
+ ColNum = ColIt->StartColumn;
+ ++ColIt;
+ }
+ Entries.push_back({VA, Line, ColNum, Group.NameIndex, false});
+ }
+
+ // Add a terminal entry line to mark the end of this subsection.
+ uint64_t EndAddr = StartAddr + Lines.header()->CodeSize;
+ LineInfo LastLine(Group.LineNumbers.back().Flags);
+ ColNum = (Lines.hasColumnInfo()) ? Group.Columns.back().StartColumn : 0;
+ Entries.push_back({EndAddr, LastLine, ColNum, Group.NameIndex, true});
+
+ EntryList.push_back(Entries);
+ }
+ }
+
+ // Sort EntryList, and add flattened contents to the line table.
+ llvm::sort(EntryList, [](const std::vector<LineTableEntry> &LHS,
+ const std::vector<LineTableEntry> &RHS) {
+ return LHS[0].Addr < RHS[0].Addr;
+ });
+ for (std::vector<LineTableEntry> &I : EntryList)
+ llvm::append_range(ModuleLineTable, I);
+
+ return ModuleLineTable;
+}
+
+std::unique_ptr<IPDBEnumLineNumbers>
+SymbolCache::findLineNumbersByVA(uint64_t VA, uint32_t Length) const {
+ uint16_t Modi;
+ if (!Session.moduleIndexForVA(VA, Modi))
+ return nullptr;
+
+ std::vector<LineTableEntry> Lines = findLineTable(Modi);
+ if (Lines.empty())
+ return nullptr;
+
+ // Find the first line in the line table whose address is not greater than
+ // the one we are searching for.
+ auto LineIter = llvm::partition_point(Lines, [&](const LineTableEntry &E) {
+ return (E.Addr < VA || (E.Addr == VA && E.IsTerminalEntry));
+ });
+
+ // Try to back up if we've gone too far.
+ if (LineIter == Lines.end() || LineIter->Addr > VA) {
+ if (LineIter == Lines.begin() || std::prev(LineIter)->IsTerminalEntry)
+ return nullptr;
+ --LineIter;
+ }
+
+ Expected<ModuleDebugStreamRef> ExpectedModS =
+ Session.getModuleDebugStream(Modi);
+ if (!ExpectedModS) {
+ consumeError(ExpectedModS.takeError());
+ return nullptr;
+ }
+ Expected<DebugChecksumsSubsectionRef> ExpectedChecksums =
+ ExpectedModS->findChecksumsSubsection();
+ if (!ExpectedChecksums) {
+ consumeError(ExpectedChecksums.takeError());
+ return nullptr;
+ }
+
+ // Populate a vector of NativeLineNumbers that have addresses in the given
+ // address range.
+ std::vector<NativeLineNumber> LineNumbers;
+ while (LineIter != Lines.end()) {
+ if (LineIter->IsTerminalEntry) {
+ ++LineIter;
+ continue;
+ }
+
+ // If the line is still within the address range, create a NativeLineNumber
+ // and add to the list.
+ if (LineIter->Addr > VA + Length)
+ break;
+
+ uint32_t LineSect, LineOff;
+ Session.addressForVA(LineIter->Addr, LineSect, LineOff);
+ uint32_t LineLength = std::next(LineIter)->Addr - LineIter->Addr;
+ auto ChecksumIter =
+ ExpectedChecksums->getArray().at(LineIter->FileNameIndex);
+ uint32_t SrcFileId = getOrCreateSourceFile(*ChecksumIter);
+ NativeLineNumber LineNum(Session, LineIter->Line, LineIter->ColumnNumber,
+ LineSect, LineOff, LineLength, SrcFileId, Modi);
+ LineNumbers.push_back(LineNum);
+ ++LineIter;
+ }
+ return std::make_unique<NativeEnumLineNumbers>(std::move(LineNumbers));
+}
+
+std::unique_ptr<PDBSymbolCompiland>
+SymbolCache::getOrCreateCompiland(uint32_t Index) {
+ if (!Dbi)
+ return nullptr;
+
+ if (Index >= Compilands.size())
+ return nullptr;
+
+ if (Compilands[Index] == 0) {
+ const DbiModuleList &Modules = Dbi->modules();
+ Compilands[Index] =
+ createSymbol<NativeCompilandSymbol>(Modules.getModuleDescriptor(Index));
+ }
+
+ return Session.getConcreteSymbolById<PDBSymbolCompiland>(Compilands[Index]);
+}
+
+std::unique_ptr<IPDBSourceFile>
+SymbolCache::getSourceFileById(SymIndexId FileId) const {
+ assert(FileId < SourceFiles.size());
+
+ // Id 0 is reserved.
+ if (FileId == 0)
+ return nullptr;
+
+ return std::unique_ptr<NativeSourceFile>(
+ new NativeSourceFile(*SourceFiles[FileId].get()));
+}
+
+SymIndexId
+SymbolCache::getOrCreateSourceFile(const FileChecksumEntry &Checksums) const {
+ auto Iter = FileNameOffsetToId.find(Checksums.FileNameOffset);
+ if (Iter != FileNameOffsetToId.end())
+ return Iter->second;
+
+ SymIndexId Id = SourceFiles.size();
+ auto SrcFile = std::make_unique<NativeSourceFile>(Session, Id, Checksums);
+ SourceFiles.push_back(std::move(SrcFile));
+ FileNameOffsetToId[Checksums.FileNameOffset] = Id;
+ return Id;
+}
+
+
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/SymbolStream.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/SymbolStream.cpp
new file mode 100644
index 0000000000..003840b6e6
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/SymbolStream.cpp
@@ -0,0 +1,45 @@
+//===- SymbolStream.cpp - PDB Symbol Stream Access ------------------------===//
+//
+// 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/PDB/Native/SymbolStream.h"
+
+#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Endian.h"
+
+using namespace llvm;
+using namespace llvm::msf;
+using namespace llvm::support;
+using namespace llvm::pdb;
+
+SymbolStream::SymbolStream(std::unique_ptr<MappedBlockStream> Stream)
+ : Stream(std::move(Stream)) {}
+
+SymbolStream::~SymbolStream() {}
+
+Error SymbolStream::reload() {
+ BinaryStreamReader Reader(*Stream);
+
+ if (auto EC = Reader.readArray(SymbolRecords, Stream->getLength()))
+ return EC;
+
+ return Error::success();
+}
+
+iterator_range<codeview::CVSymbolArray::Iterator>
+SymbolStream::getSymbols(bool *HadError) const {
+ return llvm::make_range(SymbolRecords.begin(HadError), SymbolRecords.end());
+}
+
+Error SymbolStream::commit() { return Error::success(); }
+
+codeview::CVSymbol SymbolStream::readRecord(uint32_t Offset) const {
+ return *SymbolRecords.at(Offset);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/TpiHashing.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/TpiHashing.cpp
new file mode 100644
index 0000000000..b71b2b1581
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/TpiHashing.cpp
@@ -0,0 +1,129 @@
+//===- TpiHashing.cpp -----------------------------------------------------===//
+//
+// 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/PDB/Native/TpiHashing.h"
+
+#include "llvm/DebugInfo/CodeView/TypeDeserializer.h"
+#include "llvm/DebugInfo/PDB/Native/Hash.h"
+#include "llvm/Support/CRC.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::pdb;
+
+// Corresponds to `fUDTAnon`.
+static bool isAnonymous(StringRef Name) {
+ return Name == "<unnamed-tag>" || Name == "__unnamed" ||
+ Name.endswith("::<unnamed-tag>") || Name.endswith("::__unnamed");
+}
+
+// Computes the hash for a user-defined type record. This could be a struct,
+// class, union, or enum.
+static uint32_t getHashForUdt(const TagRecord &Rec,
+ ArrayRef<uint8_t> FullRecord) {
+ ClassOptions Opts = Rec.getOptions();
+ bool ForwardRef = bool(Opts & ClassOptions::ForwardReference);
+ bool Scoped = bool(Opts & ClassOptions::Scoped);
+ bool HasUniqueName = bool(Opts & ClassOptions::HasUniqueName);
+ bool IsAnon = HasUniqueName && isAnonymous(Rec.getName());
+
+ if (!ForwardRef && !Scoped && !IsAnon)
+ return hashStringV1(Rec.getName());
+ if (!ForwardRef && HasUniqueName && !IsAnon)
+ return hashStringV1(Rec.getUniqueName());
+ return hashBufferV8(FullRecord);
+}
+
+template <typename T>
+static Expected<uint32_t> getHashForUdt(const CVType &Rec) {
+ T Deserialized;
+ if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec),
+ Deserialized))
+ return std::move(E);
+ return getHashForUdt(Deserialized, Rec.data());
+}
+
+template <typename T>
+static Expected<TagRecordHash> getTagRecordHashForUdt(const CVType &Rec) {
+ T Deserialized;
+ if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec),
+ Deserialized))
+ return std::move(E);
+
+ ClassOptions Opts = Deserialized.getOptions();
+
+ bool ForwardRef = bool(Opts & ClassOptions::ForwardReference);
+
+ uint32_t ThisRecordHash = getHashForUdt(Deserialized, Rec.data());
+
+ // If we don't have a forward ref we can't compute the hash of it from the
+ // full record because it requires hashing the entire buffer.
+ if (!ForwardRef)
+ return TagRecordHash{std::move(Deserialized), ThisRecordHash, 0};
+
+ bool Scoped = bool(Opts & ClassOptions::Scoped);
+
+ StringRef NameToHash =
+ Scoped ? Deserialized.getUniqueName() : Deserialized.getName();
+ uint32_t FullHash = hashStringV1(NameToHash);
+ return TagRecordHash{std::move(Deserialized), FullHash, ThisRecordHash};
+}
+
+template <typename T>
+static Expected<uint32_t> getSourceLineHash(const CVType &Rec) {
+ T Deserialized;
+ if (auto E = TypeDeserializer::deserializeAs(const_cast<CVType &>(Rec),
+ Deserialized))
+ return std::move(E);
+ char Buf[4];
+ support::endian::write32le(Buf, Deserialized.getUDT().getIndex());
+ return hashStringV1(StringRef(Buf, 4));
+}
+
+Expected<TagRecordHash> llvm::pdb::hashTagRecord(const codeview::CVType &Type) {
+ switch (Type.kind()) {
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_INTERFACE:
+ return getTagRecordHashForUdt<ClassRecord>(Type);
+ case LF_UNION:
+ return getTagRecordHashForUdt<UnionRecord>(Type);
+ case LF_ENUM:
+ return getTagRecordHashForUdt<EnumRecord>(Type);
+ default:
+ assert(false && "Type is not a tag record!");
+ }
+ return make_error<StringError>("Invalid record type",
+ inconvertibleErrorCode());
+}
+
+Expected<uint32_t> llvm::pdb::hashTypeRecord(const CVType &Rec) {
+ switch (Rec.kind()) {
+ case LF_CLASS:
+ case LF_STRUCTURE:
+ case LF_INTERFACE:
+ return getHashForUdt<ClassRecord>(Rec);
+ case LF_UNION:
+ return getHashForUdt<UnionRecord>(Rec);
+ case LF_ENUM:
+ return getHashForUdt<EnumRecord>(Rec);
+
+ case LF_UDT_SRC_LINE:
+ return getSourceLineHash<UdtSourceLineRecord>(Rec);
+ case LF_UDT_MOD_SRC_LINE:
+ return getSourceLineHash<UdtModSourceLineRecord>(Rec);
+
+ default:
+ break;
+ }
+
+ // Run CRC32 over the bytes. This corresponds to `hashBufv8`.
+ JamCRC JC(/*Init=*/0U);
+ JC.update(Rec.data());
+ return JC.getCRC();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/TpiStream.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/TpiStream.cpp
new file mode 100644
index 0000000000..ac19db03fa
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/TpiStream.cpp
@@ -0,0 +1,246 @@
+//===- TpiStream.cpp - PDB Type Info (TPI) Stream 2 Access ----------------===//
+//
+// 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/PDB/Native/TpiStream.h"
+
+#include "llvm/ADT/iterator_range.h"
+#include "llvm/DebugInfo/CodeView/LazyRandomTypeCollection.h"
+#include "llvm/DebugInfo/CodeView/RecordName.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/CodeView/TypeRecordHelpers.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/Hash.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawConstants.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
+#include "llvm/DebugInfo/PDB/Native/TpiHashing.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cstdint>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::support;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+
+TpiStream::TpiStream(PDBFile &File, std::unique_ptr<MappedBlockStream> Stream)
+ : Pdb(File), Stream(std::move(Stream)) {}
+
+TpiStream::~TpiStream() = default;
+
+Error TpiStream::reload() {
+ BinaryStreamReader Reader(*Stream);
+
+ if (Reader.bytesRemaining() < sizeof(TpiStreamHeader))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "TPI Stream does not contain a header.");
+
+ if (Reader.readObject(Header))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "TPI Stream does not contain a header.");
+
+ if (Header->Version != PdbTpiV80)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Unsupported TPI Version.");
+
+ if (Header->HeaderSize != sizeof(TpiStreamHeader))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Corrupt TPI Header size.");
+
+ if (Header->HashKeySize != sizeof(ulittle32_t))
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "TPI Stream expected 4 byte hash key size.");
+
+ if (Header->NumHashBuckets < MinTpiHashBuckets ||
+ Header->NumHashBuckets > MaxTpiHashBuckets)
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "TPI Stream Invalid number of hash buckets.");
+
+ // The actual type records themselves come from this stream
+ if (auto EC =
+ Reader.readSubstream(TypeRecordsSubstream, Header->TypeRecordBytes))
+ return EC;
+
+ BinaryStreamReader RecordReader(TypeRecordsSubstream.StreamData);
+ if (auto EC =
+ RecordReader.readArray(TypeRecords, TypeRecordsSubstream.size()))
+ return EC;
+
+ // Hash indices, hash values, etc come from the hash stream.
+ if (Header->HashStreamIndex != kInvalidStreamIndex) {
+ auto HS = Pdb.safelyCreateIndexedStream(Header->HashStreamIndex);
+ if (!HS) {
+ consumeError(HS.takeError());
+ return make_error<RawError>(raw_error_code::corrupt_file,
+ "Invalid TPI hash stream index.");
+ }
+ BinaryStreamReader HSR(**HS);
+
+ // There should be a hash value for every type record, or no hashes at all.
+ uint32_t NumHashValues =
+ Header->HashValueBuffer.Length / sizeof(ulittle32_t);
+ if (NumHashValues != getNumTypeRecords() && NumHashValues != 0)
+ return make_error<RawError>(
+ raw_error_code::corrupt_file,
+ "TPI hash count does not match with the number of type records.");
+ HSR.setOffset(Header->HashValueBuffer.Off);
+ if (auto EC = HSR.readArray(HashValues, NumHashValues))
+ return EC;
+
+ HSR.setOffset(Header->IndexOffsetBuffer.Off);
+ uint32_t NumTypeIndexOffsets =
+ Header->IndexOffsetBuffer.Length / sizeof(TypeIndexOffset);
+ if (auto EC = HSR.readArray(TypeIndexOffsets, NumTypeIndexOffsets))
+ return EC;
+
+ if (Header->HashAdjBuffer.Length > 0) {
+ HSR.setOffset(Header->HashAdjBuffer.Off);
+ if (auto EC = HashAdjusters.load(HSR))
+ return EC;
+ }
+
+ HashStream = std::move(*HS);
+ }
+
+ Types = std::make_unique<LazyRandomTypeCollection>(
+ TypeRecords, getNumTypeRecords(), getTypeIndexOffsets());
+ return Error::success();
+}
+
+PdbRaw_TpiVer TpiStream::getTpiVersion() const {
+ uint32_t Value = Header->Version;
+ return static_cast<PdbRaw_TpiVer>(Value);
+}
+
+uint32_t TpiStream::TypeIndexBegin() const { return Header->TypeIndexBegin; }
+
+uint32_t TpiStream::TypeIndexEnd() const { return Header->TypeIndexEnd; }
+
+uint32_t TpiStream::getNumTypeRecords() const {
+ return TypeIndexEnd() - TypeIndexBegin();
+}
+
+uint16_t TpiStream::getTypeHashStreamIndex() const {
+ return Header->HashStreamIndex;
+}
+
+uint16_t TpiStream::getTypeHashStreamAuxIndex() const {
+ return Header->HashAuxStreamIndex;
+}
+
+uint32_t TpiStream::getNumHashBuckets() const { return Header->NumHashBuckets; }
+uint32_t TpiStream::getHashKeySize() const { return Header->HashKeySize; }
+
+void TpiStream::buildHashMap() {
+ if (!HashMap.empty())
+ return;
+ if (HashValues.empty())
+ return;
+
+ HashMap.resize(Header->NumHashBuckets);
+
+ TypeIndex TIB{Header->TypeIndexBegin};
+ TypeIndex TIE{Header->TypeIndexEnd};
+ while (TIB < TIE) {
+ uint32_t HV = HashValues[TIB.toArrayIndex()];
+ HashMap[HV].push_back(TIB++);
+ }
+}
+
+std::vector<TypeIndex> TpiStream::findRecordsByName(StringRef Name) const {
+ if (!supportsTypeLookup())
+ const_cast<TpiStream*>(this)->buildHashMap();
+
+ uint32_t Bucket = hashStringV1(Name) % Header->NumHashBuckets;
+ if (Bucket > HashMap.size())
+ return {};
+
+ std::vector<TypeIndex> Result;
+ for (TypeIndex TI : HashMap[Bucket]) {
+ std::string ThisName = computeTypeName(*Types, TI);
+ if (ThisName == Name)
+ Result.push_back(TI);
+ }
+ return Result;
+}
+
+bool TpiStream::supportsTypeLookup() const { return !HashMap.empty(); }
+
+Expected<TypeIndex>
+TpiStream::findFullDeclForForwardRef(TypeIndex ForwardRefTI) const {
+ if (!supportsTypeLookup())
+ const_cast<TpiStream*>(this)->buildHashMap();
+
+ CVType F = Types->getType(ForwardRefTI);
+ if (!isUdtForwardRef(F))
+ return ForwardRefTI;
+
+ Expected<TagRecordHash> ForwardTRH = hashTagRecord(F);
+ if (!ForwardTRH)
+ return ForwardTRH.takeError();
+
+ uint32_t BucketIdx = ForwardTRH->FullRecordHash % Header->NumHashBuckets;
+
+ for (TypeIndex TI : HashMap[BucketIdx]) {
+ CVType CVT = Types->getType(TI);
+ if (CVT.kind() != F.kind())
+ continue;
+
+ Expected<TagRecordHash> FullTRH = hashTagRecord(CVT);
+ if (!FullTRH)
+ return FullTRH.takeError();
+ if (ForwardTRH->FullRecordHash != FullTRH->FullRecordHash)
+ continue;
+ TagRecord &ForwardTR = ForwardTRH->getRecord();
+ TagRecord &FullTR = FullTRH->getRecord();
+
+ if (!ForwardTR.hasUniqueName()) {
+ if (ForwardTR.getName() == FullTR.getName())
+ return TI;
+ continue;
+ }
+
+ if (!FullTR.hasUniqueName())
+ continue;
+ if (ForwardTR.getUniqueName() == FullTR.getUniqueName())
+ return TI;
+ }
+ return ForwardRefTI;
+}
+
+codeview::CVType TpiStream::getType(codeview::TypeIndex Index) {
+ assert(!Index.isSimple());
+ return Types->getType(Index);
+}
+
+BinarySubstreamRef TpiStream::getTypeRecordsSubstream() const {
+ return TypeRecordsSubstream;
+}
+
+FixedStreamArray<support::ulittle32_t> TpiStream::getHashValues() const {
+ return HashValues;
+}
+
+FixedStreamArray<TypeIndexOffset> TpiStream::getTypeIndexOffsets() const {
+ return TypeIndexOffsets;
+}
+
+HashTable<support::ulittle32_t> &TpiStream::getHashAdjusters() {
+ return HashAdjusters;
+}
+
+CVTypeRange TpiStream::types(bool *HadError) const {
+ return make_range(TypeRecords.begin(HadError), TypeRecords.end());
+}
+
+Error TpiStream::commit() { return Error::success(); }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp
new file mode 100644
index 0000000000..5f4f497690
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/Native/TpiStreamBuilder.cpp
@@ -0,0 +1,214 @@
+//===- TpiStreamBuilder.cpp - -------------------------------------------===//
+//
+// 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/PDB/Native/TpiStreamBuilder.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/CodeView/TypeIndex.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+#include "llvm/DebugInfo/MSF/MSFBuilder.h"
+#include "llvm/DebugInfo/MSF/MappedBlockStream.h"
+#include "llvm/DebugInfo/PDB/Native/PDBFile.h"
+#include "llvm/DebugInfo/PDB/Native/RawError.h"
+#include "llvm/DebugInfo/PDB/Native/RawTypes.h"
+#include "llvm/Support/Allocator.h"
+#include "llvm/Support/BinaryByteStream.h"
+#include "llvm/Support/BinaryStreamArray.h"
+#include "llvm/Support/BinaryStreamReader.h"
+#include "llvm/Support/BinaryStreamWriter.h"
+#include "llvm/Support/Endian.h"
+#include "llvm/Support/Error.h"
+#include <algorithm>
+#include <cstdint>
+#include <numeric>
+
+using namespace llvm;
+using namespace llvm::msf;
+using namespace llvm::pdb;
+using namespace llvm::support;
+
+TpiStreamBuilder::TpiStreamBuilder(MSFBuilder &Msf, uint32_t StreamIdx)
+ : Msf(Msf), Allocator(Msf.getAllocator()), Header(nullptr), Idx(StreamIdx) {
+}
+
+TpiStreamBuilder::~TpiStreamBuilder() = default;
+
+void TpiStreamBuilder::setVersionHeader(PdbRaw_TpiVer Version) {
+ VerHeader = Version;
+}
+
+void TpiStreamBuilder::updateTypeIndexOffsets(ArrayRef<uint16_t> Sizes) {
+ // If we just crossed an 8KB threshold, add a type index offset.
+ for (uint16_t Size : Sizes) {
+ size_t NewSize = TypeRecordBytes + Size;
+ constexpr size_t EightKB = 8 * 1024;
+ if (NewSize / EightKB > TypeRecordBytes / EightKB || TypeRecordCount == 0) {
+ TypeIndexOffsets.push_back(
+ {codeview::TypeIndex(codeview::TypeIndex::FirstNonSimpleIndex +
+ TypeRecordCount),
+ ulittle32_t(TypeRecordBytes)});
+ }
+ ++TypeRecordCount;
+ TypeRecordBytes = NewSize;
+ }
+}
+
+void TpiStreamBuilder::addTypeRecord(ArrayRef<uint8_t> Record,
+ Optional<uint32_t> Hash) {
+ assert(((Record.size() & 3) == 0) &&
+ "The type record's size is not a multiple of 4 bytes which will "
+ "cause misalignment in the output TPI stream!");
+ assert(Record.size() <= codeview::MaxRecordLength);
+ uint16_t OneSize = (uint16_t)Record.size();
+ updateTypeIndexOffsets(makeArrayRef(&OneSize, 1));
+
+ TypeRecBuffers.push_back(Record);
+ // FIXME: Require it.
+ if (Hash)
+ TypeHashes.push_back(*Hash);
+}
+
+void TpiStreamBuilder::addTypeRecords(ArrayRef<uint8_t> Types,
+ ArrayRef<uint16_t> Sizes,
+ ArrayRef<uint32_t> Hashes) {
+ // Ignore empty type buffers. There should be no hashes or sizes in this case.
+ if (Types.empty()) {
+ assert(Sizes.empty() && Hashes.empty());
+ return;
+ }
+
+ assert(((Types.size() & 3) == 0) &&
+ "The type record's size is not a multiple of 4 bytes which will "
+ "cause misalignment in the output TPI stream!");
+ assert(Sizes.size() == Hashes.size() && "sizes and hashes should be in sync");
+ assert(std::accumulate(Sizes.begin(), Sizes.end(), 0U) == Types.size() &&
+ "sizes of type records should sum to the size of the types");
+ updateTypeIndexOffsets(Sizes);
+
+ TypeRecBuffers.push_back(Types);
+ llvm::append_range(TypeHashes, Hashes);
+}
+
+Error TpiStreamBuilder::finalize() {
+ if (Header)
+ return Error::success();
+
+ TpiStreamHeader *H = Allocator.Allocate<TpiStreamHeader>();
+
+ H->Version = VerHeader;
+ H->HeaderSize = sizeof(TpiStreamHeader);
+ H->TypeIndexBegin = codeview::TypeIndex::FirstNonSimpleIndex;
+ H->TypeIndexEnd = H->TypeIndexBegin + TypeRecordCount;
+ H->TypeRecordBytes = TypeRecordBytes;
+
+ H->HashStreamIndex = HashStreamIndex;
+ H->HashAuxStreamIndex = kInvalidStreamIndex;
+ H->HashKeySize = sizeof(ulittle32_t);
+ H->NumHashBuckets = MaxTpiHashBuckets - 1;
+
+ // Recall that hash values go into a completely different stream identified by
+ // the `HashStreamIndex` field of the `TpiStreamHeader`. Therefore, the data
+ // begins at offset 0 of this independent stream.
+ H->HashValueBuffer.Off = 0;
+ H->HashValueBuffer.Length = calculateHashBufferSize();
+
+ // We never write any adjustments into our PDBs, so this is usually some
+ // offset with zero length.
+ H->HashAdjBuffer.Off = H->HashValueBuffer.Off + H->HashValueBuffer.Length;
+ H->HashAdjBuffer.Length = 0;
+
+ H->IndexOffsetBuffer.Off = H->HashAdjBuffer.Off + H->HashAdjBuffer.Length;
+ H->IndexOffsetBuffer.Length = calculateIndexOffsetSize();
+
+ Header = H;
+ return Error::success();
+}
+
+uint32_t TpiStreamBuilder::calculateSerializedLength() {
+ return sizeof(TpiStreamHeader) + TypeRecordBytes;
+}
+
+uint32_t TpiStreamBuilder::calculateHashBufferSize() const {
+ assert((TypeRecordCount == TypeHashes.size() || TypeHashes.empty()) &&
+ "either all or no type records should have hashes");
+ return TypeHashes.size() * sizeof(ulittle32_t);
+}
+
+uint32_t TpiStreamBuilder::calculateIndexOffsetSize() const {
+ return TypeIndexOffsets.size() * sizeof(codeview::TypeIndexOffset);
+}
+
+Error TpiStreamBuilder::finalizeMsfLayout() {
+ uint32_t Length = calculateSerializedLength();
+ if (auto EC = Msf.setStreamSize(Idx, Length))
+ return EC;
+
+ uint32_t HashStreamSize =
+ calculateHashBufferSize() + calculateIndexOffsetSize();
+
+ if (HashStreamSize == 0)
+ return Error::success();
+
+ auto ExpectedIndex = Msf.addStream(HashStreamSize);
+ if (!ExpectedIndex)
+ return ExpectedIndex.takeError();
+ HashStreamIndex = *ExpectedIndex;
+ if (!TypeHashes.empty()) {
+ ulittle32_t *H = Allocator.Allocate<ulittle32_t>(TypeHashes.size());
+ MutableArrayRef<ulittle32_t> HashBuffer(H, TypeHashes.size());
+ for (uint32_t I = 0; I < TypeHashes.size(); ++I) {
+ HashBuffer[I] = TypeHashes[I] % (MaxTpiHashBuckets - 1);
+ }
+ ArrayRef<uint8_t> Bytes(
+ reinterpret_cast<const uint8_t *>(HashBuffer.data()),
+ calculateHashBufferSize());
+ HashValueStream =
+ std::make_unique<BinaryByteStream>(Bytes, llvm::support::little);
+ }
+ return Error::success();
+}
+
+Error TpiStreamBuilder::commit(const msf::MSFLayout &Layout,
+ WritableBinaryStreamRef Buffer) {
+ if (auto EC = finalize())
+ return EC;
+
+ auto InfoS = WritableMappedBlockStream::createIndexedStream(Layout, Buffer,
+ Idx, Allocator);
+
+ BinaryStreamWriter Writer(*InfoS);
+ if (auto EC = Writer.writeObject(*Header))
+ return EC;
+
+ for (auto Rec : TypeRecBuffers) {
+ assert(!Rec.empty() && "Attempting to write an empty type record shifts "
+ "all offsets in the TPI stream!");
+ assert(((Rec.size() & 3) == 0) &&
+ "The type record's size is not a multiple of 4 bytes which will "
+ "cause misalignment in the output TPI stream!");
+ if (auto EC = Writer.writeBytes(Rec))
+ return EC;
+ }
+
+ if (HashStreamIndex != kInvalidStreamIndex) {
+ auto HVS = WritableMappedBlockStream::createIndexedStream(
+ Layout, Buffer, HashStreamIndex, Allocator);
+ BinaryStreamWriter HW(*HVS);
+ if (HashValueStream) {
+ if (auto EC = HW.writeStreamRef(*HashValueStream))
+ return EC;
+ }
+
+ for (auto &IndexOffset : TypeIndexOffsets) {
+ if (auto EC = HW.writeObject(IndexOffset))
+ return EC;
+ }
+ }
+
+ return Error::success();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDB.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDB.cpp
new file mode 100644
index 0000000000..6dc42715fb
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDB.cpp
@@ -0,0 +1,51 @@
+//===- PDB.cpp - base header file for creating a PDB reader ---------------===//
+//
+// 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/PDB/PDB.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/Config/config.h"
+#include "llvm/DebugInfo/PDB/GenericError.h"
+#if LLVM_ENABLE_DIA_SDK
+#error #include "llvm/DebugInfo/PDB/DIA/DIASession.h"
+#endif
+#include "llvm/DebugInfo/PDB/Native/NativeSession.h"
+#include "llvm/Support/Error.h"
+#include "llvm/Support/MemoryBuffer.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+Error llvm::pdb::loadDataForPDB(PDB_ReaderType Type, StringRef Path,
+ std::unique_ptr<IPDBSession> &Session) {
+ // Create the correct concrete instance type based on the value of Type.
+ if (Type == PDB_ReaderType::Native)
+ return NativeSession::createFromPdbPath(Path, Session);
+
+#if LLVM_ENABLE_DIA_SDK
+ return DIASession::createFromPdb(Path, Session);
+#else
+ return make_error<PDBError>(pdb_error_code::dia_sdk_not_present);
+#endif
+}
+
+Error llvm::pdb::loadDataForEXE(PDB_ReaderType Type, StringRef Path,
+ std::unique_ptr<IPDBSession> &Session) {
+ // Create the correct concrete instance type based on the value of Type.
+ if (Type == PDB_ReaderType::Native) {
+ Expected<std::string> PdbPath = NativeSession::searchForPdb({Path});
+ if (!PdbPath)
+ return PdbPath.takeError();
+ return NativeSession::createFromPdbPath(PdbPath.get(), Session);
+ }
+
+#if LLVM_ENABLE_DIA_SDK
+ return DIASession::createFromExe(Path, Session);
+#else
+ return make_error<PDBError>(pdb_error_code::dia_sdk_not_present);
+#endif
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBContext.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBContext.cpp
new file mode 100644
index 0000000000..0ebb70e010
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBContext.cpp
@@ -0,0 +1,159 @@
+//===-- PDBContext.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/PDB/PDBContext.h"
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
+#include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h"
+#include "llvm/Object/COFF.h"
+
+using namespace llvm;
+using namespace llvm::object;
+using namespace llvm::pdb;
+
+PDBContext::PDBContext(const COFFObjectFile &Object,
+ std::unique_ptr<IPDBSession> PDBSession)
+ : DIContext(CK_PDB), Session(std::move(PDBSession)) {
+ ErrorOr<uint64_t> ImageBase = Object.getImageBase();
+ if (ImageBase)
+ Session->setLoadAddress(ImageBase.get());
+}
+
+void PDBContext::dump(raw_ostream &OS, DIDumpOptions DumpOpts){}
+
+DILineInfo PDBContext::getLineInfoForAddress(object::SectionedAddress Address,
+ DILineInfoSpecifier Specifier) {
+ DILineInfo Result;
+ Result.FunctionName = getFunctionName(Address.Address, Specifier.FNKind);
+
+ uint32_t Length = 1;
+ std::unique_ptr<PDBSymbol> Symbol =
+ Session->findSymbolByAddress(Address.Address, PDB_SymType::None);
+ if (auto Func = dyn_cast_or_null<PDBSymbolFunc>(Symbol.get())) {
+ Length = Func->getLength();
+ } else if (auto Data = dyn_cast_or_null<PDBSymbolData>(Symbol.get())) {
+ Length = Data->getLength();
+ }
+
+ // If we couldn't find a symbol, then just assume 1 byte, so that we get
+ // only the line number of the first instruction.
+ auto LineNumbers = Session->findLineNumbersByAddress(Address.Address, Length);
+ if (!LineNumbers || LineNumbers->getChildCount() == 0)
+ return Result;
+
+ auto LineInfo = LineNumbers->getNext();
+ assert(LineInfo);
+ auto SourceFile = Session->getSourceFileById(LineInfo->getSourceFileId());
+
+ if (SourceFile &&
+ Specifier.FLIKind != DILineInfoSpecifier::FileLineInfoKind::None)
+ Result.FileName = SourceFile->getFileName();
+ Result.Column = LineInfo->getColumnNumber();
+ Result.Line = LineInfo->getLineNumber();
+ return Result;
+}
+
+DILineInfoTable
+PDBContext::getLineInfoForAddressRange(object::SectionedAddress Address,
+ uint64_t Size,
+ DILineInfoSpecifier Specifier) {
+ if (Size == 0)
+ return DILineInfoTable();
+
+ DILineInfoTable Table;
+ auto LineNumbers = Session->findLineNumbersByAddress(Address.Address, Size);
+ if (!LineNumbers || LineNumbers->getChildCount() == 0)
+ return Table;
+
+ while (auto LineInfo = LineNumbers->getNext()) {
+ DILineInfo LineEntry = getLineInfoForAddress(
+ {LineInfo->getVirtualAddress(), Address.SectionIndex}, Specifier);
+ Table.push_back(std::make_pair(LineInfo->getVirtualAddress(), LineEntry));
+ }
+ return Table;
+}
+
+DIInliningInfo
+PDBContext::getInliningInfoForAddress(object::SectionedAddress Address,
+ DILineInfoSpecifier Specifier) {
+ DIInliningInfo InlineInfo;
+ DILineInfo CurrentLine = getLineInfoForAddress(Address, Specifier);
+
+ // Find the function at this address.
+ std::unique_ptr<PDBSymbol> ParentFunc =
+ Session->findSymbolByAddress(Address.Address, PDB_SymType::Function);
+ if (!ParentFunc) {
+ InlineInfo.addFrame(CurrentLine);
+ return InlineInfo;
+ }
+
+ auto Frames = ParentFunc->findInlineFramesByVA(Address.Address);
+ if (!Frames || Frames->getChildCount() == 0) {
+ InlineInfo.addFrame(CurrentLine);
+ return InlineInfo;
+ }
+
+ while (auto Frame = Frames->getNext()) {
+ uint32_t Length = 1;
+ auto LineNumbers = Frame->findInlineeLinesByVA(Address.Address, Length);
+ if (!LineNumbers || LineNumbers->getChildCount() == 0)
+ break;
+
+ std::unique_ptr<IPDBLineNumber> Line = LineNumbers->getNext();
+ assert(Line);
+
+ DILineInfo LineInfo;
+ LineInfo.FunctionName = Frame->getName();
+ auto SourceFile = Session->getSourceFileById(Line->getSourceFileId());
+ if (SourceFile &&
+ Specifier.FLIKind != DILineInfoSpecifier::FileLineInfoKind::None)
+ LineInfo.FileName = SourceFile->getFileName();
+ LineInfo.Line = Line->getLineNumber();
+ LineInfo.Column = Line->getColumnNumber();
+ InlineInfo.addFrame(LineInfo);
+ }
+
+ InlineInfo.addFrame(CurrentLine);
+ return InlineInfo;
+}
+
+std::vector<DILocal>
+PDBContext::getLocalsForAddress(object::SectionedAddress Address) {
+ return std::vector<DILocal>();
+}
+
+std::string PDBContext::getFunctionName(uint64_t Address,
+ DINameKind NameKind) const {
+ if (NameKind == DINameKind::None)
+ return std::string();
+
+ std::unique_ptr<PDBSymbol> FuncSymbol =
+ Session->findSymbolByAddress(Address, PDB_SymType::Function);
+ auto *Func = dyn_cast_or_null<PDBSymbolFunc>(FuncSymbol.get());
+
+ if (NameKind == DINameKind::LinkageName) {
+ // It is not possible to get the mangled linkage name through a
+ // PDBSymbolFunc. For that we have to specifically request a
+ // PDBSymbolPublicSymbol.
+ auto PublicSym =
+ Session->findSymbolByAddress(Address, PDB_SymType::PublicSymbol);
+ if (auto *PS = dyn_cast_or_null<PDBSymbolPublicSymbol>(PublicSym.get())) {
+ // If we also have a function symbol, prefer the use of public symbol name
+ // only if it refers to the same address. The public symbol uses the
+ // linkage name while the function does not.
+ if (!Func || Func->getVirtualAddress() == PS->getVirtualAddress())
+ return PS->getName();
+ }
+ }
+
+ return Func ? Func->getName() : std::string();
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBExtras.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBExtras.cpp
new file mode 100644
index 0000000000..a6d7ca0da7
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBExtras.cpp
@@ -0,0 +1,408 @@
+//===- PDBExtras.cpp - helper functions and classes for PDBs --------------===//
+//
+// 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/PDB/PDBExtras.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/Support/raw_ostream.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+#define CASE_OUTPUT_ENUM_CLASS_STR(Class, Value, Str, Stream) \
+ case Class::Value: \
+ Stream << Str; \
+ break;
+
+#define CASE_OUTPUT_ENUM_CLASS_NAME(Class, Value, Stream) \
+ CASE_OUTPUT_ENUM_CLASS_STR(Class, Value, #Value, Stream)
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const PDB_VariantType &Type) {
+ switch (Type) {
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Bool, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Single, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Double, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Int8, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Int16, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Int32, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, Int64, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, UInt8, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, UInt16, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, UInt32, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_VariantType, UInt64, OS)
+ default:
+ OS << "Unknown";
+ }
+ return OS;
+}
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const PDB_BuiltinType &Type) {
+ switch (Type) {
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, None, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Void, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Char, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, WCharT, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Int, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, UInt, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Float, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, BCD, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Bool, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Long, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, ULong, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Currency, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Date, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Variant, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Complex, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Bitfield, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, BSTR, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, HResult, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Char16, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_BuiltinType, Char32, OS)
+ }
+ return OS;
+}
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const PDB_CallingConv &Conv) {
+ OS << "__";
+ switch (Conv) {
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearC , "cdecl", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarC , "cdecl", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearPascal , "pascal", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarPascal , "pascal", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearFast , "fastcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarFast , "fastcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearStdCall, "stdcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarStdCall , "stdcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearSysCall, "syscall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, FarSysCall , "syscall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, ThisCall , "thiscall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, MipsCall , "mipscall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Generic , "genericcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, AlphaCall , "alphacall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, PpcCall , "ppccall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, SHCall , "superhcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, ArmCall , "armcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, AM33Call , "am33call", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, TriCall , "tricall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, SH5Call , "sh5call", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, M32RCall , "m32rcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, ClrCall , "clrcall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, Inline , "inlinecall", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_CallingConv, NearVector , "vectorcall", OS)
+ }
+ return OS;
+}
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_DataKind &Data) {
+ switch (Data) {
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Unknown, "unknown", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Local, "local", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, StaticLocal, "static local", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Param, "param", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, ObjectPtr, "this ptr", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, FileStatic, "static global", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Global, "global", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Member, "member", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, StaticMember, "static member", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_DataKind, Constant, "const", OS)
+ }
+ return OS;
+}
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const llvm::codeview::CPURegister &CpuReg) {
+ if (CpuReg.Cpu == llvm::codeview::CPUType::ARMNT) {
+ switch (CpuReg.Reg) {
+#define CV_REGISTERS_ARM
+#define CV_REGISTER(name, val) \
+ case codeview::RegisterId::name: \
+ OS << #name; \
+ return OS;
+#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"
+#undef CV_REGISTER
+#undef CV_REGISTERS_ARM
+
+ default:
+ break;
+ }
+ } else if (CpuReg.Cpu == llvm::codeview::CPUType::ARM64) {
+ switch (CpuReg.Reg) {
+#define CV_REGISTERS_ARM64
+#define CV_REGISTER(name, val) \
+ case codeview::RegisterId::name: \
+ OS << #name; \
+ return OS;
+#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"
+#undef CV_REGISTER
+#undef CV_REGISTERS_ARM64
+
+ default:
+ break;
+ }
+ } else {
+ switch (CpuReg.Reg) {
+#define CV_REGISTERS_X86
+#define CV_REGISTER(name, val) \
+ case codeview::RegisterId::name: \
+ OS << #name; \
+ return OS;
+#include "llvm/DebugInfo/CodeView/CodeViewRegisters.def"
+#undef CV_REGISTER
+#undef CV_REGISTERS_X86
+
+ default:
+ break;
+ }
+ }
+ OS << static_cast<int>(CpuReg.Reg);
+ return OS;
+}
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_LocType &Loc) {
+ switch (Loc) {
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Static, "static", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, TLS, "tls", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, RegRel, "regrel", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, ThisRel, "thisrel", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Enregistered, "register", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, BitField, "bitfield", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Slot, "slot", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, IlRel, "IL rel", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, MetaData, "metadata", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, Constant, "constant", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_LocType, RegRelAliasIndir,
+ "regrelaliasindir", OS)
+ default:
+ OS << "Unknown";
+ }
+ return OS;
+}
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const codeview::ThunkOrdinal &Thunk) {
+ switch (Thunk) {
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, BranchIsland, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, Pcode, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, Standard, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, ThisAdjustor, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, TrampIncremental, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, UnknownLoad, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(codeview::ThunkOrdinal, Vcall, OS)
+ }
+ return OS;
+}
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const PDB_Checksum &Checksum) {
+ switch (Checksum) {
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, None, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, MD5, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, SHA1, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Checksum, SHA256, OS)
+ }
+ return OS;
+}
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_Lang &Lang) {
+ switch (Lang) {
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, C, OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_Lang, Cpp, "C++", OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Fortran, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Masm, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Pascal, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Basic, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Cobol, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Link, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Cvtres, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Cvtpgd, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, CSharp, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, VB, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, ILAsm, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Java, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, JScript, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, MSIL, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, HLSL, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, D, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Swift, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Lang, Rust, OS)
+ }
+ return OS;
+}
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_SymType &Tag) {
+ switch (Tag) {
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Exe, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Compiland, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CompilandDetails, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CompilandEnv, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Function, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Block, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Data, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Annotation, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Label, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, PublicSymbol, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, UDT, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Enum, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, FunctionSig, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, PointerType, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, ArrayType, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, BuiltinType, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Typedef, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, BaseClass, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Friend, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, FunctionArg, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, FuncDebugStart, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, FuncDebugEnd, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, UsingNamespace, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, VTableShape, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, VTable, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Custom, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Thunk, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CustomType, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, ManagedType, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Dimension, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CallSite, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, InlineSite, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, BaseInterface, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, VectorType, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, MatrixType, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, HLSLType, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Caller, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Callee, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Export, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, HeapAllocationSite, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, CoffGroup, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SymType, Inlinee, OS)
+ default:
+ OS << "Unknown SymTag " << uint32_t(Tag);
+ }
+ return OS;
+}
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const PDB_MemberAccess &Access) {
+ switch (Access) {
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_MemberAccess, Public, "public", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_MemberAccess, Protected, "protected", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_MemberAccess, Private, "private", OS)
+ }
+ return OS;
+}
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const PDB_UdtType &Type) {
+ switch (Type) {
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Class, "class", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Struct, "struct", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Interface, "interface", OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_UdtType, Union, "union", OS)
+ }
+ return OS;
+}
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const PDB_Machine &Machine) {
+ switch (Machine) {
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Am33, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Amd64, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Arm, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, ArmNT, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Ebc, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, x86, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Ia64, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, M32R, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Mips16, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, MipsFpu, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, MipsFpu16, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, PowerPC, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, PowerPCFP, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, R4000, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH3, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH3DSP, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH4, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, SH5, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, Thumb, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_Machine, WceMipsV2, OS)
+ default:
+ OS << "Unknown";
+ }
+ return OS;
+}
+
+raw_ostream &llvm::pdb::dumpPDBSourceCompression(raw_ostream &OS,
+ uint32_t Compression) {
+ switch (Compression) {
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, None, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, Huffman, OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, LZ, OS)
+ CASE_OUTPUT_ENUM_CLASS_STR(PDB_SourceCompression, RunLengthEncoded, "RLE",
+ OS)
+ CASE_OUTPUT_ENUM_CLASS_NAME(PDB_SourceCompression, DotNet, OS)
+ default:
+ OS << "Unknown (" << Compression << ")";
+ }
+ return OS;
+}
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const Variant &Value) {
+ switch (Value.Type) {
+ case PDB_VariantType::Bool:
+ OS << (Value.Value.Bool ? "true" : "false");
+ break;
+ case PDB_VariantType::Double:
+ OS << Value.Value.Double;
+ break;
+ case PDB_VariantType::Int16:
+ OS << Value.Value.Int16;
+ break;
+ case PDB_VariantType::Int32:
+ OS << Value.Value.Int32;
+ break;
+ case PDB_VariantType::Int64:
+ OS << Value.Value.Int64;
+ break;
+ case PDB_VariantType::Int8:
+ OS << static_cast<int>(Value.Value.Int8);
+ break;
+ case PDB_VariantType::Single:
+ OS << Value.Value.Single;
+ break;
+ case PDB_VariantType::UInt16:
+ OS << Value.Value.UInt16;
+ break;
+ case PDB_VariantType::UInt32:
+ OS << Value.Value.UInt32;
+ break;
+ case PDB_VariantType::UInt64:
+ OS << Value.Value.UInt64;
+ break;
+ case PDB_VariantType::UInt8:
+ OS << static_cast<unsigned>(Value.Value.UInt8);
+ break;
+ case PDB_VariantType::String:
+ OS << Value.Value.String;
+ break;
+ default:
+ OS << Value.Type;
+ }
+ return OS;
+}
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS,
+ const VersionInfo &Version) {
+ OS << Version.Major << "." << Version.Minor << "." << Version.Build;
+ return OS;
+}
+
+raw_ostream &llvm::pdb::operator<<(raw_ostream &OS, const TagStats &Stats) {
+ for (auto Tag : Stats) {
+ OS << Tag.first << ":" << Tag.second << " ";
+ }
+ return OS;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp
new file mode 100644
index 0000000000..d51091d809
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBInterfaceAnchors.cpp
@@ -0,0 +1,39 @@
+//===- PDBInterfaceAnchors.h - defines class anchor functions ---*- 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
+//
+//===----------------------------------------------------------------------===//
+// Class anchors are necessary per the LLVM Coding style guide, to ensure that
+// the vtable is only generated in this object file, and not in every object
+// file that includes the corresponding header.
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/PDB/IPDBDataStream.h"
+#include "llvm/DebugInfo/PDB/IPDBFrameData.h"
+#include "llvm/DebugInfo/PDB/IPDBInjectedSource.h"
+#include "llvm/DebugInfo/PDB/IPDBLineNumber.h"
+#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
+#include "llvm/DebugInfo/PDB/IPDBSectionContrib.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/IPDBTable.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+IPDBSession::~IPDBSession() = default;
+
+IPDBDataStream::~IPDBDataStream() = default;
+
+IPDBRawSymbol::~IPDBRawSymbol() = default;
+
+IPDBLineNumber::~IPDBLineNumber() = default;
+
+IPDBTable::~IPDBTable() = default;
+
+IPDBInjectedSource::~IPDBInjectedSource() = default;
+
+IPDBSectionContrib::~IPDBSectionContrib() = default;
+
+IPDBFrameData::~IPDBFrameData() = default;
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymDumper.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymDumper.cpp
new file mode 100644
index 0000000000..0956a32f4a
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymDumper.cpp
@@ -0,0 +1,146 @@
+//===- PDBSymDumper.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/PDB/PDBSymDumper.h"
+#include "llvm/Support/ErrorHandling.h"
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+#define PDB_SYMDUMP_UNREACHABLE(Type) \
+ if (RequireImpl) \
+ llvm_unreachable("Attempt to dump " #Type " with no dump implementation");
+
+PDBSymDumper::PDBSymDumper(bool ShouldRequireImpl)
+ : RequireImpl(ShouldRequireImpl) {}
+
+PDBSymDumper::~PDBSymDumper() = default;
+
+void PDBSymDumper::dump(const PDBSymbolAnnotation &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolAnnotation)
+}
+
+void PDBSymDumper::dump(const PDBSymbolBlock &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolBlock)
+}
+
+void PDBSymDumper::dump(const PDBSymbolCompiland &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolCompiland)
+}
+
+void PDBSymDumper::dump(const PDBSymbolCompilandDetails &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolCompilandDetails)
+}
+
+void PDBSymDumper::dump(const PDBSymbolCompilandEnv &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolCompilandEnv)
+}
+
+void PDBSymDumper::dump(const PDBSymbolCustom &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolCustom)
+}
+
+void PDBSymDumper::dump(const PDBSymbolData &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolData)
+}
+
+void PDBSymDumper::dump(const PDBSymbolExe &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolExe)
+}
+
+void PDBSymDumper::dump(const PDBSymbolFunc &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolFunc)
+}
+
+void PDBSymDumper::dump(const PDBSymbolFuncDebugEnd &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolFuncDebugEnd)
+}
+
+void PDBSymDumper::dump(const PDBSymbolFuncDebugStart &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolFuncDebugStart)
+}
+
+void PDBSymDumper::dump(const PDBSymbolLabel &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolLabel)
+}
+
+void PDBSymDumper::dump(const PDBSymbolPublicSymbol &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolPublicSymbol)
+}
+
+void PDBSymDumper::dump(const PDBSymbolThunk &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolThunk)
+}
+
+void PDBSymDumper::dump(const PDBSymbolTypeArray &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeArray)
+}
+
+void PDBSymDumper::dump(const PDBSymbolTypeBaseClass &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeBaseClass)
+}
+
+void PDBSymDumper::dump(const PDBSymbolTypeBuiltin &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeBuiltin)
+}
+
+void PDBSymDumper::dump(const PDBSymbolTypeCustom &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeCustom)
+}
+
+void PDBSymDumper::dump(const PDBSymbolTypeDimension &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeDimension)
+}
+
+void PDBSymDumper::dump(const PDBSymbolTypeEnum &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeEnum)
+}
+
+void PDBSymDumper::dump(const PDBSymbolTypeFriend &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeFriend)
+}
+
+void PDBSymDumper::dump(const PDBSymbolTypeFunctionArg &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeFunctionArg)
+}
+
+void PDBSymDumper::dump(const PDBSymbolTypeFunctionSig &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeFunctionSig)
+}
+
+void PDBSymDumper::dump(const PDBSymbolTypeManaged &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeManaged)
+}
+
+void PDBSymDumper::dump(const PDBSymbolTypePointer &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypePointer)
+}
+
+void PDBSymDumper::dump(const PDBSymbolTypeTypedef &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeTypedef)
+}
+
+void PDBSymDumper::dump(const PDBSymbolTypeUDT &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeUDT)
+}
+
+void PDBSymDumper::dump(const PDBSymbolTypeVTable &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeVTable)
+}
+
+void PDBSymDumper::dump(const PDBSymbolTypeVTableShape &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolTypeVTableShape)
+}
+
+void PDBSymDumper::dump(const PDBSymbolUnknown &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolUnknown)
+}
+
+void PDBSymDumper::dump(const PDBSymbolUsingNamespace &Symbol) {
+ PDB_SYMDUMP_UNREACHABLE(PDBSymbolUsingNamespace)
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbol.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbol.cpp
new file mode 100644
index 0000000000..d6bc7ee9c9
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbol.cpp
@@ -0,0 +1,231 @@
+//===- PDBSymbol.cpp - base class for user-facing symbol types --*- 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/PDB/PDBSymbol.h"
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBExtras.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolAnnotation.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolBlock.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCustom.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugEnd.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFuncDebugStart.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolLabel.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolPublicSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolThunk.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeArray.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeCustom.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeDimension.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeEnum.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFriend.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeManaged.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeTypedef.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolUnknown.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolUsingNamespace.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include <algorithm>
+#include <memory>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+PDBSymbol::PDBSymbol(const IPDBSession &PDBSession) : Session(PDBSession) {}
+
+PDBSymbol::PDBSymbol(PDBSymbol &&Other)
+ : Session(Other.Session), RawSymbol(std::move(Other.RawSymbol)) {}
+
+PDBSymbol::~PDBSymbol() = default;
+
+#define FACTORY_SYMTAG_CASE(Tag, Type) \
+ case PDB_SymType::Tag: \
+ return std::unique_ptr<PDBSymbol>(new Type(PDBSession));
+
+std::unique_ptr<PDBSymbol>
+PDBSymbol::createSymbol(const IPDBSession &PDBSession, PDB_SymType Tag) {
+ switch (Tag) {
+ FACTORY_SYMTAG_CASE(Exe, PDBSymbolExe)
+ FACTORY_SYMTAG_CASE(Compiland, PDBSymbolCompiland)
+ FACTORY_SYMTAG_CASE(CompilandDetails, PDBSymbolCompilandDetails)
+ FACTORY_SYMTAG_CASE(CompilandEnv, PDBSymbolCompilandEnv)
+ FACTORY_SYMTAG_CASE(Function, PDBSymbolFunc)
+ FACTORY_SYMTAG_CASE(Block, PDBSymbolBlock)
+ FACTORY_SYMTAG_CASE(Data, PDBSymbolData)
+ FACTORY_SYMTAG_CASE(Annotation, PDBSymbolAnnotation)
+ FACTORY_SYMTAG_CASE(Label, PDBSymbolLabel)
+ FACTORY_SYMTAG_CASE(PublicSymbol, PDBSymbolPublicSymbol)
+ FACTORY_SYMTAG_CASE(UDT, PDBSymbolTypeUDT)
+ FACTORY_SYMTAG_CASE(Enum, PDBSymbolTypeEnum)
+ FACTORY_SYMTAG_CASE(FunctionSig, PDBSymbolTypeFunctionSig)
+ FACTORY_SYMTAG_CASE(PointerType, PDBSymbolTypePointer)
+ FACTORY_SYMTAG_CASE(ArrayType, PDBSymbolTypeArray)
+ FACTORY_SYMTAG_CASE(BuiltinType, PDBSymbolTypeBuiltin)
+ FACTORY_SYMTAG_CASE(Typedef, PDBSymbolTypeTypedef)
+ FACTORY_SYMTAG_CASE(BaseClass, PDBSymbolTypeBaseClass)
+ FACTORY_SYMTAG_CASE(Friend, PDBSymbolTypeFriend)
+ FACTORY_SYMTAG_CASE(FunctionArg, PDBSymbolTypeFunctionArg)
+ FACTORY_SYMTAG_CASE(FuncDebugStart, PDBSymbolFuncDebugStart)
+ FACTORY_SYMTAG_CASE(FuncDebugEnd, PDBSymbolFuncDebugEnd)
+ FACTORY_SYMTAG_CASE(UsingNamespace, PDBSymbolUsingNamespace)
+ FACTORY_SYMTAG_CASE(VTableShape, PDBSymbolTypeVTableShape)
+ FACTORY_SYMTAG_CASE(VTable, PDBSymbolTypeVTable)
+ FACTORY_SYMTAG_CASE(Custom, PDBSymbolCustom)
+ FACTORY_SYMTAG_CASE(Thunk, PDBSymbolThunk)
+ FACTORY_SYMTAG_CASE(CustomType, PDBSymbolTypeCustom)
+ FACTORY_SYMTAG_CASE(ManagedType, PDBSymbolTypeManaged)
+ FACTORY_SYMTAG_CASE(Dimension, PDBSymbolTypeDimension)
+ default:
+ return std::unique_ptr<PDBSymbol>(new PDBSymbolUnknown(PDBSession));
+ }
+}
+
+std::unique_ptr<PDBSymbol>
+PDBSymbol::create(const IPDBSession &PDBSession,
+ std::unique_ptr<IPDBRawSymbol> RawSymbol) {
+ auto SymbolPtr = createSymbol(PDBSession, RawSymbol->getSymTag());
+ SymbolPtr->RawSymbol = RawSymbol.get();
+ SymbolPtr->OwnedRawSymbol = std::move(RawSymbol);
+ return SymbolPtr;
+}
+
+std::unique_ptr<PDBSymbol> PDBSymbol::create(const IPDBSession &PDBSession,
+ IPDBRawSymbol &RawSymbol) {
+ auto SymbolPtr = createSymbol(PDBSession, RawSymbol.getSymTag());
+ SymbolPtr->RawSymbol = &RawSymbol;
+ return SymbolPtr;
+}
+
+void PDBSymbol::defaultDump(raw_ostream &OS, int Indent,
+ PdbSymbolIdField ShowFlags,
+ PdbSymbolIdField RecurseFlags) const {
+ RawSymbol->dump(OS, Indent, ShowFlags, RecurseFlags);
+}
+
+void PDBSymbol::dumpProperties() const {
+ outs() << "\n";
+ defaultDump(outs(), 0, PdbSymbolIdField::All, PdbSymbolIdField::None);
+ outs().flush();
+}
+
+void PDBSymbol::dumpChildStats() const {
+ TagStats Stats;
+ getChildStats(Stats);
+ outs() << "\n";
+ for (auto &Stat : Stats) {
+ outs() << Stat.first << ": " << Stat.second << "\n";
+ }
+ outs().flush();
+}
+
+PDB_SymType PDBSymbol::getSymTag() const { return RawSymbol->getSymTag(); }
+uint32_t PDBSymbol::getSymIndexId() const { return RawSymbol->getSymIndexId(); }
+
+std::unique_ptr<IPDBEnumSymbols> PDBSymbol::findAllChildren() const {
+ return findAllChildren(PDB_SymType::None);
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+PDBSymbol::findAllChildren(PDB_SymType Type) const {
+ return RawSymbol->findChildren(Type);
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+PDBSymbol::findChildren(PDB_SymType Type, StringRef Name,
+ PDB_NameSearchFlags Flags) const {
+ return RawSymbol->findChildren(Type, Name, Flags);
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+PDBSymbol::findChildrenByRVA(PDB_SymType Type, StringRef Name,
+ PDB_NameSearchFlags Flags, uint32_t RVA) const {
+ return RawSymbol->findChildrenByRVA(Type, Name, Flags, RVA);
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+PDBSymbol::findInlineFramesByVA(uint64_t VA) const {
+ return RawSymbol->findInlineFramesByVA(VA);
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+PDBSymbol::findInlineFramesByRVA(uint32_t RVA) const {
+ return RawSymbol->findInlineFramesByRVA(RVA);
+}
+
+std::unique_ptr<IPDBEnumLineNumbers>
+PDBSymbol::findInlineeLinesByVA(uint64_t VA, uint32_t Length) const {
+ return RawSymbol->findInlineeLinesByVA(VA, Length);
+}
+
+std::unique_ptr<IPDBEnumLineNumbers>
+PDBSymbol::findInlineeLinesByRVA(uint32_t RVA, uint32_t Length) const {
+ return RawSymbol->findInlineeLinesByRVA(RVA, Length);
+}
+
+std::string PDBSymbol::getName() const { return RawSymbol->getName(); }
+
+std::unique_ptr<IPDBEnumSymbols>
+PDBSymbol::getChildStats(TagStats &Stats) const {
+ std::unique_ptr<IPDBEnumSymbols> Result(findAllChildren());
+ if (!Result)
+ return nullptr;
+ Stats.clear();
+ while (auto Child = Result->getNext()) {
+ ++Stats[Child->getSymTag()];
+ }
+ Result->reset();
+ return Result;
+}
+
+std::unique_ptr<PDBSymbol> PDBSymbol::getSymbolByIdHelper(uint32_t Id) const {
+ return Session.getSymbolById(Id);
+}
+
+void llvm::pdb::dumpSymbolIdField(raw_ostream &OS, StringRef Name,
+ SymIndexId Value, int Indent,
+ const IPDBSession &Session,
+ PdbSymbolIdField FieldId,
+ PdbSymbolIdField ShowFlags,
+ PdbSymbolIdField RecurseFlags) {
+ if ((FieldId & ShowFlags) == PdbSymbolIdField::None)
+ return;
+
+ OS << "\n";
+ OS.indent(Indent);
+ OS << Name << ": " << Value;
+ // Don't recurse unless the user requested it.
+ if ((FieldId & RecurseFlags) == PdbSymbolIdField::None)
+ return;
+ // And obviously don't recurse on the symbol itself.
+ if (FieldId == PdbSymbolIdField::SymIndexId)
+ return;
+
+ auto Child = Session.getSymbolById(Value);
+
+ // It could have been a placeholder symbol for a type we don't yet support,
+ // so just exit in that case.
+ if (!Child)
+ return;
+
+ // Don't recurse more than once, so pass PdbSymbolIdField::None) for the
+ // recurse flags.
+ Child->defaultDump(OS, Indent + 2, ShowFlags, PdbSymbolIdField::None);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp
new file mode 100644
index 0000000000..0fa83efb7a
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolAnnotation.cpp
@@ -0,0 +1,20 @@
+//===- PDBSymbolAnnotation.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/PDB/PDBSymbolAnnotation.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolAnnotation::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolBlock.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolBlock.cpp
new file mode 100644
index 0000000000..9452282a88
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolBlock.cpp
@@ -0,0 +1,19 @@
+//===- PDBSymbolBlock.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/PDB/PDBSymbolBlock.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolBlock::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp
new file mode 100644
index 0000000000..529100b23b
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolCompiland.cpp
@@ -0,0 +1,110 @@
+//===- PDBSymbolCompiland.cpp - compiland details ---------------*- 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/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/IPDBSourceFile.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymbolCompiland.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompilandDetails.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolCompilandEnv.h"
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+#include "llvm/ADT/StringSwitch.h"
+#include "llvm/Support/Path.h"
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolCompiland::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
+
+std::string PDBSymbolCompiland::getSourceFileName() const {
+ return sys::path::filename(getSourceFileFullPath()).str();
+}
+
+std::string PDBSymbolCompiland::getSourceFileFullPath() const {
+ std::string SourceFileFullPath;
+
+ // RecordedResult could be the basename, relative path or full path of the
+ // source file. Usually it is retrieved and recorded from the command that
+ // compiles this compiland.
+ //
+ // cmd FileName -> RecordedResult = .\\FileName
+ // cmd (Path)\\FileName -> RecordedResult = (Path)\\FileName
+ //
+ std::string RecordedResult = RawSymbol->getSourceFileName();
+
+ if (RecordedResult.empty()) {
+ if (auto Envs = findAllChildren<PDBSymbolCompilandEnv>()) {
+ std::string EnvWorkingDir, EnvSrc;
+
+ while (auto Env = Envs->getNext()) {
+ std::string Var = Env->getName();
+ if (Var == "cwd") {
+ EnvWorkingDir = Env->getValue();
+ continue;
+ }
+ if (Var == "src") {
+ EnvSrc = Env->getValue();
+ if (sys::path::is_absolute(EnvSrc))
+ return EnvSrc;
+ RecordedResult = EnvSrc;
+ continue;
+ }
+ }
+ if (!EnvWorkingDir.empty() && !EnvSrc.empty()) {
+ auto Len = EnvWorkingDir.length();
+ if (EnvWorkingDir[Len - 1] != '/' && EnvWorkingDir[Len - 1] != '\\') {
+ std::string Path = EnvWorkingDir + "\\" + EnvSrc;
+ std::replace(Path.begin(), Path.end(), '/', '\\');
+ // We will return it as full path if we can't find a better one.
+ if (sys::path::is_absolute(Path))
+ SourceFileFullPath = Path;
+ }
+ }
+ }
+ }
+
+ if (!RecordedResult.empty()) {
+ if (sys::path::is_absolute(RecordedResult))
+ return RecordedResult;
+
+ // This searches name that has same basename as the one in RecordedResult.
+ auto OneSrcFile = Session.findOneSourceFile(
+ this, RecordedResult, PDB_NameSearchFlags::NS_CaseInsensitive);
+ if (OneSrcFile)
+ return OneSrcFile->getFileName();
+ }
+
+ // At this point, we have to walk through all source files of this compiland,
+ // and determine the right source file if any that is used to generate this
+ // compiland based on language indicated in compilanddetails language field.
+ auto Details = findOneChild<PDBSymbolCompilandDetails>();
+ PDB_Lang Lang = Details ? Details->getLanguage() : PDB_Lang::Cpp;
+ auto SrcFiles = Session.getSourceFilesForCompiland(*this);
+ if (SrcFiles) {
+ while (auto File = SrcFiles->getNext()) {
+ std::string FileName = File->getFileName();
+ auto file_extension = sys::path::extension(FileName);
+ if (StringSwitch<bool>(file_extension.lower())
+ .Case(".cpp", Lang == PDB_Lang::Cpp)
+ .Case(".cc", Lang == PDB_Lang::Cpp)
+ .Case(".cxx", Lang == PDB_Lang::Cpp)
+ .Case(".c", Lang == PDB_Lang::C)
+ .Case(".asm", Lang == PDB_Lang::Masm)
+ .Case(".swift", Lang == PDB_Lang::Swift)
+ .Case(".rs", Lang == PDB_Lang::Rust)
+ .Default(false))
+ return File->getFileName();
+ }
+ }
+
+ return SourceFileFullPath;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp
new file mode 100644
index 0000000000..0d86dfe1e6
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolCompilandDetails.cpp
@@ -0,0 +1,21 @@
+//===- PDBSymbolCompilandDetails.cpp - compiland details --------*- 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/PDB/PDBSymbolCompilandDetails.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolCompilandDetails::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp
new file mode 100644
index 0000000000..61f119405f
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolCompilandEnv.cpp
@@ -0,0 +1,29 @@
+//===- PDBSymbolCompilandEnv.cpp - compiland env variables ------*- 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/PDB/PDBSymbolCompilandEnv.h"
+
+#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+std::string PDBSymbolCompilandEnv::getValue() const {
+ Variant Value = RawSymbol->getValue();
+ if (Value.Type != PDB_VariantType::String)
+ return std::string();
+ return std::string(Value.Value.String);
+}
+
+void PDBSymbolCompilandEnv::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolCustom.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolCustom.cpp
new file mode 100644
index 0000000000..6c9a4aa76c
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolCustom.cpp
@@ -0,0 +1,24 @@
+//===- PDBSymbolCustom.cpp - compiler-specific types ------------*- 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/PDB/PDBSymbolCustom.h"
+
+#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolCustom::getDataBytes(llvm::SmallVector<uint8_t, 32> &bytes) {
+ RawSymbol->getDataBytes(bytes);
+}
+
+void PDBSymbolCustom::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolData.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolData.cpp
new file mode 100644
index 0000000000..d2b82111cc
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolData.cpp
@@ -0,0 +1,68 @@
+//===- PDBSymbolData.cpp - PDB data (e.g. variable) accessors ---*- 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/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/IPDBSectionContrib.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolData::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); }
+
+std::unique_ptr<IPDBEnumLineNumbers> PDBSymbolData::getLineNumbers() const {
+ auto Len = RawSymbol->getLength();
+ Len = Len ? Len : 1;
+ if (auto RVA = RawSymbol->getRelativeVirtualAddress())
+ return Session.findLineNumbersByRVA(RVA, Len);
+
+ if (auto Section = RawSymbol->getAddressSection())
+ return Session.findLineNumbersBySectOffset(
+ Section, RawSymbol->getAddressOffset(), Len);
+
+ return nullptr;
+}
+
+uint32_t PDBSymbolData::getCompilandId() const {
+ if (auto Lines = getLineNumbers()) {
+ if (auto FirstLine = Lines->getNext())
+ return FirstLine->getCompilandId();
+ }
+
+ uint32_t DataSection = RawSymbol->getAddressSection();
+ uint32_t DataOffset = RawSymbol->getAddressOffset();
+ if (DataSection == 0) {
+ if (auto RVA = RawSymbol->getRelativeVirtualAddress())
+ Session.addressForRVA(RVA, DataSection, DataOffset);
+ }
+
+ if (DataSection) {
+ if (auto SecContribs = Session.getSectionContribs()) {
+ while (auto Section = SecContribs->getNext()) {
+ if (Section->getAddressSection() == DataSection &&
+ Section->getAddressOffset() <= DataOffset &&
+ (Section->getAddressOffset() + Section->getLength()) > DataOffset)
+ return Section->getCompilandId();
+ }
+ }
+ } else {
+ auto LexParentId = RawSymbol->getLexicalParentId();
+ while (auto LexParent = Session.getSymbolById(LexParentId)) {
+ if (LexParent->getSymTag() == PDB_SymType::Exe)
+ break;
+ if (LexParent->getSymTag() == PDB_SymType::Compiland)
+ return LexParentId;
+ LexParentId = LexParent->getRawSymbol().getLexicalParentId();
+ }
+ }
+
+ return 0;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolExe.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolExe.cpp
new file mode 100644
index 0000000000..c85756c43e
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolExe.cpp
@@ -0,0 +1,29 @@
+//===- PDBSymbolExe.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/PDB/PDBSymbolExe.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolExe::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); }
+
+uint32_t PDBSymbolExe::getPointerByteSize() const {
+ auto Pointer = findOneChild<PDBSymbolTypePointer>();
+ if (Pointer)
+ return Pointer->getLength();
+
+ if (getMachineType() == PDB_Machine::x86)
+ return 4;
+ return 8;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolFunc.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolFunc.cpp
new file mode 100644
index 0000000000..cb0329bc0e
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolFunc.cpp
@@ -0,0 +1,111 @@
+//===- PDBSymbolFunc.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/PDB/PDBSymbolFunc.h"
+
+#include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h"
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionSig.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+
+#include <unordered_set>
+#include <utility>
+#include <vector>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+namespace {
+class FunctionArgEnumerator : public IPDBEnumChildren<PDBSymbolData> {
+public:
+ typedef ConcreteSymbolEnumerator<PDBSymbolData> ArgEnumeratorType;
+
+ FunctionArgEnumerator(const IPDBSession &PDBSession,
+ const PDBSymbolFunc &PDBFunc)
+ : Session(PDBSession), Func(PDBFunc) {
+ // Arguments can appear multiple times if they have live range
+ // information, so we only take the first occurrence.
+ std::unordered_set<std::string> SeenNames;
+ auto DataChildren = Func.findAllChildren<PDBSymbolData>();
+ while (auto Child = DataChildren->getNext()) {
+ if (Child->getDataKind() == PDB_DataKind::Param) {
+ std::string Name = Child->getName();
+ if (SeenNames.find(Name) != SeenNames.end())
+ continue;
+ Args.push_back(std::move(Child));
+ SeenNames.insert(Name);
+ }
+ }
+ reset();
+ }
+
+ uint32_t getChildCount() const override { return Args.size(); }
+
+ std::unique_ptr<PDBSymbolData>
+ getChildAtIndex(uint32_t Index) const override {
+ if (Index >= Args.size())
+ return nullptr;
+
+ return Session.getConcreteSymbolById<PDBSymbolData>(
+ Args[Index]->getSymIndexId());
+ }
+
+ std::unique_ptr<PDBSymbolData> getNext() override {
+ if (CurIter == Args.end())
+ return nullptr;
+ const auto &Result = **CurIter;
+ ++CurIter;
+ return Session.getConcreteSymbolById<PDBSymbolData>(Result.getSymIndexId());
+ }
+
+ void reset() override { CurIter = Args.empty() ? Args.end() : Args.begin(); }
+
+private:
+ typedef std::vector<std::unique_ptr<PDBSymbolData>> ArgListType;
+ const IPDBSession &Session;
+ const PDBSymbolFunc &Func;
+ ArgListType Args;
+ ArgListType::const_iterator CurIter;
+};
+}
+
+std::unique_ptr<IPDBEnumChildren<PDBSymbolData>>
+PDBSymbolFunc::getArguments() const {
+ return std::make_unique<FunctionArgEnumerator>(Session, *this);
+}
+
+void PDBSymbolFunc::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); }
+
+bool PDBSymbolFunc::isDestructor() const {
+ std::string Name = getName();
+ if (Name.empty())
+ return false;
+ if (Name[0] == '~')
+ return true;
+ if (Name == "__vecDelDtor")
+ return true;
+ return false;
+}
+
+std::unique_ptr<IPDBEnumLineNumbers> PDBSymbolFunc::getLineNumbers() const {
+ auto Len = RawSymbol->getLength();
+ return Session.findLineNumbersByAddress(RawSymbol->getVirtualAddress(),
+ Len ? Len : 1);
+}
+
+uint32_t PDBSymbolFunc::getCompilandId() const {
+ if (auto Lines = getLineNumbers()) {
+ if (auto FirstLine = Lines->getNext()) {
+ return FirstLine->getCompilandId();
+ }
+ }
+ return 0;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp
new file mode 100644
index 0000000000..66433dc17b
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolFuncDebugEnd.cpp
@@ -0,0 +1,21 @@
+//===- PDBSymbolFuncDebugEnd.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/PDB/PDBSymbolFuncDebugEnd.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolFuncDebugEnd::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp
new file mode 100644
index 0000000000..fe32c93c01
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolFuncDebugStart.cpp
@@ -0,0 +1,21 @@
+//===- PDBSymbolFuncDebugStart.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/PDB/PDBSymbolFuncDebugStart.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolFuncDebugStart::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolLabel.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolLabel.cpp
new file mode 100644
index 0000000000..1fffe69a0c
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolLabel.cpp
@@ -0,0 +1,18 @@
+//===- PDBSymbolLabel.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/PDB/PDBSymbolLabel.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolLabel::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp
new file mode 100644
index 0000000000..08697683f6
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolPublicSymbol.cpp
@@ -0,0 +1,21 @@
+//===- PDBSymbolPublicSymbol.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/PDB/PDBSymbolPublicSymbol.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolPublicSymbol::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolThunk.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolThunk.cpp
new file mode 100644
index 0000000000..6483858183
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolThunk.cpp
@@ -0,0 +1,18 @@
+//===- PDBSymbolThunk.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/PDB/PDBSymbolThunk.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolThunk::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp
new file mode 100644
index 0000000000..a0d521abe4
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeArray.cpp
@@ -0,0 +1,24 @@
+//===- PDBSymbolTypeArray.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/PDB/PDBSymbolTypeArray.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolTypeArray::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
+
+void PDBSymbolTypeArray::dumpRight(PDBSymDumper &Dumper) const {
+ Dumper.dumpRight(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp
new file mode 100644
index 0000000000..08467059b5
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeBaseClass.cpp
@@ -0,0 +1,21 @@
+//===- PDBSymbolTypeBaseClass.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/PDB/PDBSymbolTypeBaseClass.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolTypeBaseClass::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp
new file mode 100644
index 0000000000..a0dd9ef601
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeBuiltin.cpp
@@ -0,0 +1,20 @@
+//===- PDBSymbolTypeBuiltin.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/PDB/PDBSymbolTypeBuiltin.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolTypeBuiltin::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp
new file mode 100644
index 0000000000..6723894c90
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeCustom.cpp
@@ -0,0 +1,21 @@
+//===- PDBSymbolTypeCustom.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/PDB/PDBSymbolTypeCustom.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolTypeCustom::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp
new file mode 100644
index 0000000000..4a25a391f2
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeDimension.cpp
@@ -0,0 +1,21 @@
+//===- PDBSymbolTypeDimension.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/PDB/PDBSymbolTypeDimension.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+void PDBSymbolTypeDimension::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp
new file mode 100644
index 0000000000..b9fdf6aec8
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeEnum.cpp
@@ -0,0 +1,19 @@
+//===- PDBSymbolTypeEnum.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/PDB/PDBSymbolTypeEnum.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolTypeEnum::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp
new file mode 100644
index 0000000000..4ffea42cbb
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeFriend.cpp
@@ -0,0 +1,21 @@
+//===- PDBSymbolTypeFriend.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/PDB/PDBSymbolTypeFriend.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolTypeFriend::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp
new file mode 100644
index 0000000000..683e93548f
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeFunctionArg.cpp
@@ -0,0 +1,20 @@
+//===- PDBSymbolTypeFunctionArg.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/PDB/PDBSymbolTypeFunctionArg.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolTypeFunctionArg::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp
new file mode 100644
index 0000000000..1373615522
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeFunctionSig.cpp
@@ -0,0 +1,93 @@
+//===- PDBSymbolTypeFunctionSig.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/PDB/PDBSymbolTypeFunctionSig.h"
+
+#include "llvm/DebugInfo/PDB/ConcreteSymbolEnumerator.h"
+#include "llvm/DebugInfo/PDB/IPDBEnumChildren.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeFunctionArg.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+namespace {
+class FunctionArgEnumerator : public IPDBEnumSymbols {
+public:
+ typedef ConcreteSymbolEnumerator<PDBSymbolTypeFunctionArg> ArgEnumeratorType;
+
+ FunctionArgEnumerator(const IPDBSession &PDBSession,
+ const PDBSymbolTypeFunctionSig &Sig)
+ : Session(PDBSession),
+ Enumerator(Sig.findAllChildren<PDBSymbolTypeFunctionArg>()) {}
+
+ FunctionArgEnumerator(const IPDBSession &PDBSession,
+ std::unique_ptr<ArgEnumeratorType> ArgEnumerator)
+ : Session(PDBSession), Enumerator(std::move(ArgEnumerator)) {}
+
+ uint32_t getChildCount() const override {
+ return Enumerator->getChildCount();
+ }
+
+ std::unique_ptr<PDBSymbol> getChildAtIndex(uint32_t Index) const override {
+ auto FunctionArgSymbol = Enumerator->getChildAtIndex(Index);
+ if (!FunctionArgSymbol)
+ return nullptr;
+ return Session.getSymbolById(FunctionArgSymbol->getTypeId());
+ }
+
+ std::unique_ptr<PDBSymbol> getNext() override {
+ auto FunctionArgSymbol = Enumerator->getNext();
+ if (!FunctionArgSymbol)
+ return nullptr;
+ return Session.getSymbolById(FunctionArgSymbol->getTypeId());
+ }
+
+ void reset() override { Enumerator->reset(); }
+
+private:
+ const IPDBSession &Session;
+ std::unique_ptr<ArgEnumeratorType> Enumerator;
+};
+}
+
+std::unique_ptr<IPDBEnumSymbols>
+PDBSymbolTypeFunctionSig::getArguments() const {
+ return std::make_unique<FunctionArgEnumerator>(Session, *this);
+}
+
+void PDBSymbolTypeFunctionSig::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
+
+void PDBSymbolTypeFunctionSig::dumpRight(PDBSymDumper &Dumper) const {
+ Dumper.dumpRight(*this);
+}
+
+bool PDBSymbolTypeFunctionSig::isCVarArgs() const {
+ auto SigArguments = getArguments();
+ if (!SigArguments)
+ return false;
+ uint32_t NumArgs = SigArguments->getChildCount();
+ if (NumArgs == 0)
+ return false;
+ auto Last = SigArguments->getChildAtIndex(NumArgs - 1);
+ if (auto Builtin = llvm::dyn_cast_or_null<PDBSymbolTypeBuiltin>(Last.get())) {
+ if (Builtin->getBuiltinType() == PDB_BuiltinType::None)
+ return true;
+ }
+
+ // Note that for a variadic template signature, this method always returns
+ // false since the parameters of the template are specialized.
+ return false;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp
new file mode 100644
index 0000000000..e80e6c7165
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeManaged.cpp
@@ -0,0 +1,21 @@
+//===- PDBSymboTypelManaged.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/PDB/PDBSymbolTypeManaged.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolTypeManaged::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp
new file mode 100644
index 0000000000..462fc31535
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypePointer.cpp
@@ -0,0 +1,25 @@
+//===- PDBSymbolTypePointer.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/PDB/PDBSymbolTypePointer.h"
+
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolTypePointer::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
+
+void PDBSymbolTypePointer::dumpRight(PDBSymDumper &Dumper) const {
+ Dumper.dumpRight(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp
new file mode 100644
index 0000000000..70749d9bf5
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeTypedef.cpp
@@ -0,0 +1,20 @@
+//===- PDBSymbolTypeTypedef.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/PDB/PDBSymbolTypeTypedef.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolTypeTypedef::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp
new file mode 100644
index 0000000000..d302c29a3b
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeUDT.cpp
@@ -0,0 +1,25 @@
+//===- PDBSymbolTypeUDT.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/PDB/PDBSymbolTypeUDT.h"
+
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolExe.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTableShape.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolTypeUDT::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp
new file mode 100644
index 0000000000..4e2a45116d
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeVTable.cpp
@@ -0,0 +1,20 @@
+//===- PDBSymbolTypeVTable.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/PDB/PDBSymbolTypeVTable.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolTypeVTable::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp
new file mode 100644
index 0000000000..78957620e0
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolTypeVTableShape.cpp
@@ -0,0 +1,21 @@
+//===- PDBSymbolTypeVTableShape.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/PDB/PDBSymbolTypeVTableShape.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolTypeVTableShape::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolUnknown.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolUnknown.cpp
new file mode 100644
index 0000000000..650d011831
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolUnknown.cpp
@@ -0,0 +1,19 @@
+//===- PDBSymbolUnknown.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/PDB/PDBSymbolUnknown.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolUnknown::dump(PDBSymDumper &Dumper) const { Dumper.dump(*this); }
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp
new file mode 100644
index 0000000000..74afbdb180
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/PDBSymbolUsingNamespace.cpp
@@ -0,0 +1,21 @@
+//===- PDBSymbolUsingNamespace.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/PDB/PDBSymbolUsingNamespace.h"
+
+#include "llvm/DebugInfo/PDB/PDBSymDumper.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+
+#include <utility>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+void PDBSymbolUsingNamespace::dump(PDBSymDumper &Dumper) const {
+ Dumper.dump(*this);
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/UDTLayout.cpp b/contrib/libs/llvm14/lib/DebugInfo/PDB/UDTLayout.cpp
new file mode 100644
index 0000000000..55854bb498
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/UDTLayout.cpp
@@ -0,0 +1,302 @@
+//===- UDTLayout.cpp ------------------------------------------------------===//
+//
+// 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/PDB/UDTLayout.h"
+#include "llvm/ADT/ArrayRef.h"
+#include "llvm/ADT/BitVector.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/DebugInfo/PDB/IPDBRawSymbol.h"
+#include "llvm/DebugInfo/PDB/IPDBSession.h"
+#include "llvm/DebugInfo/PDB/PDBSymbol.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolData.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolFunc.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBaseClass.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeBuiltin.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypePointer.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeUDT.h"
+#include "llvm/DebugInfo/PDB/PDBSymbolTypeVTable.h"
+#include "llvm/DebugInfo/PDB/PDBTypes.h"
+#include "llvm/Support/Casting.h"
+#include <algorithm>
+#include <cassert>
+#include <cstdint>
+#include <memory>
+
+using namespace llvm;
+using namespace llvm::pdb;
+
+static std::unique_ptr<PDBSymbol> getSymbolType(const PDBSymbol &Symbol) {
+ const IPDBSession &Session = Symbol.getSession();
+ const IPDBRawSymbol &RawSymbol = Symbol.getRawSymbol();
+ uint32_t TypeId = RawSymbol.getTypeId();
+ return Session.getSymbolById(TypeId);
+}
+
+static uint32_t getTypeLength(const PDBSymbol &Symbol) {
+ auto SymbolType = getSymbolType(Symbol);
+ const IPDBRawSymbol &RawType = SymbolType->getRawSymbol();
+
+ return RawType.getLength();
+}
+
+LayoutItemBase::LayoutItemBase(const UDTLayoutBase *Parent,
+ const PDBSymbol *Symbol, const std::string &Name,
+ uint32_t OffsetInParent, uint32_t Size,
+ bool IsElided)
+ : Symbol(Symbol), Parent(Parent), Name(Name),
+ OffsetInParent(OffsetInParent), SizeOf(Size), LayoutSize(Size),
+ IsElided(IsElided) {
+ UsedBytes.resize(SizeOf, true);
+}
+
+uint32_t LayoutItemBase::deepPaddingSize() const {
+ return UsedBytes.size() - UsedBytes.count();
+}
+
+uint32_t LayoutItemBase::tailPadding() const {
+ int Last = UsedBytes.find_last();
+
+ return UsedBytes.size() - (Last + 1);
+}
+
+DataMemberLayoutItem::DataMemberLayoutItem(
+ const UDTLayoutBase &Parent, std::unique_ptr<PDBSymbolData> Member)
+ : LayoutItemBase(&Parent, Member.get(), Member->getName(),
+ Member->getOffset(), getTypeLength(*Member), false),
+ DataMember(std::move(Member)) {
+ auto Type = DataMember->getType();
+ if (auto UDT = unique_dyn_cast<PDBSymbolTypeUDT>(Type)) {
+ UdtLayout = std::make_unique<ClassLayout>(std::move(UDT));
+ UsedBytes = UdtLayout->usedBytes();
+ }
+}
+
+VBPtrLayoutItem::VBPtrLayoutItem(const UDTLayoutBase &Parent,
+ std::unique_ptr<PDBSymbolTypeBuiltin> Sym,
+ uint32_t Offset, uint32_t Size)
+ : LayoutItemBase(&Parent, Sym.get(), "<vbptr>", Offset, Size, false),
+ Type(std::move(Sym)) {
+}
+
+const PDBSymbolData &DataMemberLayoutItem::getDataMember() {
+ return *cast<PDBSymbolData>(Symbol);
+}
+
+bool DataMemberLayoutItem::hasUDTLayout() const { return UdtLayout != nullptr; }
+
+const ClassLayout &DataMemberLayoutItem::getUDTLayout() const {
+ return *UdtLayout;
+}
+
+VTableLayoutItem::VTableLayoutItem(const UDTLayoutBase &Parent,
+ std::unique_ptr<PDBSymbolTypeVTable> VT)
+ : LayoutItemBase(&Parent, VT.get(), "<vtbl>", 0, getTypeLength(*VT), false),
+ VTable(std::move(VT)) {
+ auto VTableType = cast<PDBSymbolTypePointer>(VTable->getType());
+ ElementSize = VTableType->getLength();
+}
+
+UDTLayoutBase::UDTLayoutBase(const UDTLayoutBase *Parent, const PDBSymbol &Sym,
+ const std::string &Name, uint32_t OffsetInParent,
+ uint32_t Size, bool IsElided)
+ : LayoutItemBase(Parent, &Sym, Name, OffsetInParent, Size, IsElided) {
+ // UDT storage comes from a union of all the children's storage, so start out
+ // uninitialized.
+ UsedBytes.reset(0, Size);
+
+ initializeChildren(Sym);
+ if (LayoutSize < Size)
+ UsedBytes.resize(LayoutSize);
+}
+
+uint32_t UDTLayoutBase::tailPadding() const {
+ uint32_t Abs = LayoutItemBase::tailPadding();
+ if (!LayoutItems.empty()) {
+ const LayoutItemBase *Back = LayoutItems.back();
+ uint32_t ChildPadding = Back->LayoutItemBase::tailPadding();
+ if (Abs < ChildPadding)
+ Abs = 0;
+ else
+ Abs -= ChildPadding;
+ }
+ return Abs;
+}
+
+ClassLayout::ClassLayout(const PDBSymbolTypeUDT &UDT)
+ : UDTLayoutBase(nullptr, UDT, UDT.getName(), 0, UDT.getLength(), false),
+ UDT(UDT) {
+ ImmediateUsedBytes.resize(SizeOf, false);
+ for (auto &LI : LayoutItems) {
+ uint32_t Begin = LI->getOffsetInParent();
+ uint32_t End = Begin + LI->getLayoutSize();
+ End = std::min(SizeOf, End);
+ ImmediateUsedBytes.set(Begin, End);
+ }
+}
+
+ClassLayout::ClassLayout(std::unique_ptr<PDBSymbolTypeUDT> UDT)
+ : ClassLayout(*UDT) {
+ OwnedStorage = std::move(UDT);
+}
+
+uint32_t ClassLayout::immediatePadding() const {
+ return SizeOf - ImmediateUsedBytes.count();
+}
+
+BaseClassLayout::BaseClassLayout(const UDTLayoutBase &Parent,
+ uint32_t OffsetInParent, bool Elide,
+ std::unique_ptr<PDBSymbolTypeBaseClass> B)
+ : UDTLayoutBase(&Parent, *B, B->getName(), OffsetInParent, B->getLength(),
+ Elide),
+ Base(std::move(B)) {
+ if (isEmptyBase()) {
+ // Special case an empty base so that it doesn't get treated as padding.
+ UsedBytes.resize(1);
+ UsedBytes.set(0);
+ }
+ IsVirtualBase = Base->isVirtualBaseClass();
+}
+
+void UDTLayoutBase::initializeChildren(const PDBSymbol &Sym) {
+ // Handled bases first, followed by VTables, followed by data members,
+ // followed by functions, followed by other. This ordering is necessary
+ // so that bases and vtables get initialized before any functions which
+ // may override them.
+ UniquePtrVector<PDBSymbolTypeBaseClass> Bases;
+ UniquePtrVector<PDBSymbolTypeVTable> VTables;
+ UniquePtrVector<PDBSymbolData> Members;
+ UniquePtrVector<PDBSymbolTypeBaseClass> VirtualBaseSyms;
+
+ auto Children = Sym.findAllChildren();
+ while (auto Child = Children->getNext()) {
+ if (auto Base = unique_dyn_cast<PDBSymbolTypeBaseClass>(Child)) {
+ if (Base->isVirtualBaseClass())
+ VirtualBaseSyms.push_back(std::move(Base));
+ else
+ Bases.push_back(std::move(Base));
+ }
+ else if (auto Data = unique_dyn_cast<PDBSymbolData>(Child)) {
+ if (Data->getDataKind() == PDB_DataKind::Member)
+ Members.push_back(std::move(Data));
+ else
+ Other.push_back(std::move(Data));
+ } else if (auto VT = unique_dyn_cast<PDBSymbolTypeVTable>(Child))
+ VTables.push_back(std::move(VT));
+ else if (auto Func = unique_dyn_cast<PDBSymbolFunc>(Child))
+ Funcs.push_back(std::move(Func));
+ else {
+ Other.push_back(std::move(Child));
+ }
+ }
+
+ // We don't want to have any re-allocations in the list of bases, so make
+ // sure to reserve enough space so that our ArrayRefs don't get invalidated.
+ AllBases.reserve(Bases.size() + VirtualBaseSyms.size());
+
+ // Only add non-virtual bases to the class first. Only at the end of the
+ // class, after all non-virtual bases and data members have been added do we
+ // add virtual bases. This way the offsets are correctly aligned when we go
+ // to lay out virtual bases.
+ for (auto &Base : Bases) {
+ uint32_t Offset = Base->getOffset();
+ // Non-virtual bases never get elided.
+ auto BL = std::make_unique<BaseClassLayout>(*this, Offset, false,
+ std::move(Base));
+
+ AllBases.push_back(BL.get());
+ addChildToLayout(std::move(BL));
+ }
+ NonVirtualBases = AllBases;
+
+ assert(VTables.size() <= 1);
+ if (!VTables.empty()) {
+ auto VTLayout =
+ std::make_unique<VTableLayoutItem>(*this, std::move(VTables[0]));
+
+ VTable = VTLayout.get();
+
+ addChildToLayout(std::move(VTLayout));
+ }
+
+ for (auto &Data : Members) {
+ auto DM = std::make_unique<DataMemberLayoutItem>(*this, std::move(Data));
+
+ addChildToLayout(std::move(DM));
+ }
+
+ // Make sure add virtual bases before adding functions, since functions may be
+ // overrides of virtual functions declared in a virtual base, so the VTables
+ // and virtual intros need to be correctly initialized.
+ for (auto &VB : VirtualBaseSyms) {
+ int VBPO = VB->getVirtualBasePointerOffset();
+ if (!hasVBPtrAtOffset(VBPO)) {
+ if (auto VBP = VB->getRawSymbol().getVirtualBaseTableType()) {
+ auto VBPL = std::make_unique<VBPtrLayoutItem>(*this, std::move(VBP),
+ VBPO, VBP->getLength());
+ VBPtr = VBPL.get();
+ addChildToLayout(std::move(VBPL));
+ }
+ }
+
+ // Virtual bases always go at the end. So just look for the last place we
+ // ended when writing something, and put our virtual base there.
+ // Note that virtual bases get elided unless this is a top-most derived
+ // class.
+ uint32_t Offset = UsedBytes.find_last() + 1;
+ bool Elide = (Parent != nullptr);
+ auto BL =
+ std::make_unique<BaseClassLayout>(*this, Offset, Elide, std::move(VB));
+ AllBases.push_back(BL.get());
+
+ // Only lay this virtual base out directly inside of *this* class if this
+ // is a top-most derived class. Keep track of it regardless, but only
+ // physically lay it out if it's a topmost derived class.
+ addChildToLayout(std::move(BL));
+ }
+ VirtualBases = makeArrayRef(AllBases).drop_front(NonVirtualBases.size());
+
+ if (Parent != nullptr)
+ LayoutSize = UsedBytes.find_last() + 1;
+}
+
+bool UDTLayoutBase::hasVBPtrAtOffset(uint32_t Off) const {
+ if (VBPtr && VBPtr->getOffsetInParent() == Off)
+ return true;
+ for (BaseClassLayout *BL : AllBases) {
+ if (BL->hasVBPtrAtOffset(Off - BL->getOffsetInParent()))
+ return true;
+ }
+ return false;
+}
+
+void UDTLayoutBase::addChildToLayout(std::unique_ptr<LayoutItemBase> Child) {
+ uint32_t Begin = Child->getOffsetInParent();
+
+ if (!Child->isElided()) {
+ BitVector ChildBytes = Child->usedBytes();
+
+ // Suppose the child occupies 4 bytes starting at offset 12 in a 32 byte
+ // class. When we call ChildBytes.resize(32), the Child's storage will
+ // still begin at offset 0, so we need to shift it left by offset bytes
+ // to get it into the right position.
+ ChildBytes.resize(UsedBytes.size());
+ ChildBytes <<= Child->getOffsetInParent();
+ UsedBytes |= ChildBytes;
+
+ if (ChildBytes.count() > 0) {
+ auto Loc = llvm::upper_bound(
+ LayoutItems, Begin, [](uint32_t Off, const LayoutItemBase *Item) {
+ return (Off < Item->getOffsetInParent());
+ });
+
+ LayoutItems.insert(Loc, Child.get());
+ }
+ }
+
+ ChildStorage.push_back(std::move(Child));
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/PDB/ya.make b/contrib/libs/llvm14/lib/DebugInfo/PDB/ya.make
new file mode 100644
index 0000000000..de93bdcfca
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/PDB/ya.make
@@ -0,0 +1,119 @@
+# Generated by devtools/yamaker.
+
+LIBRARY()
+
+LICENSE(Apache-2.0 WITH LLVM-exception)
+
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
+PEERDIR(
+ contrib/libs/llvm14
+ contrib/libs/llvm14/lib/BinaryFormat
+ contrib/libs/llvm14/lib/DebugInfo/CodeView
+ contrib/libs/llvm14/lib/DebugInfo/MSF
+ contrib/libs/llvm14/lib/Object
+ contrib/libs/llvm14/lib/Support
+)
+
+ADDINCL(
+ contrib/libs/llvm14/lib/DebugInfo/PDB
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ GenericError.cpp
+ IPDBSourceFile.cpp
+ Native/DbiModuleDescriptor.cpp
+ Native/DbiModuleDescriptorBuilder.cpp
+ Native/DbiModuleList.cpp
+ Native/DbiStream.cpp
+ Native/DbiStreamBuilder.cpp
+ Native/EnumTables.cpp
+ Native/GSIStreamBuilder.cpp
+ Native/GlobalsStream.cpp
+ Native/Hash.cpp
+ Native/HashTable.cpp
+ Native/InfoStream.cpp
+ Native/InfoStreamBuilder.cpp
+ Native/InjectedSourceStream.cpp
+ Native/ModuleDebugStream.cpp
+ Native/NamedStreamMap.cpp
+ Native/NativeCompilandSymbol.cpp
+ Native/NativeEnumGlobals.cpp
+ Native/NativeEnumInjectedSources.cpp
+ Native/NativeEnumLineNumbers.cpp
+ Native/NativeEnumModules.cpp
+ Native/NativeEnumSymbols.cpp
+ Native/NativeEnumTypes.cpp
+ Native/NativeExeSymbol.cpp
+ Native/NativeFunctionSymbol.cpp
+ Native/NativeInlineSiteSymbol.cpp
+ Native/NativeLineNumber.cpp
+ Native/NativePublicSymbol.cpp
+ Native/NativeRawSymbol.cpp
+ Native/NativeSession.cpp
+ Native/NativeSourceFile.cpp
+ Native/NativeSymbolEnumerator.cpp
+ Native/NativeTypeArray.cpp
+ Native/NativeTypeBuiltin.cpp
+ Native/NativeTypeEnum.cpp
+ Native/NativeTypeFunctionSig.cpp
+ Native/NativeTypePointer.cpp
+ Native/NativeTypeTypedef.cpp
+ Native/NativeTypeUDT.cpp
+ Native/NativeTypeVTShape.cpp
+ Native/PDBFile.cpp
+ Native/PDBFileBuilder.cpp
+ Native/PDBStringTable.cpp
+ Native/PDBStringTableBuilder.cpp
+ Native/PublicsStream.cpp
+ Native/RawError.cpp
+ Native/SymbolCache.cpp
+ Native/SymbolStream.cpp
+ Native/TpiHashing.cpp
+ Native/TpiStream.cpp
+ Native/TpiStreamBuilder.cpp
+ PDB.cpp
+ PDBContext.cpp
+ PDBExtras.cpp
+ PDBInterfaceAnchors.cpp
+ PDBSymDumper.cpp
+ PDBSymbol.cpp
+ PDBSymbolAnnotation.cpp
+ PDBSymbolBlock.cpp
+ PDBSymbolCompiland.cpp
+ PDBSymbolCompilandDetails.cpp
+ PDBSymbolCompilandEnv.cpp
+ PDBSymbolCustom.cpp
+ PDBSymbolData.cpp
+ PDBSymbolExe.cpp
+ PDBSymbolFunc.cpp
+ PDBSymbolFuncDebugEnd.cpp
+ PDBSymbolFuncDebugStart.cpp
+ PDBSymbolLabel.cpp
+ PDBSymbolPublicSymbol.cpp
+ PDBSymbolThunk.cpp
+ PDBSymbolTypeArray.cpp
+ PDBSymbolTypeBaseClass.cpp
+ PDBSymbolTypeBuiltin.cpp
+ PDBSymbolTypeCustom.cpp
+ PDBSymbolTypeDimension.cpp
+ PDBSymbolTypeEnum.cpp
+ PDBSymbolTypeFriend.cpp
+ PDBSymbolTypeFunctionArg.cpp
+ PDBSymbolTypeFunctionSig.cpp
+ PDBSymbolTypeManaged.cpp
+ PDBSymbolTypePointer.cpp
+ PDBSymbolTypeTypedef.cpp
+ PDBSymbolTypeUDT.cpp
+ PDBSymbolTypeVTable.cpp
+ PDBSymbolTypeVTableShape.cpp
+ PDBSymbolUnknown.cpp
+ PDBSymbolUsingNamespace.cpp
+ UDTLayout.cpp
+)
+
+END()
diff --git a/contrib/libs/llvm14/lib/DebugInfo/Symbolize/DIFetcher.cpp b/contrib/libs/llvm14/lib/DebugInfo/Symbolize/DIFetcher.cpp
new file mode 100644
index 0000000000..0493fcd3cb
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/Symbolize/DIFetcher.cpp
@@ -0,0 +1,58 @@
+//===-- lib/DebugInfo/Symbolize/DIFetcher.cpp -----------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+///
+/// \file
+/// This file defines the implementation of the local debug info fetcher, which
+/// searches cache directories.
+///
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/Symbolize/DIFetcher.h"
+
+#include "llvm/Debuginfod/Debuginfod.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/Path.h"
+
+namespace llvm {
+namespace symbolize {
+
+Optional<std::string>
+LocalDIFetcher::fetchBuildID(ArrayRef<uint8_t> BuildID) const {
+ auto GetDebugPath = [&](StringRef Directory) {
+ SmallString<128> Path{Directory};
+ sys::path::append(Path, ".build-id",
+ llvm::toHex(BuildID[0], /*LowerCase=*/true),
+ llvm::toHex(BuildID.slice(1), /*LowerCase=*/true));
+ Path += ".debug";
+ return Path;
+ };
+ if (DebugFileDirectory.empty()) {
+ SmallString<128> Path = GetDebugPath(
+#if defined(__NetBSD__)
+ // Try /usr/libdata/debug/.build-id/../...
+ "/usr/libdata/debug"
+#else
+ // Try /usr/lib/debug/.build-id/../...
+ "/usr/lib/debug"
+#endif
+ );
+ if (llvm::sys::fs::exists(Path))
+ return std::string(Path);
+ } else {
+ for (const auto &Directory : DebugFileDirectory) {
+ // Try <debug-file-directory>/.build-id/../...
+ SmallString<128> Path = GetDebugPath(Directory);
+ if (llvm::sys::fs::exists(Path))
+ return std::string(Path);
+ }
+ }
+ return None;
+}
+
+} // namespace symbolize
+} // namespace llvm
diff --git a/contrib/libs/llvm14/lib/DebugInfo/Symbolize/DIPrinter.cpp b/contrib/libs/llvm14/lib/DebugInfo/Symbolize/DIPrinter.cpp
new file mode 100644
index 0000000000..e29968d113
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/Symbolize/DIPrinter.cpp
@@ -0,0 +1,398 @@
+//===- lib/DebugInfo/Symbolize/DIPrinter.cpp ------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file defines the DIPrinter class, which is responsible for printing
+// structures defined in DebugInfo/DIContext.h
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/Symbolize/DIPrinter.h"
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/Support/ErrorOr.h"
+#include "llvm/Support/Format.h"
+#include "llvm/Support/LineIterator.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include "llvm/Support/raw_ostream.h"
+#include <algorithm>
+#include <cmath>
+#include <cstddef>
+#include <cstdint>
+#include <memory>
+#include <string>
+
+namespace llvm {
+namespace symbolize {
+
+class SourceCode {
+ std::unique_ptr<MemoryBuffer> MemBuf;
+
+ Optional<StringRef> load(StringRef FileName,
+ const Optional<StringRef> &EmbeddedSource) {
+ if (Lines <= 0)
+ return None;
+
+ if (EmbeddedSource)
+ return EmbeddedSource;
+ else {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> BufOrErr =
+ MemoryBuffer::getFile(FileName);
+ if (!BufOrErr)
+ return None;
+ MemBuf = std::move(*BufOrErr);
+ return MemBuf->getBuffer();
+ }
+ }
+
+ Optional<StringRef> pruneSource(const Optional<StringRef> &Source) {
+ if (!Source)
+ return None;
+ size_t FirstLinePos = StringRef::npos, Pos = 0;
+ for (int64_t L = 1; L <= LastLine; ++L, ++Pos) {
+ if (L == FirstLine)
+ FirstLinePos = Pos;
+ Pos = Source->find('\n', Pos);
+ if (Pos == StringRef::npos)
+ break;
+ }
+ if (FirstLinePos == StringRef::npos)
+ return None;
+ return Source->substr(FirstLinePos, (Pos == StringRef::npos)
+ ? StringRef::npos
+ : Pos - FirstLinePos);
+ }
+
+public:
+ const int64_t Line;
+ const int Lines;
+ const int64_t FirstLine;
+ const int64_t LastLine;
+ const Optional<StringRef> PrunedSource;
+
+ SourceCode(
+ StringRef FileName, int64_t Line, int Lines,
+ const Optional<StringRef> &EmbeddedSource = Optional<StringRef>(None))
+ : Line(Line), Lines(Lines),
+ FirstLine(std::max(static_cast<int64_t>(1), Line - Lines / 2)),
+ LastLine(FirstLine + Lines - 1),
+ PrunedSource(pruneSource(load(FileName, EmbeddedSource))) {}
+
+ void format(raw_ostream &OS) {
+ if (!PrunedSource)
+ return;
+ size_t MaxLineNumberWidth = std::ceil(std::log10(LastLine));
+ int64_t L = FirstLine;
+ for (size_t Pos = 0; Pos < PrunedSource->size(); ++L) {
+ size_t PosEnd = PrunedSource->find('\n', Pos);
+ StringRef String = PrunedSource->substr(
+ Pos, (PosEnd == StringRef::npos) ? StringRef::npos : (PosEnd - Pos));
+ if (String.endswith("\r"))
+ String = String.drop_back(1);
+ OS << format_decimal(L, MaxLineNumberWidth);
+ if (L == Line)
+ OS << " >: ";
+ else
+ OS << " : ";
+ OS << String << '\n';
+ if (PosEnd == StringRef::npos)
+ break;
+ Pos = PosEnd + 1;
+ }
+ }
+};
+
+void PlainPrinterBase::printHeader(uint64_t Address) {
+ if (Config.PrintAddress) {
+ OS << "0x";
+ OS.write_hex(Address);
+ StringRef Delimiter = Config.Pretty ? ": " : "\n";
+ OS << Delimiter;
+ }
+}
+
+// Prints source code around in the FileName the Line.
+void PlainPrinterBase::printContext(SourceCode SourceCode) {
+ SourceCode.format(OS);
+}
+
+void PlainPrinterBase::printFunctionName(StringRef FunctionName, bool Inlined) {
+ if (Config.PrintFunctions) {
+ if (FunctionName == DILineInfo::BadString)
+ FunctionName = DILineInfo::Addr2LineBadString;
+ StringRef Delimiter = Config.Pretty ? " at " : "\n";
+ StringRef Prefix = (Config.Pretty && Inlined) ? " (inlined by) " : "";
+ OS << Prefix << FunctionName << Delimiter;
+ }
+}
+
+void LLVMPrinter::printSimpleLocation(StringRef Filename,
+ const DILineInfo &Info) {
+ OS << Filename << ':' << Info.Line << ':' << Info.Column << '\n';
+ printContext(
+ SourceCode(Filename, Info.Line, Config.SourceContextLines, Info.Source));
+}
+
+void GNUPrinter::printSimpleLocation(StringRef Filename,
+ const DILineInfo &Info) {
+ OS << Filename << ':' << Info.Line;
+ if (Info.Discriminator)
+ OS << " (discriminator " << Info.Discriminator << ')';
+ OS << '\n';
+ printContext(
+ SourceCode(Filename, Info.Line, Config.SourceContextLines, Info.Source));
+}
+
+void PlainPrinterBase::printVerbose(StringRef Filename,
+ const DILineInfo &Info) {
+ OS << " Filename: " << Filename << '\n';
+ if (Info.StartLine) {
+ OS << " Function start filename: " << Info.StartFileName << '\n';
+ OS << " Function start line: " << Info.StartLine << '\n';
+ }
+ printStartAddress(Info);
+ OS << " Line: " << Info.Line << '\n';
+ OS << " Column: " << Info.Column << '\n';
+ if (Info.Discriminator)
+ OS << " Discriminator: " << Info.Discriminator << '\n';
+}
+
+void LLVMPrinter::printStartAddress(const DILineInfo &Info) {
+ if (Info.StartAddress) {
+ OS << " Function start address: 0x";
+ OS.write_hex(*Info.StartAddress);
+ OS << '\n';
+ }
+}
+
+void LLVMPrinter::printFooter() { OS << '\n'; }
+
+void PlainPrinterBase::print(const DILineInfo &Info, bool Inlined) {
+ printFunctionName(Info.FunctionName, Inlined);
+ StringRef Filename = Info.FileName;
+ if (Filename == DILineInfo::BadString)
+ Filename = DILineInfo::Addr2LineBadString;
+ if (Config.Verbose)
+ printVerbose(Filename, Info);
+ else
+ printSimpleLocation(Filename, Info);
+}
+
+void PlainPrinterBase::print(const Request &Request, const DILineInfo &Info) {
+ printHeader(*Request.Address);
+ print(Info, false);
+ printFooter();
+}
+
+void PlainPrinterBase::print(const Request &Request,
+ const DIInliningInfo &Info) {
+ printHeader(*Request.Address);
+ uint32_t FramesNum = Info.getNumberOfFrames();
+ if (FramesNum == 0)
+ print(DILineInfo(), false);
+ else
+ for (uint32_t I = 0; I < FramesNum; ++I)
+ print(Info.getFrame(I), I > 0);
+ printFooter();
+}
+
+void PlainPrinterBase::print(const Request &Request, const DIGlobal &Global) {
+ printHeader(*Request.Address);
+ StringRef Name = Global.Name;
+ if (Name == DILineInfo::BadString)
+ Name = DILineInfo::Addr2LineBadString;
+ OS << Name << "\n";
+ OS << Global.Start << " " << Global.Size << "\n";
+ printFooter();
+}
+
+void PlainPrinterBase::print(const Request &Request,
+ const std::vector<DILocal> &Locals) {
+ printHeader(*Request.Address);
+ if (Locals.empty())
+ OS << DILineInfo::Addr2LineBadString << '\n';
+ else
+ for (const DILocal &L : Locals) {
+ if (L.FunctionName.empty())
+ OS << DILineInfo::Addr2LineBadString;
+ else
+ OS << L.FunctionName;
+ OS << '\n';
+
+ if (L.Name.empty())
+ OS << DILineInfo::Addr2LineBadString;
+ else
+ OS << L.Name;
+ OS << '\n';
+
+ if (L.DeclFile.empty())
+ OS << DILineInfo::Addr2LineBadString;
+ else
+ OS << L.DeclFile;
+
+ OS << ':' << L.DeclLine << '\n';
+
+ if (L.FrameOffset)
+ OS << *L.FrameOffset;
+ else
+ OS << DILineInfo::Addr2LineBadString;
+ OS << ' ';
+
+ if (L.Size)
+ OS << *L.Size;
+ else
+ OS << DILineInfo::Addr2LineBadString;
+ OS << ' ';
+
+ if (L.TagOffset)
+ OS << *L.TagOffset;
+ else
+ OS << DILineInfo::Addr2LineBadString;
+ OS << '\n';
+ }
+ printFooter();
+}
+
+void PlainPrinterBase::printInvalidCommand(const Request &Request,
+ StringRef Command) {
+ OS << Command << '\n';
+}
+
+bool PlainPrinterBase::printError(const Request &Request,
+ const ErrorInfoBase &ErrorInfo,
+ StringRef ErrorBanner) {
+ ES << ErrorBanner;
+ ErrorInfo.log(ES);
+ ES << '\n';
+ // Print an empty struct too.
+ return true;
+}
+
+static std::string toHex(uint64_t V) {
+ return ("0x" + Twine::utohexstr(V)).str();
+}
+
+static json::Object toJSON(const Request &Request, StringRef ErrorMsg = "") {
+ json::Object Json({{"ModuleName", Request.ModuleName.str()}});
+ if (Request.Address)
+ Json["Address"] = toHex(*Request.Address);
+ if (!ErrorMsg.empty())
+ Json["Error"] = json::Object({{"Message", ErrorMsg.str()}});
+ return Json;
+}
+
+void JSONPrinter::print(const Request &Request, const DILineInfo &Info) {
+ DIInliningInfo InliningInfo;
+ InliningInfo.addFrame(Info);
+ print(Request, InliningInfo);
+}
+
+void JSONPrinter::print(const Request &Request, const DIInliningInfo &Info) {
+ json::Array Array;
+ for (uint32_t I = 0, N = Info.getNumberOfFrames(); I < N; ++I) {
+ const DILineInfo &LineInfo = Info.getFrame(I);
+ json::Object Object(
+ {{"FunctionName", LineInfo.FunctionName != DILineInfo::BadString
+ ? LineInfo.FunctionName
+ : ""},
+ {"StartFileName", LineInfo.StartFileName != DILineInfo::BadString
+ ? LineInfo.StartFileName
+ : ""},
+ {"StartLine", LineInfo.StartLine},
+ {"StartAddress",
+ LineInfo.StartAddress ? toHex(*LineInfo.StartAddress) : ""},
+ {"FileName",
+ LineInfo.FileName != DILineInfo::BadString ? LineInfo.FileName : ""},
+ {"Line", LineInfo.Line},
+ {"Column", LineInfo.Column},
+ {"Discriminator", LineInfo.Discriminator}});
+ SourceCode SourceCode(LineInfo.FileName, LineInfo.Line,
+ Config.SourceContextLines, LineInfo.Source);
+ std::string FormattedSource;
+ raw_string_ostream Stream(FormattedSource);
+ SourceCode.format(Stream);
+ if (!FormattedSource.empty())
+ Object["Source"] = std::move(FormattedSource);
+ Array.push_back(std::move(Object));
+ }
+ json::Object Json = toJSON(Request);
+ Json["Symbol"] = std::move(Array);
+ if (ObjectList)
+ ObjectList->push_back(std::move(Json));
+ else
+ printJSON(std::move(Json));
+}
+
+void JSONPrinter::print(const Request &Request, const DIGlobal &Global) {
+ json::Object Data(
+ {{"Name", Global.Name != DILineInfo::BadString ? Global.Name : ""},
+ {"Start", toHex(Global.Start)},
+ {"Size", toHex(Global.Size)}});
+ json::Object Json = toJSON(Request);
+ Json["Data"] = std::move(Data);
+ if (ObjectList)
+ ObjectList->push_back(std::move(Json));
+ else
+ printJSON(std::move(Json));
+}
+
+void JSONPrinter::print(const Request &Request,
+ const std::vector<DILocal> &Locals) {
+ json::Array Frame;
+ for (const DILocal &Local : Locals) {
+ json::Object FrameObject(
+ {{"FunctionName", Local.FunctionName},
+ {"Name", Local.Name},
+ {"DeclFile", Local.DeclFile},
+ {"DeclLine", int64_t(Local.DeclLine)},
+ {"Size", Local.Size ? toHex(*Local.Size) : ""},
+ {"TagOffset", Local.TagOffset ? toHex(*Local.TagOffset) : ""}});
+ if (Local.FrameOffset)
+ FrameObject["FrameOffset"] = *Local.FrameOffset;
+ Frame.push_back(std::move(FrameObject));
+ }
+ json::Object Json = toJSON(Request);
+ Json["Frame"] = std::move(Frame);
+ if (ObjectList)
+ ObjectList->push_back(std::move(Json));
+ else
+ printJSON(std::move(Json));
+}
+
+void JSONPrinter::printInvalidCommand(const Request &Request,
+ StringRef Command) {
+ printError(Request,
+ StringError("unable to parse arguments: " + Command,
+ std::make_error_code(std::errc::invalid_argument)),
+ "");
+}
+
+bool JSONPrinter::printError(const Request &Request,
+ const ErrorInfoBase &ErrorInfo,
+ StringRef ErrorBanner) {
+ json::Object Json = toJSON(Request, ErrorInfo.message());
+ if (ObjectList)
+ ObjectList->push_back(std::move(Json));
+ else
+ printJSON(std::move(Json));
+ return false;
+}
+
+void JSONPrinter::listBegin() {
+ assert(!ObjectList);
+ ObjectList = std::make_unique<json::Array>();
+}
+
+void JSONPrinter::listEnd() {
+ assert(ObjectList);
+ printJSON(std::move(*ObjectList));
+ ObjectList.reset();
+}
+
+} // end namespace symbolize
+} // end namespace llvm
diff --git a/contrib/libs/llvm14/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp b/contrib/libs/llvm14/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
new file mode 100644
index 0000000000..a9c78830fa
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/Symbolize/SymbolizableObjectFile.cpp
@@ -0,0 +1,355 @@
+//===- SymbolizableObjectFile.cpp -----------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation of SymbolizableObjectFile class.
+//
+//===----------------------------------------------------------------------===//
+
+#include "SymbolizableObjectFile.h"
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/ADT/Triple.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/ELFObjectFile.h"
+#include "llvm/Object/ObjectFile.h"
+#include "llvm/Object/SymbolSize.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/DataExtractor.h"
+#include <algorithm>
+
+using namespace llvm;
+using namespace object;
+using namespace symbolize;
+
+Expected<std::unique_ptr<SymbolizableObjectFile>>
+SymbolizableObjectFile::create(const object::ObjectFile *Obj,
+ std::unique_ptr<DIContext> DICtx,
+ bool UntagAddresses) {
+ assert(DICtx);
+ std::unique_ptr<SymbolizableObjectFile> res(
+ new SymbolizableObjectFile(Obj, std::move(DICtx), UntagAddresses));
+ std::unique_ptr<DataExtractor> OpdExtractor;
+ uint64_t OpdAddress = 0;
+ // Find the .opd (function descriptor) section if any, for big-endian
+ // PowerPC64 ELF.
+ if (Obj->getArch() == Triple::ppc64) {
+ for (section_iterator Section : Obj->sections()) {
+ Expected<StringRef> NameOrErr = Section->getName();
+ if (!NameOrErr)
+ return NameOrErr.takeError();
+
+ if (*NameOrErr == ".opd") {
+ Expected<StringRef> E = Section->getContents();
+ if (!E)
+ return E.takeError();
+ OpdExtractor.reset(new DataExtractor(*E, Obj->isLittleEndian(),
+ Obj->getBytesInAddress()));
+ OpdAddress = Section->getAddress();
+ break;
+ }
+ }
+ }
+ std::vector<std::pair<SymbolRef, uint64_t>> Symbols =
+ computeSymbolSizes(*Obj);
+ for (auto &P : Symbols)
+ if (Error E =
+ res->addSymbol(P.first, P.second, OpdExtractor.get(), OpdAddress))
+ return std::move(E);
+
+ // If this is a COFF object and we didn't find any symbols, try the export
+ // table.
+ if (Symbols.empty()) {
+ if (auto *CoffObj = dyn_cast<COFFObjectFile>(Obj))
+ if (Error E = res->addCoffExportSymbols(CoffObj))
+ return std::move(E);
+ }
+
+ std::vector<SymbolDesc> &SS = res->Symbols;
+ // Sort by (Addr,Size,Name). If several SymbolDescs share the same Addr,
+ // pick the one with the largest Size. This helps us avoid symbols with no
+ // size information (Size=0).
+ llvm::stable_sort(SS);
+ auto I = SS.begin(), E = SS.end(), J = SS.begin();
+ while (I != E) {
+ auto OI = I;
+ while (++I != E && OI->Addr == I->Addr) {
+ }
+ *J++ = I[-1];
+ }
+ SS.erase(J, SS.end());
+
+ return std::move(res);
+}
+
+SymbolizableObjectFile::SymbolizableObjectFile(const ObjectFile *Obj,
+ std::unique_ptr<DIContext> DICtx,
+ bool UntagAddresses)
+ : Module(Obj), DebugInfoContext(std::move(DICtx)),
+ UntagAddresses(UntagAddresses) {}
+
+namespace {
+
+struct OffsetNamePair {
+ uint32_t Offset;
+ StringRef Name;
+
+ bool operator<(const OffsetNamePair &R) const {
+ return Offset < R.Offset;
+ }
+};
+
+} // end anonymous namespace
+
+Error SymbolizableObjectFile::addCoffExportSymbols(
+ const COFFObjectFile *CoffObj) {
+ // Get all export names and offsets.
+ std::vector<OffsetNamePair> ExportSyms;
+ for (const ExportDirectoryEntryRef &Ref : CoffObj->export_directories()) {
+ StringRef Name;
+ uint32_t Offset;
+ if (auto EC = Ref.getSymbolName(Name))
+ return EC;
+ if (auto EC = Ref.getExportRVA(Offset))
+ return EC;
+ ExportSyms.push_back(OffsetNamePair{Offset, Name});
+ }
+ if (ExportSyms.empty())
+ return Error::success();
+
+ // Sort by ascending offset.
+ array_pod_sort(ExportSyms.begin(), ExportSyms.end());
+
+ // Approximate the symbol sizes by assuming they run to the next symbol.
+ // FIXME: This assumes all exports are functions.
+ uint64_t ImageBase = CoffObj->getImageBase();
+ for (auto I = ExportSyms.begin(), E = ExportSyms.end(); I != E; ++I) {
+ OffsetNamePair &Export = *I;
+ // FIXME: The last export has a one byte size now.
+ uint32_t NextOffset = I != E ? I->Offset : Export.Offset + 1;
+ uint64_t SymbolStart = ImageBase + Export.Offset;
+ uint64_t SymbolSize = NextOffset - Export.Offset;
+ Symbols.push_back({SymbolStart, SymbolSize, Export.Name, 0});
+ }
+ return Error::success();
+}
+
+Error SymbolizableObjectFile::addSymbol(const SymbolRef &Symbol,
+ uint64_t SymbolSize,
+ DataExtractor *OpdExtractor,
+ uint64_t OpdAddress) {
+ // Avoid adding symbols from an unknown/undefined section.
+ const ObjectFile &Obj = *Symbol.getObject();
+ Expected<StringRef> SymbolNameOrErr = Symbol.getName();
+ if (!SymbolNameOrErr)
+ return SymbolNameOrErr.takeError();
+ StringRef SymbolName = *SymbolNameOrErr;
+
+ uint32_t ELFSymIdx =
+ Obj.isELF() ? ELFSymbolRef(Symbol).getRawDataRefImpl().d.b : 0;
+ Expected<section_iterator> Sec = Symbol.getSection();
+ if (!Sec || Obj.section_end() == *Sec) {
+ if (Obj.isELF()) {
+ // Store the (index, filename) pair for a file symbol.
+ ELFSymbolRef ESym(Symbol);
+ if (ESym.getELFType() == ELF::STT_FILE)
+ FileSymbols.emplace_back(ELFSymIdx, SymbolName);
+ }
+ return Error::success();
+ }
+
+ Expected<SymbolRef::Type> SymbolTypeOrErr = Symbol.getType();
+ if (!SymbolTypeOrErr)
+ return SymbolTypeOrErr.takeError();
+ SymbolRef::Type SymbolType = *SymbolTypeOrErr;
+ if (Obj.isELF()) {
+ // Allow function and data symbols. Additionally allow STT_NONE, which are
+ // common for functions defined in assembly.
+ uint8_t Type = ELFSymbolRef(Symbol).getELFType();
+ if (Type != ELF::STT_NOTYPE && Type != ELF::STT_FUNC &&
+ Type != ELF::STT_OBJECT && Type != ELF::STT_GNU_IFUNC)
+ return Error::success();
+ // Some STT_NOTYPE symbols are not desired. This excludes STT_SECTION and
+ // ARM mapping symbols.
+ uint32_t Flags = cantFail(Symbol.getFlags());
+ if (Flags & SymbolRef::SF_FormatSpecific)
+ return Error::success();
+ } else if (SymbolType != SymbolRef::ST_Function &&
+ SymbolType != SymbolRef::ST_Data) {
+ return Error::success();
+ }
+
+ Expected<uint64_t> SymbolAddressOrErr = Symbol.getAddress();
+ if (!SymbolAddressOrErr)
+ return SymbolAddressOrErr.takeError();
+ uint64_t SymbolAddress = *SymbolAddressOrErr;
+ if (UntagAddresses) {
+ // For kernel addresses, bits 56-63 need to be set, so we sign extend bit 55
+ // into bits 56-63 instead of masking them out.
+ SymbolAddress &= (1ull << 56) - 1;
+ SymbolAddress = (int64_t(SymbolAddress) << 8) >> 8;
+ }
+ if (OpdExtractor) {
+ // For big-endian PowerPC64 ELF, symbols in the .opd section refer to
+ // function descriptors. The first word of the descriptor is a pointer to
+ // the function's code.
+ // For the purposes of symbolization, pretend the symbol's address is that
+ // of the function's code, not the descriptor.
+ uint64_t OpdOffset = SymbolAddress - OpdAddress;
+ if (OpdExtractor->isValidOffsetForAddress(OpdOffset))
+ SymbolAddress = OpdExtractor->getAddress(&OpdOffset);
+ }
+ // Mach-O symbol table names have leading underscore, skip it.
+ if (Module->isMachO() && !SymbolName.empty() && SymbolName[0] == '_')
+ SymbolName = SymbolName.drop_front();
+
+ if (Obj.isELF() && ELFSymbolRef(Symbol).getBinding() != ELF::STB_LOCAL)
+ ELFSymIdx = 0;
+ Symbols.push_back({SymbolAddress, SymbolSize, SymbolName, ELFSymIdx});
+ return Error::success();
+}
+
+// Return true if this is a 32-bit x86 PE COFF module.
+bool SymbolizableObjectFile::isWin32Module() const {
+ auto *CoffObject = dyn_cast<COFFObjectFile>(Module);
+ return CoffObject && CoffObject->getMachine() == COFF::IMAGE_FILE_MACHINE_I386;
+}
+
+uint64_t SymbolizableObjectFile::getModulePreferredBase() const {
+ if (auto *CoffObject = dyn_cast<COFFObjectFile>(Module))
+ return CoffObject->getImageBase();
+ return 0;
+}
+
+bool SymbolizableObjectFile::getNameFromSymbolTable(
+ uint64_t Address, std::string &Name, uint64_t &Addr, uint64_t &Size,
+ std::string &FileName) const {
+ SymbolDesc SD{Address, UINT64_C(-1), StringRef(), 0};
+ auto SymbolIterator = llvm::upper_bound(Symbols, SD);
+ if (SymbolIterator == Symbols.begin())
+ return false;
+ --SymbolIterator;
+ if (SymbolIterator->Size != 0 &&
+ SymbolIterator->Addr + SymbolIterator->Size <= Address)
+ return false;
+ Name = SymbolIterator->Name.str();
+ Addr = SymbolIterator->Addr;
+ Size = SymbolIterator->Size;
+
+ if (SymbolIterator->ELFLocalSymIdx != 0) {
+ // If this is an ELF local symbol, find the STT_FILE symbol preceding
+ // SymbolIterator to get the filename. The ELF spec requires the STT_FILE
+ // symbol (if present) precedes the other STB_LOCAL symbols for the file.
+ assert(Module->isELF());
+ auto It = llvm::upper_bound(
+ FileSymbols,
+ std::make_pair(SymbolIterator->ELFLocalSymIdx, StringRef()));
+ if (It != FileSymbols.begin())
+ FileName = It[-1].second.str();
+ }
+ return true;
+}
+
+bool SymbolizableObjectFile::shouldOverrideWithSymbolTable(
+ FunctionNameKind FNKind, bool UseSymbolTable) const {
+ // When DWARF is used with -gline-tables-only / -gmlt, the symbol table gives
+ // better answers for linkage names than the DIContext. Otherwise, we are
+ // probably using PEs and PDBs, and we shouldn't do the override. PE files
+ // generally only contain the names of exported symbols.
+ return FNKind == FunctionNameKind::LinkageName && UseSymbolTable &&
+ isa<DWARFContext>(DebugInfoContext.get());
+}
+
+DILineInfo
+SymbolizableObjectFile::symbolizeCode(object::SectionedAddress ModuleOffset,
+ DILineInfoSpecifier LineInfoSpecifier,
+ bool UseSymbolTable) const {
+ if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection)
+ ModuleOffset.SectionIndex =
+ getModuleSectionIndexForAddress(ModuleOffset.Address);
+ DILineInfo LineInfo =
+ DebugInfoContext->getLineInfoForAddress(ModuleOffset, LineInfoSpecifier);
+
+ // Override function name from symbol table if necessary.
+ if (shouldOverrideWithSymbolTable(LineInfoSpecifier.FNKind, UseSymbolTable)) {
+ std::string FunctionName, FileName;
+ uint64_t Start, Size;
+ if (getNameFromSymbolTable(ModuleOffset.Address, FunctionName, Start, Size,
+ FileName)) {
+ LineInfo.FunctionName = FunctionName;
+ LineInfo.StartAddress = Start;
+ if (LineInfo.FileName == DILineInfo::BadString && !FileName.empty())
+ LineInfo.FileName = FileName;
+ }
+ }
+ return LineInfo;
+}
+
+DIInliningInfo SymbolizableObjectFile::symbolizeInlinedCode(
+ object::SectionedAddress ModuleOffset,
+ DILineInfoSpecifier LineInfoSpecifier, bool UseSymbolTable) const {
+ if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection)
+ ModuleOffset.SectionIndex =
+ getModuleSectionIndexForAddress(ModuleOffset.Address);
+ DIInliningInfo InlinedContext = DebugInfoContext->getInliningInfoForAddress(
+ ModuleOffset, LineInfoSpecifier);
+
+ // Make sure there is at least one frame in context.
+ if (InlinedContext.getNumberOfFrames() == 0)
+ InlinedContext.addFrame(DILineInfo());
+
+ // Override the function name in lower frame with name from symbol table.
+ if (shouldOverrideWithSymbolTable(LineInfoSpecifier.FNKind, UseSymbolTable)) {
+ std::string FunctionName, FileName;
+ uint64_t Start, Size;
+ if (getNameFromSymbolTable(ModuleOffset.Address, FunctionName, Start, Size,
+ FileName)) {
+ DILineInfo *LI = InlinedContext.getMutableFrame(
+ InlinedContext.getNumberOfFrames() - 1);
+ LI->FunctionName = FunctionName;
+ LI->StartAddress = Start;
+ if (LI->FileName == DILineInfo::BadString && !FileName.empty())
+ LI->FileName = FileName;
+ }
+ }
+
+ return InlinedContext;
+}
+
+DIGlobal SymbolizableObjectFile::symbolizeData(
+ object::SectionedAddress ModuleOffset) const {
+ DIGlobal Res;
+ std::string FileName;
+ getNameFromSymbolTable(ModuleOffset.Address, Res.Name, Res.Start, Res.Size,
+ FileName);
+ return Res;
+}
+
+std::vector<DILocal> SymbolizableObjectFile::symbolizeFrame(
+ object::SectionedAddress ModuleOffset) const {
+ if (ModuleOffset.SectionIndex == object::SectionedAddress::UndefSection)
+ ModuleOffset.SectionIndex =
+ getModuleSectionIndexForAddress(ModuleOffset.Address);
+ return DebugInfoContext->getLocalsForAddress(ModuleOffset);
+}
+
+/// Search for the first occurence of specified Address in ObjectFile.
+uint64_t SymbolizableObjectFile::getModuleSectionIndexForAddress(
+ uint64_t Address) const {
+
+ for (SectionRef Sec : Module->sections()) {
+ if (!Sec.isText() || Sec.isVirtual())
+ continue;
+
+ if (Address >= Sec.getAddress() &&
+ Address < Sec.getAddress() + Sec.getSize())
+ return Sec.getIndex();
+ }
+
+ return object::SectionedAddress::UndefSection;
+}
diff --git a/contrib/libs/llvm14/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h b/contrib/libs/llvm14/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h
new file mode 100644
index 0000000000..8fb003fff0
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/Symbolize/SymbolizableObjectFile.h
@@ -0,0 +1,103 @@
+//===- SymbolizableObjectFile.h ---------------------------------*- 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
+//
+//===----------------------------------------------------------------------===//
+//
+// This file declares the SymbolizableObjectFile class.
+//
+//===----------------------------------------------------------------------===//
+#ifndef LLVM_LIB_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEOBJECTFILE_H
+#define LLVM_LIB_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEOBJECTFILE_H
+
+#include "llvm/ADT/StringRef.h"
+#include "llvm/DebugInfo/DIContext.h"
+#include "llvm/DebugInfo/Symbolize/SymbolizableModule.h"
+#include "llvm/Support/Error.h"
+#include <cstdint>
+#include <memory>
+#include <string>
+#include <utility>
+#include <vector>
+
+namespace llvm {
+
+class DataExtractor;
+
+namespace symbolize {
+
+class SymbolizableObjectFile : public SymbolizableModule {
+public:
+ static Expected<std::unique_ptr<SymbolizableObjectFile>>
+ create(const object::ObjectFile *Obj, std::unique_ptr<DIContext> DICtx,
+ bool UntagAddresses);
+
+ DILineInfo symbolizeCode(object::SectionedAddress ModuleOffset,
+ DILineInfoSpecifier LineInfoSpecifier,
+ bool UseSymbolTable) const override;
+ DIInliningInfo symbolizeInlinedCode(object::SectionedAddress ModuleOffset,
+ DILineInfoSpecifier LineInfoSpecifier,
+ bool UseSymbolTable) const override;
+ DIGlobal symbolizeData(object::SectionedAddress ModuleOffset) const override;
+ std::vector<DILocal>
+ symbolizeFrame(object::SectionedAddress ModuleOffset) const override;
+
+ // Return true if this is a 32-bit x86 PE COFF module.
+ bool isWin32Module() const override;
+
+ // Returns the preferred base of the module, i.e. where the loader would place
+ // it in memory assuming there were no conflicts.
+ uint64_t getModulePreferredBase() const override;
+
+private:
+ bool shouldOverrideWithSymbolTable(FunctionNameKind FNKind,
+ bool UseSymbolTable) const;
+
+ bool getNameFromSymbolTable(uint64_t Address, std::string &Name,
+ uint64_t &Addr, uint64_t &Size,
+ std::string &FileName) const;
+ // For big-endian PowerPC64 ELF, OpdAddress is the address of the .opd
+ // (function descriptor) section and OpdExtractor refers to its contents.
+ Error addSymbol(const object::SymbolRef &Symbol, uint64_t SymbolSize,
+ DataExtractor *OpdExtractor = nullptr,
+ uint64_t OpdAddress = 0);
+ Error addCoffExportSymbols(const object::COFFObjectFile *CoffObj);
+
+ /// Search for the first occurence of specified Address in ObjectFile.
+ uint64_t getModuleSectionIndexForAddress(uint64_t Address) const;
+
+ const object::ObjectFile *Module;
+ std::unique_ptr<DIContext> DebugInfoContext;
+ bool UntagAddresses;
+
+ struct SymbolDesc {
+ uint64_t Addr;
+ // If size is 0, assume that symbol occupies the whole memory range up to
+ // the following symbol.
+ uint64_t Size;
+
+ StringRef Name;
+ // Non-zero if this is an ELF local symbol. See the comment in
+ // getNameFromSymbolTable.
+ uint32_t ELFLocalSymIdx;
+
+ bool operator<(const SymbolDesc &RHS) const {
+ return Addr != RHS.Addr ? Addr < RHS.Addr : Size < RHS.Size;
+ }
+ };
+ std::vector<SymbolDesc> Symbols;
+ // (index, filename) pairs of ELF STT_FILE symbols.
+ std::vector<std::pair<uint32_t, StringRef>> FileSymbols;
+
+ SymbolizableObjectFile(const object::ObjectFile *Obj,
+ std::unique_ptr<DIContext> DICtx,
+ bool UntagAddresses);
+};
+
+} // end namespace symbolize
+
+} // end namespace llvm
+
+#endif // LLVM_LIB_DEBUGINFO_SYMBOLIZE_SYMBOLIZABLEOBJECTFILE_H
diff --git a/contrib/libs/llvm14/lib/DebugInfo/Symbolize/Symbolize.cpp b/contrib/libs/llvm14/lib/DebugInfo/Symbolize/Symbolize.cpp
new file mode 100644
index 0000000000..f085cc63a8
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/Symbolize/Symbolize.cpp
@@ -0,0 +1,659 @@
+//===-- LLVMSymbolize.cpp -------------------------------------------------===//
+//
+// 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
+//
+//===----------------------------------------------------------------------===//
+//
+// Implementation for LLVM symbolization library.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/Symbolize/Symbolize.h"
+
+#include "SymbolizableObjectFile.h"
+
+#include "llvm/ADT/STLExtras.h"
+#include "llvm/BinaryFormat/COFF.h"
+#include "llvm/Config/config.h"
+#include "llvm/DebugInfo/DWARF/DWARFContext.h"
+#include "llvm/DebugInfo/PDB/PDB.h"
+#include "llvm/DebugInfo/PDB/PDBContext.h"
+#include "llvm/DebugInfo/Symbolize/DIFetcher.h"
+#include "llvm/Demangle/Demangle.h"
+#include "llvm/Object/COFF.h"
+#include "llvm/Object/MachO.h"
+#include "llvm/Object/MachOUniversal.h"
+#include "llvm/Support/CRC.h"
+#include "llvm/Support/Casting.h"
+#include "llvm/Support/Compression.h"
+#include "llvm/Support/DataExtractor.h"
+#include "llvm/Support/Errc.h"
+#include "llvm/Support/FileSystem.h"
+#include "llvm/Support/MemoryBuffer.h"
+#include "llvm/Support/Path.h"
+#include <algorithm>
+#include <cassert>
+#include <cstring>
+
+namespace llvm {
+namespace symbolize {
+
+template <typename T>
+Expected<DILineInfo>
+LLVMSymbolizer::symbolizeCodeCommon(const T &ModuleSpecifier,
+ object::SectionedAddress ModuleOffset) {
+
+ auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
+ if (!InfoOrErr)
+ return InfoOrErr.takeError();
+
+ SymbolizableModule *Info = *InfoOrErr;
+
+ // A null module means an error has already been reported. Return an empty
+ // result.
+ if (!Info)
+ return DILineInfo();
+
+ // If the user is giving us relative addresses, add the preferred base of the
+ // object to the offset before we do the query. It's what DIContext expects.
+ if (Opts.RelativeAddresses)
+ ModuleOffset.Address += Info->getModulePreferredBase();
+
+ DILineInfo LineInfo = Info->symbolizeCode(
+ ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
+ Opts.UseSymbolTable);
+ if (Opts.Demangle)
+ LineInfo.FunctionName = DemangleName(LineInfo.FunctionName, Info);
+ return LineInfo;
+}
+
+Expected<DILineInfo>
+LLVMSymbolizer::symbolizeCode(const ObjectFile &Obj,
+ object::SectionedAddress ModuleOffset) {
+ return symbolizeCodeCommon(Obj, ModuleOffset);
+}
+
+Expected<DILineInfo>
+LLVMSymbolizer::symbolizeCode(const std::string &ModuleName,
+ object::SectionedAddress ModuleOffset) {
+ return symbolizeCodeCommon(ModuleName, ModuleOffset);
+}
+
+template <typename T>
+Expected<DIInliningInfo> LLVMSymbolizer::symbolizeInlinedCodeCommon(
+ const T &ModuleSpecifier, object::SectionedAddress ModuleOffset) {
+ auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
+ if (!InfoOrErr)
+ return InfoOrErr.takeError();
+
+ SymbolizableModule *Info = *InfoOrErr;
+
+ // A null module means an error has already been reported. Return an empty
+ // result.
+ if (!Info)
+ return DIInliningInfo();
+
+ // If the user is giving us relative addresses, add the preferred base of the
+ // object to the offset before we do the query. It's what DIContext expects.
+ if (Opts.RelativeAddresses)
+ ModuleOffset.Address += Info->getModulePreferredBase();
+
+ DIInliningInfo InlinedContext = Info->symbolizeInlinedCode(
+ ModuleOffset, DILineInfoSpecifier(Opts.PathStyle, Opts.PrintFunctions),
+ Opts.UseSymbolTable);
+ if (Opts.Demangle) {
+ for (int i = 0, n = InlinedContext.getNumberOfFrames(); i < n; i++) {
+ auto *Frame = InlinedContext.getMutableFrame(i);
+ Frame->FunctionName = DemangleName(Frame->FunctionName, Info);
+ }
+ }
+ return InlinedContext;
+}
+
+Expected<DIInliningInfo>
+LLVMSymbolizer::symbolizeInlinedCode(const ObjectFile &Obj,
+ object::SectionedAddress ModuleOffset) {
+ return symbolizeInlinedCodeCommon(Obj, ModuleOffset);
+}
+
+Expected<DIInliningInfo>
+LLVMSymbolizer::symbolizeInlinedCode(const std::string &ModuleName,
+ object::SectionedAddress ModuleOffset) {
+ return symbolizeInlinedCodeCommon(ModuleName, ModuleOffset);
+}
+
+template <typename T>
+Expected<DIGlobal>
+LLVMSymbolizer::symbolizeDataCommon(const T &ModuleSpecifier,
+ object::SectionedAddress ModuleOffset) {
+
+ auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
+ if (!InfoOrErr)
+ return InfoOrErr.takeError();
+
+ SymbolizableModule *Info = *InfoOrErr;
+ // A null module means an error has already been reported. Return an empty
+ // result.
+ if (!Info)
+ return DIGlobal();
+
+ // If the user is giving us relative addresses, add the preferred base of
+ // the object to the offset before we do the query. It's what DIContext
+ // expects.
+ if (Opts.RelativeAddresses)
+ ModuleOffset.Address += Info->getModulePreferredBase();
+
+ DIGlobal Global = Info->symbolizeData(ModuleOffset);
+ if (Opts.Demangle)
+ Global.Name = DemangleName(Global.Name, Info);
+ return Global;
+}
+
+Expected<DIGlobal>
+LLVMSymbolizer::symbolizeData(const ObjectFile &Obj,
+ object::SectionedAddress ModuleOffset) {
+ return symbolizeDataCommon(Obj, ModuleOffset);
+}
+
+Expected<DIGlobal>
+LLVMSymbolizer::symbolizeData(const std::string &ModuleName,
+ object::SectionedAddress ModuleOffset) {
+ return symbolizeDataCommon(ModuleName, ModuleOffset);
+}
+
+template <typename T>
+Expected<std::vector<DILocal>>
+LLVMSymbolizer::symbolizeFrameCommon(const T &ModuleSpecifier,
+ object::SectionedAddress ModuleOffset) {
+ auto InfoOrErr = getOrCreateModuleInfo(ModuleSpecifier);
+ if (!InfoOrErr)
+ return InfoOrErr.takeError();
+
+ SymbolizableModule *Info = *InfoOrErr;
+ // A null module means an error has already been reported. Return an empty
+ // result.
+ if (!Info)
+ return std::vector<DILocal>();
+
+ // If the user is giving us relative addresses, add the preferred base of
+ // the object to the offset before we do the query. It's what DIContext
+ // expects.
+ if (Opts.RelativeAddresses)
+ ModuleOffset.Address += Info->getModulePreferredBase();
+
+ return Info->symbolizeFrame(ModuleOffset);
+}
+
+Expected<std::vector<DILocal>>
+LLVMSymbolizer::symbolizeFrame(const ObjectFile &Obj,
+ object::SectionedAddress ModuleOffset) {
+ return symbolizeFrameCommon(Obj, ModuleOffset);
+}
+
+Expected<std::vector<DILocal>>
+LLVMSymbolizer::symbolizeFrame(const std::string &ModuleName,
+ object::SectionedAddress ModuleOffset) {
+ return symbolizeFrameCommon(ModuleName, ModuleOffset);
+}
+
+void LLVMSymbolizer::flush() {
+ ObjectForUBPathAndArch.clear();
+ BinaryForPath.clear();
+ ObjectPairForPathArch.clear();
+ Modules.clear();
+}
+
+namespace {
+
+// For Path="/path/to/foo" and Basename="foo" assume that debug info is in
+// /path/to/foo.dSYM/Contents/Resources/DWARF/foo.
+// For Path="/path/to/bar.dSYM" and Basename="foo" assume that debug info is in
+// /path/to/bar.dSYM/Contents/Resources/DWARF/foo.
+std::string getDarwinDWARFResourceForPath(const std::string &Path,
+ const std::string &Basename) {
+ SmallString<16> ResourceName = StringRef(Path);
+ if (sys::path::extension(Path) != ".dSYM") {
+ ResourceName += ".dSYM";
+ }
+ sys::path::append(ResourceName, "Contents", "Resources", "DWARF");
+ sys::path::append(ResourceName, Basename);
+ return std::string(ResourceName.str());
+}
+
+bool checkFileCRC(StringRef Path, uint32_t CRCHash) {
+ ErrorOr<std::unique_ptr<MemoryBuffer>> MB =
+ MemoryBuffer::getFileOrSTDIN(Path);
+ if (!MB)
+ return false;
+ return CRCHash == llvm::crc32(arrayRefFromStringRef(MB.get()->getBuffer()));
+}
+
+bool getGNUDebuglinkContents(const ObjectFile *Obj, std::string &DebugName,
+ uint32_t &CRCHash) {
+ if (!Obj)
+ return false;
+ for (const SectionRef &Section : Obj->sections()) {
+ StringRef Name;
+ consumeError(Section.getName().moveInto(Name));
+
+ Name = Name.substr(Name.find_first_not_of("._"));
+ if (Name == "gnu_debuglink") {
+ Expected<StringRef> ContentsOrErr = Section.getContents();
+ if (!ContentsOrErr) {
+ consumeError(ContentsOrErr.takeError());
+ return false;
+ }
+ DataExtractor DE(*ContentsOrErr, Obj->isLittleEndian(), 0);
+ uint64_t Offset = 0;
+ if (const char *DebugNameStr = DE.getCStr(&Offset)) {
+ // 4-byte align the offset.
+ Offset = (Offset + 3) & ~0x3;
+ if (DE.isValidOffsetForDataOfSize(Offset, 4)) {
+ DebugName = DebugNameStr;
+ CRCHash = DE.getU32(&Offset);
+ return true;
+ }
+ }
+ break;
+ }
+ }
+ return false;
+}
+
+bool darwinDsymMatchesBinary(const MachOObjectFile *DbgObj,
+ const MachOObjectFile *Obj) {
+ ArrayRef<uint8_t> dbg_uuid = DbgObj->getUuid();
+ ArrayRef<uint8_t> bin_uuid = Obj->getUuid();
+ if (dbg_uuid.empty() || bin_uuid.empty())
+ return false;
+ return !memcmp(dbg_uuid.data(), bin_uuid.data(), dbg_uuid.size());
+}
+
+template <typename ELFT>
+Optional<ArrayRef<uint8_t>> getBuildID(const ELFFile<ELFT> &Obj) {
+ auto PhdrsOrErr = Obj.program_headers();
+ if (!PhdrsOrErr) {
+ consumeError(PhdrsOrErr.takeError());
+ return {};
+ }
+ for (const auto &P : *PhdrsOrErr) {
+ if (P.p_type != ELF::PT_NOTE)
+ continue;
+ Error Err = Error::success();
+ for (auto N : Obj.notes(P, Err))
+ if (N.getType() == ELF::NT_GNU_BUILD_ID &&
+ N.getName() == ELF::ELF_NOTE_GNU)
+ return N.getDesc();
+ consumeError(std::move(Err));
+ }
+ return {};
+}
+
+Optional<ArrayRef<uint8_t>> getBuildID(const ELFObjectFileBase *Obj) {
+ Optional<ArrayRef<uint8_t>> BuildID;
+ if (auto *O = dyn_cast<ELFObjectFile<ELF32LE>>(Obj))
+ BuildID = getBuildID(O->getELFFile());
+ else if (auto *O = dyn_cast<ELFObjectFile<ELF32BE>>(Obj))
+ BuildID = getBuildID(O->getELFFile());
+ else if (auto *O = dyn_cast<ELFObjectFile<ELF64LE>>(Obj))
+ BuildID = getBuildID(O->getELFFile());
+ else if (auto *O = dyn_cast<ELFObjectFile<ELF64BE>>(Obj))
+ BuildID = getBuildID(O->getELFFile());
+ else
+ llvm_unreachable("unsupported file format");
+ return BuildID;
+}
+
+} // end anonymous namespace
+
+ObjectFile *LLVMSymbolizer::lookUpDsymFile(const std::string &ExePath,
+ const MachOObjectFile *MachExeObj,
+ const std::string &ArchName) {
+ // On Darwin we may find DWARF in separate object file in
+ // resource directory.
+ std::vector<std::string> DsymPaths;
+ StringRef Filename = sys::path::filename(ExePath);
+ DsymPaths.push_back(
+ getDarwinDWARFResourceForPath(ExePath, std::string(Filename)));
+ for (const auto &Path : Opts.DsymHints) {
+ DsymPaths.push_back(
+ getDarwinDWARFResourceForPath(Path, std::string(Filename)));
+ }
+ for (const auto &Path : DsymPaths) {
+ auto DbgObjOrErr = getOrCreateObject(Path, ArchName);
+ if (!DbgObjOrErr) {
+ // Ignore errors, the file might not exist.
+ consumeError(DbgObjOrErr.takeError());
+ continue;
+ }
+ ObjectFile *DbgObj = DbgObjOrErr.get();
+ if (!DbgObj)
+ continue;
+ const MachOObjectFile *MachDbgObj = dyn_cast<const MachOObjectFile>(DbgObj);
+ if (!MachDbgObj)
+ continue;
+ if (darwinDsymMatchesBinary(MachDbgObj, MachExeObj))
+ return DbgObj;
+ }
+ return nullptr;
+}
+
+ObjectFile *LLVMSymbolizer::lookUpDebuglinkObject(const std::string &Path,
+ const ObjectFile *Obj,
+ const std::string &ArchName) {
+ std::string DebuglinkName;
+ uint32_t CRCHash;
+ std::string DebugBinaryPath;
+ if (!getGNUDebuglinkContents(Obj, DebuglinkName, CRCHash))
+ return nullptr;
+ if (!findDebugBinary(Path, DebuglinkName, CRCHash, DebugBinaryPath))
+ return nullptr;
+ auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
+ if (!DbgObjOrErr) {
+ // Ignore errors, the file might not exist.
+ consumeError(DbgObjOrErr.takeError());
+ return nullptr;
+ }
+ return DbgObjOrErr.get();
+}
+
+ObjectFile *LLVMSymbolizer::lookUpBuildIDObject(const std::string &Path,
+ const ELFObjectFileBase *Obj,
+ const std::string &ArchName) {
+ auto BuildID = getBuildID(Obj);
+ if (!BuildID)
+ return nullptr;
+ if (BuildID->size() < 2)
+ return nullptr;
+ std::string DebugBinaryPath;
+ if (!findDebugBinary(*BuildID, DebugBinaryPath))
+ return nullptr;
+ auto DbgObjOrErr = getOrCreateObject(DebugBinaryPath, ArchName);
+ if (!DbgObjOrErr) {
+ consumeError(DbgObjOrErr.takeError());
+ return nullptr;
+ }
+ return DbgObjOrErr.get();
+}
+
+bool LLVMSymbolizer::findDebugBinary(const std::string &OrigPath,
+ const std::string &DebuglinkName,
+ uint32_t CRCHash, std::string &Result) {
+ SmallString<16> OrigDir(OrigPath);
+ llvm::sys::path::remove_filename(OrigDir);
+ SmallString<16> DebugPath = OrigDir;
+ // Try relative/path/to/original_binary/debuglink_name
+ llvm::sys::path::append(DebugPath, DebuglinkName);
+ if (checkFileCRC(DebugPath, CRCHash)) {
+ Result = std::string(DebugPath.str());
+ return true;
+ }
+ // Try relative/path/to/original_binary/.debug/debuglink_name
+ DebugPath = OrigDir;
+ llvm::sys::path::append(DebugPath, ".debug", DebuglinkName);
+ if (checkFileCRC(DebugPath, CRCHash)) {
+ Result = std::string(DebugPath.str());
+ return true;
+ }
+ // Make the path absolute so that lookups will go to
+ // "/usr/lib/debug/full/path/to/debug", not
+ // "/usr/lib/debug/to/debug"
+ llvm::sys::fs::make_absolute(OrigDir);
+ if (!Opts.FallbackDebugPath.empty()) {
+ // Try <FallbackDebugPath>/absolute/path/to/original_binary/debuglink_name
+ DebugPath = Opts.FallbackDebugPath;
+ } else {
+#if defined(__NetBSD__)
+ // Try /usr/libdata/debug/absolute/path/to/original_binary/debuglink_name
+ DebugPath = "/usr/libdata/debug";
+#else
+ // Try /usr/lib/debug/absolute/path/to/original_binary/debuglink_name
+ DebugPath = "/usr/lib/debug";
+#endif
+ }
+ llvm::sys::path::append(DebugPath, llvm::sys::path::relative_path(OrigDir),
+ DebuglinkName);
+ if (checkFileCRC(DebugPath, CRCHash)) {
+ Result = std::string(DebugPath.str());
+ return true;
+ }
+ return false;
+}
+
+bool LLVMSymbolizer::findDebugBinary(const ArrayRef<uint8_t> BuildID,
+ std::string &Result) {
+ Optional<std::string> Path;
+ Path = LocalDIFetcher(Opts.DebugFileDirectory).fetchBuildID(BuildID);
+ if (Path) {
+ Result = std::move(*Path);
+ return true;
+ }
+
+ // Try caller-provided debug info fetchers.
+ for (const std::unique_ptr<DIFetcher> &Fetcher : DIFetchers) {
+ Path = Fetcher->fetchBuildID(BuildID);
+ if (Path) {
+ Result = std::move(*Path);
+ return true;
+ }
+ }
+
+ return false;
+}
+
+Expected<LLVMSymbolizer::ObjectPair>
+LLVMSymbolizer::getOrCreateObjectPair(const std::string &Path,
+ const std::string &ArchName) {
+ auto I = ObjectPairForPathArch.find(std::make_pair(Path, ArchName));
+ if (I != ObjectPairForPathArch.end())
+ return I->second;
+
+ auto ObjOrErr = getOrCreateObject(Path, ArchName);
+ if (!ObjOrErr) {
+ ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName),
+ ObjectPair(nullptr, nullptr));
+ return ObjOrErr.takeError();
+ }
+
+ ObjectFile *Obj = ObjOrErr.get();
+ assert(Obj != nullptr);
+ ObjectFile *DbgObj = nullptr;
+
+ if (auto MachObj = dyn_cast<const MachOObjectFile>(Obj))
+ DbgObj = lookUpDsymFile(Path, MachObj, ArchName);
+ else if (auto ELFObj = dyn_cast<const ELFObjectFileBase>(Obj))
+ DbgObj = lookUpBuildIDObject(Path, ELFObj, ArchName);
+ if (!DbgObj)
+ DbgObj = lookUpDebuglinkObject(Path, Obj, ArchName);
+ if (!DbgObj)
+ DbgObj = Obj;
+ ObjectPair Res = std::make_pair(Obj, DbgObj);
+ ObjectPairForPathArch.emplace(std::make_pair(Path, ArchName), Res);
+ return Res;
+}
+
+Expected<ObjectFile *>
+LLVMSymbolizer::getOrCreateObject(const std::string &Path,
+ const std::string &ArchName) {
+ Binary *Bin;
+ auto Pair = BinaryForPath.emplace(Path, OwningBinary<Binary>());
+ if (!Pair.second) {
+ Bin = Pair.first->second.getBinary();
+ } else {
+ Expected<OwningBinary<Binary>> BinOrErr = createBinary(Path);
+ if (!BinOrErr)
+ return BinOrErr.takeError();
+ Pair.first->second = std::move(BinOrErr.get());
+ Bin = Pair.first->second.getBinary();
+ }
+
+ if (!Bin)
+ return static_cast<ObjectFile *>(nullptr);
+
+ if (MachOUniversalBinary *UB = dyn_cast_or_null<MachOUniversalBinary>(Bin)) {
+ auto I = ObjectForUBPathAndArch.find(std::make_pair(Path, ArchName));
+ if (I != ObjectForUBPathAndArch.end())
+ return I->second.get();
+
+ Expected<std::unique_ptr<ObjectFile>> ObjOrErr =
+ UB->getMachOObjectForArch(ArchName);
+ if (!ObjOrErr) {
+ ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName),
+ std::unique_ptr<ObjectFile>());
+ return ObjOrErr.takeError();
+ }
+ ObjectFile *Res = ObjOrErr->get();
+ ObjectForUBPathAndArch.emplace(std::make_pair(Path, ArchName),
+ std::move(ObjOrErr.get()));
+ return Res;
+ }
+ if (Bin->isObject()) {
+ return cast<ObjectFile>(Bin);
+ }
+ return errorCodeToError(object_error::arch_not_found);
+}
+
+Expected<SymbolizableModule *>
+LLVMSymbolizer::createModuleInfo(const ObjectFile *Obj,
+ std::unique_ptr<DIContext> Context,
+ StringRef ModuleName) {
+ auto InfoOrErr = SymbolizableObjectFile::create(Obj, std::move(Context),
+ Opts.UntagAddresses);
+ std::unique_ptr<SymbolizableModule> SymMod;
+ if (InfoOrErr)
+ SymMod = std::move(*InfoOrErr);
+ auto InsertResult = Modules.insert(
+ std::make_pair(std::string(ModuleName), std::move(SymMod)));
+ assert(InsertResult.second);
+ if (!InfoOrErr)
+ return InfoOrErr.takeError();
+ return InsertResult.first->second.get();
+}
+
+Expected<SymbolizableModule *>
+LLVMSymbolizer::getOrCreateModuleInfo(const std::string &ModuleName) {
+ auto I = Modules.find(ModuleName);
+ if (I != Modules.end())
+ return I->second.get();
+
+ std::string BinaryName = ModuleName;
+ std::string ArchName = Opts.DefaultArch;
+ size_t ColonPos = ModuleName.find_last_of(':');
+ // Verify that substring after colon form a valid arch name.
+ if (ColonPos != std::string::npos) {
+ std::string ArchStr = ModuleName.substr(ColonPos + 1);
+ if (Triple(ArchStr).getArch() != Triple::UnknownArch) {
+ BinaryName = ModuleName.substr(0, ColonPos);
+ ArchName = ArchStr;
+ }
+ }
+ auto ObjectsOrErr = getOrCreateObjectPair(BinaryName, ArchName);
+ if (!ObjectsOrErr) {
+ // Failed to find valid object file.
+ Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>());
+ return ObjectsOrErr.takeError();
+ }
+ ObjectPair Objects = ObjectsOrErr.get();
+
+ std::unique_ptr<DIContext> Context;
+ // If this is a COFF object containing PDB info, use a PDBContext to
+ // symbolize. Otherwise, use DWARF.
+ if (auto CoffObject = dyn_cast<COFFObjectFile>(Objects.first)) {
+ const codeview::DebugInfo *DebugInfo;
+ StringRef PDBFileName;
+ auto EC = CoffObject->getDebugPDBInfo(DebugInfo, PDBFileName);
+ if (!EC && DebugInfo != nullptr && !PDBFileName.empty()) {
+ using namespace pdb;
+ std::unique_ptr<IPDBSession> Session;
+
+ PDB_ReaderType ReaderType =
+ Opts.UseDIA ? PDB_ReaderType::DIA : PDB_ReaderType::Native;
+ if (auto Err = loadDataForEXE(ReaderType, Objects.first->getFileName(),
+ Session)) {
+ Modules.emplace(ModuleName, std::unique_ptr<SymbolizableModule>());
+ // Return along the PDB filename to provide more context
+ return createFileError(PDBFileName, std::move(Err));
+ }
+ Context.reset(new PDBContext(*CoffObject, std::move(Session)));
+ }
+ }
+ if (!Context)
+ Context = DWARFContext::create(
+ *Objects.second, DWARFContext::ProcessDebugRelocations::Process,
+ nullptr, Opts.DWPName);
+ return createModuleInfo(Objects.first, std::move(Context), ModuleName);
+}
+
+Expected<SymbolizableModule *>
+LLVMSymbolizer::getOrCreateModuleInfo(const ObjectFile &Obj) {
+ StringRef ObjName = Obj.getFileName();
+ auto I = Modules.find(ObjName);
+ if (I != Modules.end())
+ return I->second.get();
+
+ std::unique_ptr<DIContext> Context = DWARFContext::create(Obj);
+ // FIXME: handle COFF object with PDB info to use PDBContext
+ return createModuleInfo(&Obj, std::move(Context), ObjName);
+}
+
+namespace {
+
+// Undo these various manglings for Win32 extern "C" functions:
+// cdecl - _foo
+// stdcall - _foo@12
+// fastcall - @foo@12
+// vectorcall - foo@@12
+// These are all different linkage names for 'foo'.
+StringRef demanglePE32ExternCFunc(StringRef SymbolName) {
+ // Remove any '_' or '@' prefix.
+ char Front = SymbolName.empty() ? '\0' : SymbolName[0];
+ if (Front == '_' || Front == '@')
+ SymbolName = SymbolName.drop_front();
+
+ // Remove any '@[0-9]+' suffix.
+ if (Front != '?') {
+ size_t AtPos = SymbolName.rfind('@');
+ if (AtPos != StringRef::npos &&
+ all_of(drop_begin(SymbolName, AtPos + 1), isDigit))
+ SymbolName = SymbolName.substr(0, AtPos);
+ }
+
+ // Remove any ending '@' for vectorcall.
+ if (SymbolName.endswith("@"))
+ SymbolName = SymbolName.drop_back();
+
+ return SymbolName;
+}
+
+} // end anonymous namespace
+
+std::string
+LLVMSymbolizer::DemangleName(const std::string &Name,
+ const SymbolizableModule *DbiModuleDescriptor) {
+ std::string Result;
+ if (nonMicrosoftDemangle(Name.c_str(), Result))
+ return Result;
+
+ if (!Name.empty() && Name.front() == '?') {
+ // Only do MSVC C++ demangling on symbols starting with '?'.
+ int status = 0;
+ char *DemangledName = microsoftDemangle(
+ Name.c_str(), nullptr, nullptr, nullptr, &status,
+ MSDemangleFlags(MSDF_NoAccessSpecifier | MSDF_NoCallingConvention |
+ MSDF_NoMemberType | MSDF_NoReturnType));
+ if (status != 0)
+ return Name;
+ Result = DemangledName;
+ free(DemangledName);
+ return Result;
+ }
+
+ if (DbiModuleDescriptor && DbiModuleDescriptor->isWin32Module())
+ return std::string(demanglePE32ExternCFunc(Name));
+ return Name;
+}
+
+} // namespace symbolize
+} // namespace llvm
diff --git a/contrib/libs/llvm14/lib/DebugInfo/Symbolize/ya.make b/contrib/libs/llvm14/lib/DebugInfo/Symbolize/ya.make
new file mode 100644
index 0000000000..14f497a8e3
--- /dev/null
+++ b/contrib/libs/llvm14/lib/DebugInfo/Symbolize/ya.make
@@ -0,0 +1,33 @@
+# Generated by devtools/yamaker.
+
+LIBRARY()
+
+LICENSE(Apache-2.0 WITH LLVM-exception)
+
+LICENSE_TEXTS(.yandex_meta/licenses.list.txt)
+
+PEERDIR(
+ contrib/libs/llvm14
+ contrib/libs/llvm14/lib/DebugInfo/DWARF
+ contrib/libs/llvm14/lib/DebugInfo/PDB
+ contrib/libs/llvm14/lib/Demangle
+ contrib/libs/llvm14/lib/Object
+ contrib/libs/llvm14/lib/Support
+)
+
+ADDINCL(
+ contrib/libs/llvm14/lib/DebugInfo/Symbolize
+)
+
+NO_COMPILER_WARNINGS()
+
+NO_UTIL()
+
+SRCS(
+ DIFetcher.cpp
+ DIPrinter.cpp
+ SymbolizableObjectFile.cpp
+ Symbolize.cpp
+)
+
+END()