Home | History | Annotate | Download | only in CodeView
      1 //===- RecordSerialization.h ------------------------------------*- C++ -*-===//
      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 #ifndef LLVM_DEBUGINFO_CODEVIEW_RECORDSERIALIZATION_H
     11 #define LLVM_DEBUGINFO_CODEVIEW_RECORDSERIALIZATION_H
     12 
     13 #include "llvm/ADT/APSInt.h"
     14 #include "llvm/ADT/ArrayRef.h"
     15 #include "llvm/ADT/StringRef.h"
     16 #include "llvm/Support/Endian.h"
     17 #include "llvm/DebugInfo/CodeView/CodeView.h"
     18 #include <cinttypes>
     19 #include <tuple>
     20 
     21 namespace llvm {
     22 namespace codeview {
     23 using llvm::support::little32_t;
     24 using llvm::support::ulittle16_t;
     25 using llvm::support::ulittle32_t;
     26 
     27 struct RecordPrefix {
     28   ulittle16_t RecordLen;  // Record length, starting from &Leaf.
     29   ulittle16_t RecordKind; // Record kind enum (SymRecordKind or TypeRecordKind)
     30 };
     31 
     32 /// Reinterpret a byte array as an array of characters. Does not interpret as
     33 /// a C string, as StringRef has several helpers (split) that make that easy.
     34 StringRef getBytesAsCharacters(ArrayRef<uint8_t> LeafData);
     35 StringRef getBytesAsCString(ArrayRef<uint8_t> LeafData);
     36 
     37 /// Consumes sizeof(T) bytes from the given byte sequence. Returns an error if
     38 /// there are not enough bytes remaining. Reinterprets the consumed bytes as a
     39 /// T object and points 'Res' at them.
     40 template <typename T, typename U>
     41 inline std::error_code consumeObject(U &Data, const T *&Res) {
     42   if (Data.size() < sizeof(*Res))
     43     return std::make_error_code(std::errc::illegal_byte_sequence);
     44   Res = reinterpret_cast<const T *>(Data.data());
     45   Data = Data.drop_front(sizeof(*Res));
     46   return std::error_code();
     47 }
     48 
     49 inline std::error_code consume(ArrayRef<uint8_t> &Data) {
     50   return std::error_code();
     51 }
     52 
     53 /// Decodes a numeric "leaf" value. These are integer literals encountered in
     54 /// the type stream. If the value is positive and less than LF_NUMERIC (1 <<
     55 /// 15), it is emitted directly in Data. Otherwise, it has a tag like LF_CHAR
     56 /// that indicates the bitwidth and sign of the numeric data.
     57 std::error_code consume(ArrayRef<uint8_t> &Data, APSInt &Num);
     58 std::error_code consume(StringRef &Data, APSInt &Num);
     59 
     60 /// Decodes a numeric leaf value that is known to be a particular type.
     61 std::error_code consume_numeric(ArrayRef<uint8_t> &Data, uint64_t &Value);
     62 
     63 /// Decodes signed and unsigned fixed-length integers.
     64 std::error_code consume(ArrayRef<uint8_t> &Data, uint32_t &Item);
     65 std::error_code consume(StringRef &Data, uint32_t &Item);
     66 std::error_code consume(ArrayRef<uint8_t> &Data, int32_t &Item);
     67 
     68 /// Decodes a null terminated string.
     69 std::error_code consume(ArrayRef<uint8_t> &Data, StringRef &Item);
     70 
     71 /// Decodes an arbitrary object whose layout matches that of the underlying
     72 /// byte sequence, and returns a pointer to the object.
     73 template <typename T>
     74 std::error_code consume(ArrayRef<uint8_t> &Data, T *&Item) {
     75   return consumeObject(Data, Item);
     76 }
     77 
     78 template <typename T, typename U> struct serialize_conditional_impl {
     79   serialize_conditional_impl(T &Item, U Func) : Item(Item), Func(Func) {}
     80 
     81   std::error_code deserialize(ArrayRef<uint8_t> &Data) const {
     82     if (!Func())
     83       return std::error_code();
     84     return consume(Data, Item);
     85   }
     86 
     87   T &Item;
     88   U Func;
     89 };
     90 
     91 template <typename T, typename U>
     92 serialize_conditional_impl<T, U> serialize_conditional(T &Item, U Func) {
     93   return serialize_conditional_impl<T, U>(Item, Func);
     94 }
     95 
     96 template <typename T, typename U> struct serialize_array_impl {
     97   serialize_array_impl(ArrayRef<T> &Item, U Func) : Item(Item), Func(Func) {}
     98 
     99   std::error_code deserialize(ArrayRef<uint8_t> &Data) const {
    100     uint32_t N = Func();
    101     if (N == 0)
    102       return std::error_code();
    103 
    104     uint32_t Size = sizeof(T) * N;
    105 
    106     if (Size / sizeof(T) != N)
    107       return std::make_error_code(std::errc::illegal_byte_sequence);
    108 
    109     if (Data.size() < Size)
    110       return std::make_error_code(std::errc::illegal_byte_sequence);
    111 
    112     Item = ArrayRef<T>(reinterpret_cast<const T *>(Data.data()), N);
    113     Data = Data.drop_front(Size);
    114     return std::error_code();
    115   }
    116 
    117   ArrayRef<T> &Item;
    118   U Func;
    119 };
    120 
    121 template <typename T> struct serialize_vector_tail_impl {
    122   serialize_vector_tail_impl(std::vector<T> &Item) : Item(Item) {}
    123 
    124   std::error_code deserialize(ArrayRef<uint8_t> &Data) const {
    125     T Field;
    126     // Stop when we run out of bytes or we hit record padding bytes.
    127     while (!Data.empty() && Data.front() < LF_PAD0) {
    128       if (auto EC = consume(Data, Field))
    129         return EC;
    130       Item.push_back(Field);
    131     }
    132     return std::error_code();
    133   }
    134 
    135   std::vector<T> &Item;
    136 };
    137 
    138 struct serialize_null_term_string_array_impl {
    139   serialize_null_term_string_array_impl(std::vector<StringRef> &Item)
    140       : Item(Item) {}
    141 
    142   std::error_code deserialize(ArrayRef<uint8_t> &Data) const {
    143     if (Data.empty())
    144       return std::make_error_code(std::errc::illegal_byte_sequence);
    145 
    146     StringRef Field;
    147     // Stop when we run out of bytes or we hit record padding bytes.
    148     while (Data.front() != 0) {
    149       if (auto EC = consume(Data, Field))
    150         return EC;
    151       Item.push_back(Field);
    152       if (Data.empty())
    153         return std::make_error_code(std::errc::illegal_byte_sequence);
    154     }
    155     Data = Data.drop_front(1);
    156     return std::error_code();
    157   }
    158 
    159   std::vector<StringRef> &Item;
    160 };
    161 
    162 template <typename T> struct serialize_arrayref_tail_impl {
    163   serialize_arrayref_tail_impl(ArrayRef<T> &Item) : Item(Item) {}
    164 
    165   std::error_code deserialize(ArrayRef<uint8_t> &Data) const {
    166     uint32_t Count = Data.size() / sizeof(T);
    167     Item = ArrayRef<T>(reinterpret_cast<const T *>(Data.begin()), Count);
    168     return std::error_code();
    169   }
    170 
    171   ArrayRef<T> &Item;
    172 };
    173 
    174 template <typename T> struct serialize_numeric_impl {
    175   serialize_numeric_impl(T &Item) : Item(Item) {}
    176 
    177   std::error_code deserialize(ArrayRef<uint8_t> &Data) const {
    178     return consume_numeric(Data, Item);
    179   }
    180 
    181   T &Item;
    182 };
    183 
    184 template <typename T, typename U>
    185 serialize_array_impl<T, U> serialize_array(ArrayRef<T> &Item, U Func) {
    186   return serialize_array_impl<T, U>(Item, Func);
    187 }
    188 
    189 inline serialize_null_term_string_array_impl
    190 serialize_null_term_string_array(std::vector<StringRef> &Item) {
    191   return serialize_null_term_string_array_impl(Item);
    192 }
    193 
    194 template <typename T>
    195 serialize_vector_tail_impl<T> serialize_array_tail(std::vector<T> &Item) {
    196   return serialize_vector_tail_impl<T>(Item);
    197 }
    198 
    199 template <typename T>
    200 serialize_arrayref_tail_impl<T> serialize_array_tail(ArrayRef<T> &Item) {
    201   return serialize_arrayref_tail_impl<T>(Item);
    202 }
    203 
    204 template <typename T> serialize_numeric_impl<T> serialize_numeric(T &Item) {
    205   return serialize_numeric_impl<T>(Item);
    206 }
    207 
    208 // This field is only present in the byte record if the condition is true.  The
    209 // condition is evaluated lazily, so it can depend on items that were
    210 // deserialized
    211 // earlier.
    212 #define CV_CONDITIONAL_FIELD(I, C)                                             \
    213   serialize_conditional(I, [&]() { return !!(C); })
    214 
    215 // This is an array of N items, where N is evaluated lazily, so it can refer
    216 // to a field deserialized earlier.
    217 #define CV_ARRAY_FIELD_N(I, N) serialize_array(I, [&]() { return N; })
    218 
    219 // This is an array that exhausts the remainder of the input buffer.
    220 #define CV_ARRAY_FIELD_TAIL(I) serialize_array_tail(I)
    221 
    222 // This is an array that consumes null terminated strings until a double null
    223 // is encountered.
    224 #define CV_STRING_ARRAY_NULL_TERM(I) serialize_null_term_string_array(I)
    225 
    226 #define CV_NUMERIC_FIELD(I) serialize_numeric(I)
    227 
    228 template <typename T, typename U>
    229 std::error_code consume(ArrayRef<uint8_t> &Data,
    230                         const serialize_conditional_impl<T, U> &Item) {
    231   return Item.deserialize(Data);
    232 }
    233 
    234 template <typename T, typename U>
    235 std::error_code consume(ArrayRef<uint8_t> &Data,
    236                         const serialize_array_impl<T, U> &Item) {
    237   return Item.deserialize(Data);
    238 }
    239 
    240 inline std::error_code
    241 consume(ArrayRef<uint8_t> &Data,
    242         const serialize_null_term_string_array_impl &Item) {
    243   return Item.deserialize(Data);
    244 }
    245 
    246 template <typename T>
    247 std::error_code consume(ArrayRef<uint8_t> &Data,
    248                         const serialize_vector_tail_impl<T> &Item) {
    249   return Item.deserialize(Data);
    250 }
    251 
    252 template <typename T>
    253 std::error_code consume(ArrayRef<uint8_t> &Data,
    254                         const serialize_arrayref_tail_impl<T> &Item) {
    255   return Item.deserialize(Data);
    256 }
    257 
    258 template <typename T>
    259 std::error_code consume(ArrayRef<uint8_t> &Data,
    260                         const serialize_numeric_impl<T> &Item) {
    261   return Item.deserialize(Data);
    262 }
    263 
    264 template <typename T, typename U, typename... Args>
    265 std::error_code consume(ArrayRef<uint8_t> &Data, T &&X, U &&Y,
    266                         Args &&... Rest) {
    267   if (auto EC = consume(Data, X))
    268     return EC;
    269   return consume(Data, Y, std::forward<Args>(Rest)...);
    270 }
    271 
    272 #define CV_DESERIALIZE(...)                                                    \
    273   if (auto EC = consume(__VA_ARGS__))                                          \
    274     return EC;
    275 }
    276 }
    277 
    278 #endif
    279