1 //===-- RecordSerialization.cpp -------------------------------------------===// 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 // Utilities for serializing and deserializing CodeView records. 10 // 11 //===----------------------------------------------------------------------===// 12 13 #include "llvm/DebugInfo/CodeView/RecordSerialization.h" 14 #include "llvm/ADT/APInt.h" 15 #include "llvm/ADT/APSInt.h" 16 #include "llvm/DebugInfo/CodeView/CVRecord.h" 17 #include "llvm/DebugInfo/CodeView/CodeViewError.h" 18 #include "llvm/DebugInfo/CodeView/SymbolRecord.h" 19 #include "llvm/Support/BinaryByteStream.h" 20 21 using namespace llvm; 22 using namespace llvm::codeview; 23 using namespace llvm::support; 24 25 /// Reinterpret a byte array as an array of characters. Does not interpret as 26 /// a C string, as StringRef has several helpers (split) that make that easy. 27 StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) { 28 return StringRef(reinterpret_cast<const char *>(LeafData.data()), 29 LeafData.size()); 30 } 31 32 StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) { 33 return getBytesAsCharacters(LeafData).split('\0').first; 34 } 35 36 Error llvm::codeview::consume(BinaryStreamReader &Reader, APSInt &Num) { 37 // Used to avoid overload ambiguity on APInt constructor. 38 bool FalseVal = false; 39 uint16_t Short; 40 if (auto EC = Reader.readInteger(Short)) 41 return EC; 42 43 if (Short < LF_NUMERIC) { 44 Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false), 45 /*isUnsigned=*/true); 46 return Error::success(); 47 } 48 49 switch (Short) { 50 case LF_CHAR: { 51 int8_t N; 52 if (auto EC = Reader.readInteger(N)) 53 return EC; 54 Num = APSInt(APInt(8, N, true), false); 55 return Error::success(); 56 } 57 case LF_SHORT: { 58 int16_t N; 59 if (auto EC = Reader.readInteger(N)) 60 return EC; 61 Num = APSInt(APInt(16, N, true), false); 62 return Error::success(); 63 } 64 case LF_USHORT: { 65 uint16_t N; 66 if (auto EC = Reader.readInteger(N)) 67 return EC; 68 Num = APSInt(APInt(16, N, false), true); 69 return Error::success(); 70 } 71 case LF_LONG: { 72 int32_t N; 73 if (auto EC = Reader.readInteger(N)) 74 return EC; 75 Num = APSInt(APInt(32, N, true), false); 76 return Error::success(); 77 } 78 case LF_ULONG: { 79 uint32_t N; 80 if (auto EC = Reader.readInteger(N)) 81 return EC; 82 Num = APSInt(APInt(32, N, FalseVal), true); 83 return Error::success(); 84 } 85 case LF_QUADWORD: { 86 int64_t N; 87 if (auto EC = Reader.readInteger(N)) 88 return EC; 89 Num = APSInt(APInt(64, N, true), false); 90 return Error::success(); 91 } 92 case LF_UQUADWORD: { 93 uint64_t N; 94 if (auto EC = Reader.readInteger(N)) 95 return EC; 96 Num = APSInt(APInt(64, N, false), true); 97 return Error::success(); 98 } 99 } 100 return make_error<CodeViewError>(cv_error_code::corrupt_record, 101 "Buffer contains invalid APSInt type"); 102 } 103 104 Error llvm::codeview::consume(StringRef &Data, APSInt &Num) { 105 ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end()); 106 BinaryByteStream S(Bytes, llvm::endianness::little); 107 BinaryStreamReader SR(S); 108 auto EC = consume(SR, Num); 109 Data = Data.take_back(SR.bytesRemaining()); 110 return EC; 111 } 112 113 /// Decode a numeric leaf value that is known to be a uint64_t. 114 Error llvm::codeview::consume_numeric(BinaryStreamReader &Reader, 115 uint64_t &Num) { 116 APSInt N; 117 if (auto EC = consume(Reader, N)) 118 return EC; 119 if (N.isSigned() || !N.isIntN(64)) 120 return make_error<CodeViewError>(cv_error_code::corrupt_record, 121 "Data is not a numeric value!"); 122 Num = N.getLimitedValue(); 123 return Error::success(); 124 } 125 126 Error llvm::codeview::consume(BinaryStreamReader &Reader, uint32_t &Item) { 127 return Reader.readInteger(Item); 128 } 129 130 Error llvm::codeview::consume(StringRef &Data, uint32_t &Item) { 131 ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end()); 132 BinaryByteStream S(Bytes, llvm::endianness::little); 133 BinaryStreamReader SR(S); 134 auto EC = consume(SR, Item); 135 Data = Data.take_back(SR.bytesRemaining()); 136 return EC; 137 } 138 139 Error llvm::codeview::consume(BinaryStreamReader &Reader, int32_t &Item) { 140 return Reader.readInteger(Item); 141 } 142 143 Error llvm::codeview::consume(BinaryStreamReader &Reader, StringRef &Item) { 144 if (Reader.empty()) 145 return make_error<CodeViewError>(cv_error_code::corrupt_record, 146 "Null terminated string buffer is empty!"); 147 148 return Reader.readCString(Item); 149 } 150 151 Expected<CVSymbol> llvm::codeview::readSymbolFromStream(BinaryStreamRef Stream, 152 uint32_t Offset) { 153 return readCVRecordFromStream<SymbolKind>(Stream, Offset); 154 } 155