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(); }
Expected<std::shared_ptr<YAMLFrameDataSubsection>> YAMLFrameDataSubsection::fromCodeViewSubsection( const DebugStringTableSubsectionRef &Strings, const DebugFrameDataSubsectionRef &Frames) { auto Result = std::make_shared<YAMLFrameDataSubsection>(); for (const auto &F : Frames) { YAMLFrameData YF; YF.CodeSize = F.CodeSize; YF.Flags = F.Flags; YF.LocalSize = F.LocalSize; YF.MaxStackSize = F.MaxStackSize; YF.ParamsSize = F.ParamsSize; YF.PrologSize = F.PrologSize; YF.RvaStart = F.RvaStart; YF.SavedRegsSize = F.SavedRegsSize; auto ES = Strings.getString(F.FrameFunc); if (!ES) return joinErrors( make_error<CodeViewError>( cv_error_code::no_records, "Could not find string for string id while mapping FrameData!"), ES.takeError()); YF.FrameFunc = *ES; Result->Frames.push_back(YF); } return Result; }
static Expected<StringRef> getFileName(const DebugStringTableSubsectionRef &Strings, const DebugChecksumsSubsectionRef &Checksums, uint32_t FileID) { auto Iter = Checksums.getArray().at(FileID); if (Iter == Checksums.getArray().end()) return make_error<CodeViewError>(cv_error_code::no_records); uint32_t Offset = Iter->FileNameOffset; return Strings.getString(Offset); }
static Expected<SourceFileChecksumEntry> convertOneChecksum(const DebugStringTableSubsectionRef &Strings, const FileChecksumEntry &CS) { auto ExpectedString = Strings.getString(CS.FileNameOffset); if (!ExpectedString) return ExpectedString.takeError(); SourceFileChecksumEntry Result; Result.ChecksumBytes.Bytes = CS.Checksum; Result.Kind = CS.Kind; Result.FileName = *ExpectedString; return Result; }
Expected<std::shared_ptr<YAMLCrossModuleImportsSubsection>> YAMLCrossModuleImportsSubsection::fromCodeViewSubsection( const DebugStringTableSubsectionRef &Strings, const DebugCrossModuleImportsSubsectionRef &Imports) { auto Result = std::make_shared<YAMLCrossModuleImportsSubsection>(); for (const auto &CMI : Imports) { YAMLCrossModuleImport YCMI; auto ExpectedStr = Strings.getString(CMI.Header->ModuleNameOffset); if (!ExpectedStr) return ExpectedStr.takeError(); YCMI.ModuleName = *ExpectedStr; YCMI.ImportIds.assign(CMI.Imports.begin(), CMI.Imports.end()); Result->Imports.push_back(YCMI); } return Result; }
Expected<std::shared_ptr<YAMLStringTableSubsection>> YAMLStringTableSubsection::fromCodeViewSubsection( const DebugStringTableSubsectionRef &Strings) { auto Result = std::make_shared<YAMLStringTableSubsection>(); BinaryStreamReader Reader(Strings.getBuffer()); StringRef S; // First item is a single null string, skip it. if (auto EC = Reader.readCString(S)) return std::move(EC); assert(S.empty()); while (Reader.bytesRemaining() > 0) { if (auto EC = Reader.readCString(S)) return std::move(EC); Result->Strings.push_back(S); } return Result; }
// Add all object files to the PDB. Merge .debug$T sections into IpiData and // TpiData. static void addObjectsToPDB(BumpPtrAllocator &Alloc, SymbolTable *Symtab, pdb::PDBFileBuilder &Builder, TypeTableBuilder &TypeTable, TypeTableBuilder &IDTable) { // Follow type servers. If the same type server is encountered more than // once for this instance of `PDBTypeServerHandler` (for example if many // object files reference the same TypeServer), the types from the // TypeServer will only be visited once. pdb::PDBTypeServerHandler Handler; // PDBs use a single global string table for filenames in the file checksum // table. auto PDBStrTab = std::make_shared<DebugStringTableSubsection>(); // Visit all .debug$T sections to add them to Builder. for (ObjectFile *File : Symtab->ObjectFiles) { // Add a module descriptor for every object file. We need to put an absolute // path to the object into the PDB. If this is a plain object, we make its // path absolute. If it's an object in an archive, we make the archive path // absolute. bool InArchive = !File->ParentName.empty(); SmallString<128> Path = InArchive ? File->ParentName : File->getName(); sys::fs::make_absolute(Path); StringRef Name = InArchive ? File->getName() : StringRef(Path); File->ModuleDBI = &ExitOnErr(Builder.getDbiBuilder().addModuleInfo(Name)); File->ModuleDBI->setObjFileName(Path); // Before we can process symbol substreams from .debug$S, we need to process // type information, file checksums, and the string table. Add type info to // the PDB first, so that we can get the map from object file type and item // indices to PDB type and item indices. SmallVector<TypeIndex, 128> TypeIndexMap; mergeDebugT(File, IDTable, TypeTable, TypeIndexMap, Handler); // Now do all line info. for (SectionChunk *DebugChunk : File->getDebugChunks()) { if (!DebugChunk->isLive() || DebugChunk->getSectionName() != ".debug$S") continue; ArrayRef<uint8_t> RelocatedDebugContents = relocateDebugChunk(Alloc, DebugChunk); if (RelocatedDebugContents.empty()) continue; DebugSubsectionArray Subsections; BinaryStreamReader Reader(RelocatedDebugContents, support::little); ExitOnErr(Reader.readArray(Subsections, RelocatedDebugContents.size())); DebugStringTableSubsectionRef CVStrTab; DebugChecksumsSubsectionRef Checksums; for (const DebugSubsectionRecord &SS : Subsections) { switch (SS.kind()) { case DebugSubsectionKind::StringTable: ExitOnErr(CVStrTab.initialize(SS.getRecordData())); break; case DebugSubsectionKind::FileChecksums: ExitOnErr(Checksums.initialize(SS.getRecordData())); break; case DebugSubsectionKind::Lines: // We can add the relocated line table directly to the PDB without // modification because the file checksum offsets will stay the same. File->ModuleDBI->addDebugSubsection(SS); break; case DebugSubsectionKind::Symbols: mergeSymbolRecords(Alloc, File, TypeIndexMap, SS.getRecordData()); break; default: // FIXME: Process the rest of the subsections. break; } } if (Checksums.valid()) { // Make a new file checksum table that refers to offsets in the PDB-wide // string table. Generally the string table subsection appears after the // checksum table, so we have to do this after looping over all the // subsections. if (!CVStrTab.valid()) fatal(".debug$S sections must have both a string table subsection " "and a checksum subsection table or neither"); auto NewChecksums = make_unique<DebugChecksumsSubsection>(*PDBStrTab); for (FileChecksumEntry &FC : Checksums) { StringRef FileName = ExitOnErr(CVStrTab.getString(FC.FileNameOffset)); ExitOnErr(Builder.getDbiBuilder().addModuleSourceFile( *File->ModuleDBI, FileName)); NewChecksums->addChecksum(FileName, FC.Kind, FC.Checksum); } File->ModuleDBI->addDebugSubsection(std::move(NewChecksums)); } } } Builder.getStringTableBuilder().setStrings(*PDBStrTab); // Construct TPI stream contents. addTypeInfo(Builder.getTpiBuilder(), TypeTable); // Construct IPI stream contents. addTypeInfo(Builder.getIpiBuilder(), IDTable); }
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); } } }