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