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