BinaryStreamRef SymData) {
// FIXME: Improve error recovery by warning and skipping records when
// possible.
- CVSymbolArray Syms;
- BinaryStreamReader Reader(SymData);
- ExitOnErr(Reader.readArray(Syms, Reader.getLength()));
+ ArrayRef<uint8_t> SymsBuffer;
+ cantFail(SymData.readBytes(0, SymData.getLength(), SymsBuffer));
SmallVector<SymbolScope, 4> Scopes;
- for (CVSymbol Sym : Syms) {
- // Discover type index references in the record. Skip it if we don't know
- // where they are.
- SmallVector<TiReference, 32> TypeRefs;
- if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) {
- log("ignoring unknown symbol record with kind 0x" + utohexstr(Sym.kind()));
- continue;
- }
-
- // Copy the symbol record so we can mutate it.
- MutableArrayRef<uint8_t> NewData = copySymbolForPdb(Sym, Alloc);
-
- // Re-map all the type index references.
- MutableArrayRef<uint8_t> Contents =
- NewData.drop_front(sizeof(RecordPrefix));
- remapTypesInSymbolRecord(File, Sym.kind(), Contents, IndexMap, TypeRefs);
-
- // An object file may have S_xxx_ID symbols, but these get converted to
- // "real" symbols in a PDB.
- translateIdSymbols(NewData, IDTable);
- // If this record refers to an offset in the object file's string table,
- // add that item to the global PDB string table and re-write the index.
- recordStringTableReferences(Sym.kind(), Contents, StringTableRefs);
-
- SymbolKind NewKind = symbolKind(NewData);
-
- // Fill in "Parent" and "End" fields by maintaining a stack of scopes.
- CVSymbol NewSym(NewKind, NewData);
- if (symbolOpensScope(NewKind))
- scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(), NewSym);
- else if (symbolEndsScope(NewKind))
- scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File);
-
- // Add the symbol to the globals stream if necessary. Do this before adding
- // the symbol to the module since we may need to get the next symbol offset,
- // and writing to the module's symbol stream will update that offset.
- if (symbolGoesInGlobalsStream(NewSym))
- addGlobalSymbol(GsiBuilder, *File, NewSym);
+ auto EC = forEachCodeViewRecord<CVSymbol>(
+ SymsBuffer, [&](const CVSymbol &Sym) -> llvm::Error {
+ // Discover type index references in the record. Skip it if we don't
+ // know where they are.
+ SmallVector<TiReference, 32> TypeRefs;
+ if (!discoverTypeIndicesInSymbol(Sym, TypeRefs)) {
+ log("ignoring unknown symbol record with kind 0x" +
+ utohexstr(Sym.kind()));
+ return Error::success();
+ }
- // Add the symbol to the module.
- if (symbolGoesInModuleStream(NewSym))
- File->ModuleDBI->addSymbol(NewSym);
- }
+ // Copy the symbol record so we can mutate it.
+ MutableArrayRef<uint8_t> NewData = copySymbolForPdb(Sym, Alloc);
+
+ // Re-map all the type index references.
+ MutableArrayRef<uint8_t> Contents =
+ NewData.drop_front(sizeof(RecordPrefix));
+ remapTypesInSymbolRecord(File, Sym.kind(), Contents, IndexMap,
+ TypeRefs);
+
+ // An object file may have S_xxx_ID symbols, but these get converted to
+ // "real" symbols in a PDB.
+ translateIdSymbols(NewData, IDTable);
+
+ // If this record refers to an offset in the object file's string table,
+ // add that item to the global PDB string table and re-write the index.
+ recordStringTableReferences(Sym.kind(), Contents, StringTableRefs);
+
+ SymbolKind NewKind = symbolKind(NewData);
+
+ // Fill in "Parent" and "End" fields by maintaining a stack of scopes.
+ CVSymbol NewSym(NewKind, NewData);
+ if (symbolOpensScope(NewKind))
+ scopeStackOpen(Scopes, File->ModuleDBI->getNextSymbolOffset(),
+ NewSym);
+ else if (symbolEndsScope(NewKind))
+ scopeStackClose(Scopes, File->ModuleDBI->getNextSymbolOffset(), File);
+
+ // Add the symbol to the globals stream if necessary. Do this before
+ // adding the symbol to the module since we may need to get the next
+ // symbol offset, and writing to the module's symbol stream will update
+ // that offset.
+ if (symbolGoesInGlobalsStream(NewSym))
+ addGlobalSymbol(GsiBuilder, *File, NewSym);
+
+ // Add the symbol to the module.
+ if (symbolGoesInModuleStream(NewSym))
+ File->ModuleDBI->addSymbol(NewSym);
+ return Error::success();
+ });
+ cantFail(std::move(EC));
}
// Allocate memory for a .debug$S section and relocate it.
SmallVector<std::pair<uint32_t, TypeIndex>, 8> Mappings;
};
+template <typename Record, typename Func>
+Error forEachCodeViewRecord(ArrayRef<uint8_t> StreamBuffer, Func F) {
+ while (!StreamBuffer.empty()) {
+ if (StreamBuffer.size() < sizeof(RecordPrefix))
+ return make_error<CodeViewError>(cv_error_code::corrupt_record);
+
+ const RecordPrefix *Prefix =
+ reinterpret_cast<const RecordPrefix *>(StreamBuffer.data());
+
+ uint16_t RealLen = Prefix->RecordLen + 2;
+ if (StreamBuffer.size() < RealLen)
+ return make_error<CodeViewError>(cv_error_code::corrupt_record);
+
+ ArrayRef<uint8_t> Data = StreamBuffer.take_front(RealLen);
+ StreamBuffer = StreamBuffer.drop_front(RealLen);
+
+ Record R(static_cast<decltype(Record::Type)>((uint16_t)Prefix->RecordKind),
+ Data);
+ if (auto EC = F(R))
+ return EC;
+ }
+ return Error::success();
+}
+
/// Read a complete record from a stream at a random offset.
template <typename Kind>
inline Expected<CVRecord<Kind>> readCVRecordFromStream(BinaryStreamRef Stream,