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