138cc8b3fSZachary Turner //===-- RecordSerialization.cpp -------------------------------------------===//
238cc8b3fSZachary Turner //
338cc8b3fSZachary Turner //                     The LLVM Compiler Infrastructure
438cc8b3fSZachary Turner //
538cc8b3fSZachary Turner // This file is distributed under the University of Illinois Open Source
638cc8b3fSZachary Turner // License. See LICENSE.TXT for details.
738cc8b3fSZachary Turner //
838cc8b3fSZachary Turner //===----------------------------------------------------------------------===//
938cc8b3fSZachary Turner //
1038cc8b3fSZachary Turner // Utilities for serializing and deserializing CodeView records.
1138cc8b3fSZachary Turner //
1238cc8b3fSZachary Turner //===----------------------------------------------------------------------===//
1338cc8b3fSZachary Turner 
1438cc8b3fSZachary Turner #include "llvm/DebugInfo/CodeView/RecordSerialization.h"
1538cc8b3fSZachary Turner #include "llvm/ADT/APInt.h"
1638cc8b3fSZachary Turner #include "llvm/ADT/APSInt.h"
1738cc8b3fSZachary Turner #include "llvm/DebugInfo/CodeView/TypeRecord.h"
1838cc8b3fSZachary Turner 
1938cc8b3fSZachary Turner using namespace llvm;
2038cc8b3fSZachary Turner using namespace llvm::codeview;
2138cc8b3fSZachary Turner using namespace llvm::support;
2238cc8b3fSZachary Turner 
2338cc8b3fSZachary Turner /// Reinterpret a byte array as an array of characters. Does not interpret as
2438cc8b3fSZachary Turner /// a C string, as StringRef has several helpers (split) that make that easy.
2538cc8b3fSZachary Turner StringRef llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {
2638cc8b3fSZachary Turner   return StringRef(reinterpret_cast<const char *>(LeafData.data()),
2738cc8b3fSZachary Turner                    LeafData.size());
2838cc8b3fSZachary Turner }
2938cc8b3fSZachary Turner 
3038cc8b3fSZachary Turner StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) {
3138cc8b3fSZachary Turner   return getBytesAsCharacters(LeafData).split('\0').first;
3238cc8b3fSZachary Turner }
3338cc8b3fSZachary Turner 
3438cc8b3fSZachary Turner std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data, APSInt &Num) {
3538cc8b3fSZachary Turner   // Used to avoid overload ambiguity on APInt construtor.
3638cc8b3fSZachary Turner   bool FalseVal = false;
3738cc8b3fSZachary Turner   if (Data.size() < 2)
3838cc8b3fSZachary Turner     return std::make_error_code(std::errc::illegal_byte_sequence);
3938cc8b3fSZachary Turner   uint16_t Short = *reinterpret_cast<const ulittle16_t *>(Data.data());
4038cc8b3fSZachary Turner   Data = Data.drop_front(2);
4138cc8b3fSZachary Turner   if (Short < LF_NUMERIC) {
4238cc8b3fSZachary Turner     Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false),
4338cc8b3fSZachary Turner                  /*isUnsigned=*/true);
4438cc8b3fSZachary Turner     return std::error_code();
4538cc8b3fSZachary Turner   }
4638cc8b3fSZachary Turner   switch (Short) {
4738cc8b3fSZachary Turner   case LF_CHAR:
48*6c13db40SDavid Majnemer     if (Data.size() < 1)
49*6c13db40SDavid Majnemer       return std::make_error_code(std::errc::illegal_byte_sequence);
5038cc8b3fSZachary Turner     Num = APSInt(APInt(/*numBits=*/8,
5138cc8b3fSZachary Turner                        *reinterpret_cast<const int8_t *>(Data.data()),
5238cc8b3fSZachary Turner                        /*isSigned=*/true),
5338cc8b3fSZachary Turner                  /*isUnsigned=*/false);
5438cc8b3fSZachary Turner     Data = Data.drop_front(1);
5538cc8b3fSZachary Turner     return std::error_code();
5638cc8b3fSZachary Turner   case LF_SHORT:
57*6c13db40SDavid Majnemer     if (Data.size() < 2)
58*6c13db40SDavid Majnemer       return std::make_error_code(std::errc::illegal_byte_sequence);
5938cc8b3fSZachary Turner     Num = APSInt(APInt(/*numBits=*/16,
6038cc8b3fSZachary Turner                        *reinterpret_cast<const little16_t *>(Data.data()),
6138cc8b3fSZachary Turner                        /*isSigned=*/true),
6238cc8b3fSZachary Turner                  /*isUnsigned=*/false);
6338cc8b3fSZachary Turner     Data = Data.drop_front(2);
6438cc8b3fSZachary Turner     return std::error_code();
6538cc8b3fSZachary Turner   case LF_USHORT:
66*6c13db40SDavid Majnemer     if (Data.size() < 2)
67*6c13db40SDavid Majnemer       return std::make_error_code(std::errc::illegal_byte_sequence);
6838cc8b3fSZachary Turner     Num = APSInt(APInt(/*numBits=*/16,
6938cc8b3fSZachary Turner                        *reinterpret_cast<const ulittle16_t *>(Data.data()),
7038cc8b3fSZachary Turner                        /*isSigned=*/false),
7138cc8b3fSZachary Turner                  /*isUnsigned=*/true);
7238cc8b3fSZachary Turner     Data = Data.drop_front(2);
7338cc8b3fSZachary Turner     return std::error_code();
7438cc8b3fSZachary Turner   case LF_LONG:
75*6c13db40SDavid Majnemer     if (Data.size() < 4)
76*6c13db40SDavid Majnemer       return std::make_error_code(std::errc::illegal_byte_sequence);
7738cc8b3fSZachary Turner     Num = APSInt(APInt(/*numBits=*/32,
7838cc8b3fSZachary Turner                        *reinterpret_cast<const little32_t *>(Data.data()),
7938cc8b3fSZachary Turner                        /*isSigned=*/true),
8038cc8b3fSZachary Turner                  /*isUnsigned=*/false);
8138cc8b3fSZachary Turner     Data = Data.drop_front(4);
8238cc8b3fSZachary Turner     return std::error_code();
8338cc8b3fSZachary Turner   case LF_ULONG:
84*6c13db40SDavid Majnemer     if (Data.size() < 4)
85*6c13db40SDavid Majnemer       return std::make_error_code(std::errc::illegal_byte_sequence);
8638cc8b3fSZachary Turner     Num = APSInt(APInt(/*numBits=*/32,
8738cc8b3fSZachary Turner                        *reinterpret_cast<const ulittle32_t *>(Data.data()),
8838cc8b3fSZachary Turner                        /*isSigned=*/FalseVal),
8938cc8b3fSZachary Turner                  /*isUnsigned=*/true);
9038cc8b3fSZachary Turner     Data = Data.drop_front(4);
9138cc8b3fSZachary Turner     return std::error_code();
9238cc8b3fSZachary Turner   case LF_QUADWORD:
93*6c13db40SDavid Majnemer     if (Data.size() < 8)
94*6c13db40SDavid Majnemer       return std::make_error_code(std::errc::illegal_byte_sequence);
9538cc8b3fSZachary Turner     Num = APSInt(APInt(/*numBits=*/64,
9638cc8b3fSZachary Turner                        *reinterpret_cast<const little64_t *>(Data.data()),
9738cc8b3fSZachary Turner                        /*isSigned=*/true),
9838cc8b3fSZachary Turner                  /*isUnsigned=*/false);
9938cc8b3fSZachary Turner     Data = Data.drop_front(8);
10038cc8b3fSZachary Turner     return std::error_code();
10138cc8b3fSZachary Turner   case LF_UQUADWORD:
102*6c13db40SDavid Majnemer     if (Data.size() < 8)
103*6c13db40SDavid Majnemer       return std::make_error_code(std::errc::illegal_byte_sequence);
10438cc8b3fSZachary Turner     Num = APSInt(APInt(/*numBits=*/64,
10538cc8b3fSZachary Turner                        *reinterpret_cast<const ulittle64_t *>(Data.data()),
10638cc8b3fSZachary Turner                        /*isSigned=*/false),
10738cc8b3fSZachary Turner                  /*isUnsigned=*/true);
10838cc8b3fSZachary Turner     Data = Data.drop_front(8);
10938cc8b3fSZachary Turner     return std::error_code();
11038cc8b3fSZachary Turner   }
11138cc8b3fSZachary Turner   return std::make_error_code(std::errc::illegal_byte_sequence);
11238cc8b3fSZachary Turner }
11338cc8b3fSZachary Turner 
11438cc8b3fSZachary Turner std::error_code llvm::codeview::consume(StringRef &Data, APSInt &Num) {
11538cc8b3fSZachary Turner   ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
11638cc8b3fSZachary Turner   auto EC = consume(Bytes, Num);
11738cc8b3fSZachary Turner   Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
11838cc8b3fSZachary Turner   return EC;
11938cc8b3fSZachary Turner }
12038cc8b3fSZachary Turner 
12138cc8b3fSZachary Turner /// Decode a numeric leaf value that is known to be a uint64_t.
12238cc8b3fSZachary Turner std::error_code llvm::codeview::consume_numeric(ArrayRef<uint8_t> &Data,
12338cc8b3fSZachary Turner                                                 uint64_t &Num) {
12438cc8b3fSZachary Turner   APSInt N;
12538cc8b3fSZachary Turner   if (auto EC = consume(Data, N))
12638cc8b3fSZachary Turner     return EC;
12738cc8b3fSZachary Turner   if (N.isSigned() || !N.isIntN(64))
12838cc8b3fSZachary Turner     return std::make_error_code(std::errc::illegal_byte_sequence);
12938cc8b3fSZachary Turner   Num = N.getLimitedValue();
13038cc8b3fSZachary Turner   return std::error_code();
13138cc8b3fSZachary Turner }
13238cc8b3fSZachary Turner 
13338cc8b3fSZachary Turner std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
13438cc8b3fSZachary Turner                                         uint32_t &Item) {
13538cc8b3fSZachary Turner   const support::ulittle32_t *IntPtr;
13638cc8b3fSZachary Turner   if (auto EC = consumeObject(Data, IntPtr))
13738cc8b3fSZachary Turner     return EC;
13838cc8b3fSZachary Turner   Item = *IntPtr;
13938cc8b3fSZachary Turner   return std::error_code();
14038cc8b3fSZachary Turner }
14138cc8b3fSZachary Turner 
14238cc8b3fSZachary Turner std::error_code llvm::codeview::consume(StringRef &Data, uint32_t &Item) {
14338cc8b3fSZachary Turner   ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
14438cc8b3fSZachary Turner   auto EC = consume(Bytes, Item);
14538cc8b3fSZachary Turner   Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
14638cc8b3fSZachary Turner   return EC;
14738cc8b3fSZachary Turner }
14838cc8b3fSZachary Turner 
14938cc8b3fSZachary Turner std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
15038cc8b3fSZachary Turner                                         int32_t &Item) {
15138cc8b3fSZachary Turner   const support::little32_t *IntPtr;
15238cc8b3fSZachary Turner   if (auto EC = consumeObject(Data, IntPtr))
15338cc8b3fSZachary Turner     return EC;
15438cc8b3fSZachary Turner   Item = *IntPtr;
15538cc8b3fSZachary Turner   return std::error_code();
15638cc8b3fSZachary Turner }
15738cc8b3fSZachary Turner 
15838cc8b3fSZachary Turner std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
15938cc8b3fSZachary Turner                                         StringRef &Item) {
16038cc8b3fSZachary Turner   if (Data.empty())
16138cc8b3fSZachary Turner     return std::make_error_code(std::errc::illegal_byte_sequence);
16238cc8b3fSZachary Turner 
16338cc8b3fSZachary Turner   StringRef Rest;
16438cc8b3fSZachary Turner   std::tie(Item, Rest) = getBytesAsCharacters(Data).split('\0');
16538cc8b3fSZachary Turner   // We expect this to be null terminated.  If it was not, it is an error.
16638cc8b3fSZachary Turner   if (Data.size() == Item.size())
16738cc8b3fSZachary Turner     return std::make_error_code(std::errc::illegal_byte_sequence);
16838cc8b3fSZachary Turner 
16938cc8b3fSZachary Turner   Data = ArrayRef<uint8_t>(Rest.bytes_begin(), Rest.bytes_end());
17038cc8b3fSZachary Turner   return std::error_code();
17138cc8b3fSZachary Turner }
172