1 //===- CVRecord.h -----------------------------------------------*- C++ -*-===// 2 // 3 // Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. 4 // See https://llvm.org/LICENSE.txt for license information. 5 // SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception 6 // 7 //===----------------------------------------------------------------------===// 8 9 #ifndef LLVM_DEBUGINFO_CODEVIEW_CVRECORD_H 10 #define LLVM_DEBUGINFO_CODEVIEW_CVRECORD_H 11 12 #include "llvm/ADT/ArrayRef.h" 13 #include "llvm/ADT/Optional.h" 14 #include "llvm/DebugInfo/CodeView/CodeView.h" 15 #include "llvm/DebugInfo/CodeView/CodeViewError.h" 16 #include "llvm/DebugInfo/CodeView/RecordSerialization.h" 17 #include "llvm/Support/BinaryStreamReader.h" 18 #include "llvm/Support/BinaryStreamRef.h" 19 #include "llvm/Support/Endian.h" 20 #include "llvm/Support/Error.h" 21 #include <cstdint> 22 23 namespace llvm { 24 25 namespace codeview { 26 27 /// CVRecord is a fat pointer (base + size pair) to a symbol or type record. 28 /// Carrying the size separately instead of trusting the size stored in the 29 /// record prefix provides some extra safety and flexibility. 30 template <typename Kind> class CVRecord { 31 public: 32 CVRecord() = default; 33 34 CVRecord(ArrayRef<uint8_t> Data) : RecordData(Data) {} 35 36 CVRecord(const RecordPrefix *P, size_t Size) 37 : RecordData(reinterpret_cast<const uint8_t *>(P), Size) {} 38 39 bool valid() const { return kind() != Kind(0); } 40 41 uint32_t length() const { return RecordData.size(); } 42 43 Kind kind() const { 44 if (RecordData.size() < sizeof(RecordPrefix)) 45 return Kind(0); 46 return static_cast<Kind>(static_cast<uint16_t>( 47 reinterpret_cast<const RecordPrefix *>(RecordData.data())->RecordKind)); 48 } 49 50 ArrayRef<uint8_t> data() const { return RecordData; } 51 52 StringRef str_data() const { 53 return StringRef(reinterpret_cast<const char *>(RecordData.data()), 54 RecordData.size()); 55 } 56 57 ArrayRef<uint8_t> content() const { 58 return RecordData.drop_front(sizeof(RecordPrefix)); 59 } 60 61 ArrayRef<uint8_t> RecordData; 62 }; 63 64 // There are two kinds of codeview records: type and symbol records. 65 using CVType = CVRecord<TypeLeafKind>; 66 using CVSymbol = CVRecord<SymbolKind>; 67 68 template <typename Record, typename Func> 69 Error forEachCodeViewRecord(ArrayRef<uint8_t> StreamBuffer, Func F) { 70 while (!StreamBuffer.empty()) { 71 if (StreamBuffer.size() < sizeof(RecordPrefix)) 72 return make_error<CodeViewError>(cv_error_code::corrupt_record); 73 74 const RecordPrefix *Prefix = 75 reinterpret_cast<const RecordPrefix *>(StreamBuffer.data()); 76 77 size_t RealLen = Prefix->RecordLen + 2; 78 if (StreamBuffer.size() < RealLen) 79 return make_error<CodeViewError>(cv_error_code::corrupt_record); 80 81 ArrayRef<uint8_t> Data = StreamBuffer.take_front(RealLen); 82 StreamBuffer = StreamBuffer.drop_front(RealLen); 83 84 Record R(Data); 85 if (auto EC = F(R)) 86 return EC; 87 } 88 return Error::success(); 89 } 90 91 /// Read a complete record from a stream at a random offset. 92 template <typename Kind> 93 inline Expected<CVRecord<Kind>> readCVRecordFromStream(BinaryStreamRef Stream, 94 uint32_t Offset) { 95 const RecordPrefix *Prefix = nullptr; 96 BinaryStreamReader Reader(Stream); 97 Reader.setOffset(Offset); 98 99 if (auto EC = Reader.readObject(Prefix)) 100 return std::move(EC); 101 if (Prefix->RecordLen < 2) 102 return make_error<CodeViewError>(cv_error_code::corrupt_record); 103 104 Reader.setOffset(Offset); 105 ArrayRef<uint8_t> RawData; 106 if (auto EC = Reader.readBytes(RawData, Prefix->RecordLen + sizeof(uint16_t))) 107 return std::move(EC); 108 return codeview::CVRecord<Kind>(RawData); 109 } 110 111 } // end namespace codeview 112 113 template <typename Kind> 114 struct VarStreamArrayExtractor<codeview::CVRecord<Kind>> { 115 Error operator()(BinaryStreamRef Stream, uint32_t &Len, 116 codeview::CVRecord<Kind> &Item) { 117 auto ExpectedRec = codeview::readCVRecordFromStream<Kind>(Stream, 0); 118 if (!ExpectedRec) 119 return ExpectedRec.takeError(); 120 Item = *ExpectedRec; 121 Len = ExpectedRec->length(); 122 return Error::success(); 123 } 124 }; 125 126 namespace codeview { 127 using CVSymbolArray = VarStreamArray<CVSymbol>; 128 using CVTypeArray = VarStreamArray<CVType>; 129 using CVTypeRange = iterator_range<CVTypeArray::Iterator>; 130 } // namespace codeview 131 132 } // end namespace llvm 133 134 #endif // LLVM_DEBUGINFO_CODEVIEW_CVRECORD_H 135