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