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.
getBytesAsCharacters(ArrayRef<uint8_t> LeafData)28 StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {
29   return StringRef(reinterpret_cast<const char *>(LeafData.data()),
30                    LeafData.size());
31 }
32 
getBytesAsCString(ArrayRef<uint8_t> LeafData)33 StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) {
34   return getBytesAsCharacters(LeafData).split('\0').first;
35 }
36 
consume(BinaryStreamReader & Reader,APSInt & Num)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 
consume(StringRef & Data,APSInt & Num)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.
consume_numeric(BinaryStreamReader & Reader,uint64_t & Num)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 
consume(BinaryStreamReader & Reader,uint32_t & Item)127 Error llvm::codeview::consume(BinaryStreamReader &Reader, uint32_t &Item) {
128   return Reader.readInteger(Item);
129 }
130 
consume(StringRef & Data,uint32_t & Item)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 
consume(BinaryStreamReader & Reader,int32_t & Item)140 Error llvm::codeview::consume(BinaryStreamReader &Reader, int32_t &Item) {
141   return Reader.readInteger(Item);
142 }
143 
consume(BinaryStreamReader & Reader,StringRef & Item)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 
readSymbolFromStream(BinaryStreamRef Stream,uint32_t Offset)152 Expected<CVSymbol> llvm::codeview::readSymbolFromStream(BinaryStreamRef Stream,
153                                                         uint32_t Offset) {
154   return readCVRecordFromStream<SymbolKind>(Stream, Offset);
155 }
156