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 | |
33 | CVRecord(ArrayRef<uint8_t> Data) : RecordData(Data) {} |
34 | |
35 | CVRecord(const RecordPrefix *P, size_t Size) |
36 | : RecordData(reinterpret_cast<const uint8_t *>(P), Size) {} |
37 | |
38 | bool valid() const { return kind() != Kind(0); } |
39 | |
40 | uint32_t length() const { return RecordData.size(); } |
41 | |
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 | |
49 | ArrayRef<uint8_t> data() const { return RecordData; } |
50 | |
51 | StringRef str_data() const { |
52 | return StringRef(reinterpret_cast<const char *>(RecordData.data()), |
53 | RecordData.size()); |
54 | } |
55 | |
56 | ArrayRef<uint8_t> content() const { |
57 | return RecordData.drop_front(N: 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> |
68 | Error forEachCodeViewRecord(ArrayRef<uint8_t> StreamBuffer, Func F) { |
69 | while (!StreamBuffer.empty()) { |
70 | if (StreamBuffer.size() < sizeof(RecordPrefix)) |
71 | return make_error<CodeViewError>(Args: 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>(Args: cv_error_code::corrupt_record); |
79 | |
80 | ArrayRef<uint8_t> Data = StreamBuffer.take_front(N: RealLen); |
81 | StreamBuffer = StreamBuffer.drop_front(N: 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> |
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(Dest&: Prefix)) |
99 | return std::move(EC); |
100 | if (Prefix->RecordLen < 2) |
101 | return make_error<CodeViewError>(Args: cv_error_code::corrupt_record); |
102 | |
103 | Reader.setOffset(Offset); |
104 | ArrayRef<uint8_t> RawData; |
105 | if (auto EC = Reader.readBytes(Buffer&: RawData, Size: 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 <codeview::CVRecord<Kind>> { |
114 | Error (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 | |