Files
archived-llvm/include/llvm/DebugInfo/CodeView/RecordSerialization.h
Zachary Turner a459ab93aa [CodeView] Refactor serialization to use StreamInterface.
This was all using ArrayRef<>s before which presents a problem
when you want to serialize to or deserialize from an actual
PDB stream.  An ArrayRef<> is really just a special case of
what can be handled with StreamInterface though (e.g. by using
a ByteStream), so changing this to use StreamInterface allows
us to plug in a PDB stream and get all the record serialization
and deserialization for free on a MappedBlockStream.

Subsequent patches will try to remove TypeTableBuilder and
TypeRecordBuilder in favor of class that operate on
Streams as well, which should allow us to completely merge
the reading and writing codepaths for both types and symbols.

Differential Revision: https://reviews.llvm.org/D25831

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@284762 91177308-0d34-0410-b5e6-96231b3b80d8
2016-10-20 18:31:19 +00:00

252 lines
7.9 KiB
C++

//===- RecordSerialization.h ------------------------------------*- C++ -*-===//
//
// The LLVM Compiler Infrastructure
//
// This file is distributed under the University of Illinois Open Source
// License. See LICENSE.TXT for details.
//
//===----------------------------------------------------------------------===//
#ifndef LLVM_DEBUGINFO_CODEVIEW_RECORDSERIALIZATION_H
#define LLVM_DEBUGINFO_CODEVIEW_RECORDSERIALIZATION_H
#include "llvm/ADT/APSInt.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/CodeViewError.h"
#include "llvm/DebugInfo/MSF/StreamReader.h"
#include "llvm/Support/Endian.h"
#include "llvm/Support/Error.h"
#include <cinttypes>
#include <tuple>
namespace llvm {
namespace codeview {
using llvm::support::little32_t;
using llvm::support::ulittle16_t;
using llvm::support::ulittle32_t;
/// Limit on the size of all codeview symbol and type records, including the
/// RecordPrefix. MSVC does not emit any records larger than this.
enum : unsigned { MaxRecordLength = 0xFF00 };
struct RecordPrefix {
ulittle16_t RecordLen; // Record length, starting from &Leaf.
ulittle16_t RecordKind; // Record kind enum (SymRecordKind or TypeRecordKind)
};
/// Reinterpret a byte array as an array of characters. Does not interpret as
/// a C string, as StringRef has several helpers (split) that make that easy.
StringRef getBytesAsCharacters(ArrayRef<uint8_t> LeafData);
StringRef getBytesAsCString(ArrayRef<uint8_t> LeafData);
inline Error consume(msf::StreamReader &Reader) { return Error::success(); }
/// Decodes a numeric "leaf" value. These are integer literals encountered in
/// the type stream. If the value is positive and less than LF_NUMERIC (1 <<
/// 15), it is emitted directly in Data. Otherwise, it has a tag like LF_CHAR
/// that indicates the bitwidth and sign of the numeric data.
Error consume(msf::StreamReader &Reader, APSInt &Num);
/// Decodes a numeric leaf value that is known to be a particular type.
Error consume_numeric(msf::StreamReader &Reader, uint64_t &Value);
/// Decodes signed and unsigned fixed-length integers.
Error consume(msf::StreamReader &Reader, uint32_t &Item);
Error consume(msf::StreamReader &Reader, int32_t &Item);
/// Decodes a null terminated string.
Error consume(msf::StreamReader &Reader, StringRef &Item);
Error consume(StringRef &Data, APSInt &Num);
Error consume(StringRef &Data, uint32_t &Item);
/// Decodes an arbitrary object whose layout matches that of the underlying
/// byte sequence, and returns a pointer to the object.
template <typename T> Error consume(msf::StreamReader &Reader, T *&Item) {
return Reader.readObject(Item);
}
template <typename T, typename U> struct serialize_conditional_impl {
serialize_conditional_impl(T &Item, U Func) : Item(Item), Func(Func) {}
Error deserialize(msf::StreamReader &Reader) const {
if (!Func())
return Error::success();
return consume(Reader, Item);
}
T &Item;
U Func;
};
template <typename T, typename U>
serialize_conditional_impl<T, U> serialize_conditional(T &Item, U Func) {
return serialize_conditional_impl<T, U>(Item, Func);
}
template <typename T, typename U> struct serialize_array_impl {
serialize_array_impl(ArrayRef<T> &Item, U Func) : Item(Item), Func(Func) {}
Error deserialize(msf::StreamReader &Reader) const {
return Reader.readArray(Item, Func());
}
ArrayRef<T> &Item;
U Func;
};
template <typename T> struct serialize_vector_tail_impl {
serialize_vector_tail_impl(std::vector<T> &Item) : Item(Item) {}
Error deserialize(msf::StreamReader &Reader) const {
T Field;
// Stop when we run out of bytes or we hit record padding bytes.
while (!Reader.empty() && Reader.peek() < LF_PAD0) {
if (auto EC = consume(Reader, Field))
return EC;
Item.push_back(Field);
}
return Error::success();
}
std::vector<T> &Item;
};
struct serialize_null_term_string_array_impl {
serialize_null_term_string_array_impl(std::vector<StringRef> &Item)
: Item(Item) {}
Error deserialize(msf::StreamReader &Reader) const {
if (Reader.empty())
return make_error<CodeViewError>(cv_error_code::insufficient_buffer,
"Null terminated string is empty!");
while (Reader.peek() != 0) {
StringRef Field;
if (auto EC = Reader.readZeroString(Field))
return EC;
Item.push_back(Field);
}
return Reader.skip(1);
}
std::vector<StringRef> &Item;
};
template <typename T> struct serialize_arrayref_tail_impl {
serialize_arrayref_tail_impl(ArrayRef<T> &Item) : Item(Item) {}
Error deserialize(msf::StreamReader &Reader) const {
uint32_t Count = Reader.bytesRemaining() / sizeof(T);
return Reader.readArray(Item, Count);
}
ArrayRef<T> &Item;
};
template <typename T> struct serialize_numeric_impl {
serialize_numeric_impl(T &Item) : Item(Item) {}
Error deserialize(msf::StreamReader &Reader) const {
return consume_numeric(Reader, Item);
}
T &Item;
};
template <typename T, typename U>
serialize_array_impl<T, U> serialize_array(ArrayRef<T> &Item, U Func) {
return serialize_array_impl<T, U>(Item, Func);
}
inline serialize_null_term_string_array_impl
serialize_null_term_string_array(std::vector<StringRef> &Item) {
return serialize_null_term_string_array_impl(Item);
}
template <typename T>
serialize_vector_tail_impl<T> serialize_array_tail(std::vector<T> &Item) {
return serialize_vector_tail_impl<T>(Item);
}
template <typename T>
serialize_arrayref_tail_impl<T> serialize_array_tail(ArrayRef<T> &Item) {
return serialize_arrayref_tail_impl<T>(Item);
}
template <typename T> serialize_numeric_impl<T> serialize_numeric(T &Item) {
return serialize_numeric_impl<T>(Item);
}
// This field is only present in the byte record if the condition is true. The
// condition is evaluated lazily, so it can depend on items that were
// deserialized
// earlier.
#define CV_CONDITIONAL_FIELD(I, C) \
serialize_conditional(I, [&]() { return !!(C); })
// This is an array of N items, where N is evaluated lazily, so it can refer
// to a field deserialized earlier.
#define CV_ARRAY_FIELD_N(I, N) serialize_array(I, [&]() { return N; })
// This is an array that exhausts the remainder of the input buffer.
#define CV_ARRAY_FIELD_TAIL(I) serialize_array_tail(I)
// This is an array that consumes null terminated strings until a double null
// is encountered.
#define CV_STRING_ARRAY_NULL_TERM(I) serialize_null_term_string_array(I)
#define CV_NUMERIC_FIELD(I) serialize_numeric(I)
template <typename T, typename U>
Error consume(msf::StreamReader &Reader,
const serialize_conditional_impl<T, U> &Item) {
return Item.deserialize(Reader);
}
template <typename T, typename U>
Error consume(msf::StreamReader &Reader,
const serialize_array_impl<T, U> &Item) {
return Item.deserialize(Reader);
}
inline Error consume(msf::StreamReader &Reader,
const serialize_null_term_string_array_impl &Item) {
return Item.deserialize(Reader);
}
template <typename T>
Error consume(msf::StreamReader &Reader,
const serialize_vector_tail_impl<T> &Item) {
return Item.deserialize(Reader);
}
template <typename T>
Error consume(msf::StreamReader &Reader,
const serialize_arrayref_tail_impl<T> &Item) {
return Item.deserialize(Reader);
}
template <typename T>
Error consume(msf::StreamReader &Reader,
const serialize_numeric_impl<T> &Item) {
return Item.deserialize(Reader);
}
template <typename T, typename U, typename... Args>
Error consume(msf::StreamReader &Reader, T &&X, U &&Y, Args &&... Rest) {
if (auto EC = consume(Reader, X))
return EC;
return consume(Reader, Y, std::forward<Args>(Rest)...);
}
#define CV_DESERIALIZE(...) \
if (auto EC = consume(__VA_ARGS__)) \
return std::move(EC);
}
}
#endif