[llvm] r269315 - Make CodeView record serialization more generic.
Zachary Turner via llvm-commits
llvm-commits at lists.llvm.org
Thu May 12 10:45:45 PDT 2016
Author: zturner
Date: Thu May 12 12:45:44 2016
New Revision: 269315
URL: http://llvm.org/viewvc/llvm-project?rev=269315&view=rev
Log:
Make CodeView record serialization more generic.
This introduces a variadic template and some helper macros to
safely and correctly deserialize many types of common record
fields while maintaining error checking.
Differential Revision: http://reviews.llvm.org/D20183
Reviewed By: rnk, amccarth
Added:
llvm/trunk/include/llvm/DebugInfo/CodeView/RecordSerialization.h
llvm/trunk/lib/DebugInfo/CodeView/RecordSerialization.cpp
Removed:
llvm/trunk/lib/DebugInfo/CodeView/TypeStream.cpp
Modified:
llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h
llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt
llvm/trunk/tools/llvm-readobj/COFFDumper.cpp
Added: llvm/trunk/include/llvm/DebugInfo/CodeView/RecordSerialization.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/RecordSerialization.h?rev=269315&view=auto
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/RecordSerialization.h (added)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/RecordSerialization.h Thu May 12 12:45:44 2016
@@ -0,0 +1,205 @@
+//===- 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/Support/Endian.h"
+#include <cinttypes>
+#include <tuple>
+
+namespace llvm {
+namespace codeview {
+using llvm::support::little32_t;
+using llvm::support::ulittle16_t;
+using llvm::support::ulittle32_t;
+
+/// 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);
+
+/// Consumes sizeof(T) bytes from the given byte sequence. Returns an error if
+/// there are not enough bytes remaining. Reinterprets the consumed bytes as a
+/// T object and points 'Res' at them.
+template <typename T, typename U>
+inline std::error_code consumeObject(U &Data, const T *&Res) {
+ if (Data.size() < sizeof(*Res))
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Res = reinterpret_cast<const T *>(Data.data());
+ Data = Data.drop_front(sizeof(*Res));
+ return std::error_code();
+}
+
+inline std::error_code consume(ArrayRef<uint8_t> &Data) {
+ return std::error_code();
+}
+
+/// 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.
+std::error_code consume(ArrayRef<uint8_t> &Data, APSInt &Num);
+std::error_code consume(StringRef &Data, APSInt &Num);
+
+/// Decodes a numeric leaf value that is known to be a particular type.
+std::error_code consume_numeric(ArrayRef<uint8_t> &Data, uint64_t &Value);
+
+/// Decodes signed and unsigned fixed-length integers.
+std::error_code consume(ArrayRef<uint8_t> &Data, uint32_t &Item);
+std::error_code consume(StringRef &Data, uint32_t &Item);
+std::error_code consume(ArrayRef<uint8_t> &Data, int32_t &Item);
+
+/// Decodes a null terminated string.
+std::error_code consume(ArrayRef<uint8_t> &Data, StringRef &Item);
+
+/// Decodes an arbitrary object whose layout matches that of the underlying
+/// byte sequence, and returns a pointer to the object.
+template <typename T>
+std::error_code consume(ArrayRef<uint8_t> &Data, T *&Item) {
+ return consumeObject(Data, Item);
+}
+
+template <typename T, typename U> struct serialize_conditional_impl {
+ serialize_conditional_impl(T &Item, U Func) : Item(Item), Func(Func) {}
+
+ std::error_code deserialize(ArrayRef<uint8_t> &Data) const {
+ if (!Func())
+ return std::error_code();
+ return consume(Data, 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) {}
+
+ std::error_code deserialize(ArrayRef<uint8_t> &Data) const {
+ uint32_t N = Func();
+ if (N == 0)
+ return std::error_code();
+
+ uint32_t Size = sizeof(T) * N;
+ if (Data.size() < Size)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+
+ Item = ArrayRef<T>(reinterpret_cast<const T *>(Data.data()), N);
+ Data = Data.drop_front(Size);
+ return std::error_code();
+ }
+
+ ArrayRef<T> &Item;
+ U Func;
+};
+
+template <typename T> struct serialize_array_tail_impl {
+ serialize_array_tail_impl(std::vector<T> &Item) : Item(Item) {}
+
+ std::error_code deserialize(ArrayRef<uint8_t> &Data) const {
+ T Field;
+ while (!Data.empty()) {
+ if (auto EC = consume(Data, Field))
+ return EC;
+ Item.push_back(Field);
+ }
+ return std::error_code();
+ }
+
+ std::vector<T> &Item;
+};
+
+template <typename T> struct serialize_numeric_impl {
+ serialize_numeric_impl(T &Item) : Item(Item) {}
+
+ std::error_code deserialize(ArrayRef<uint8_t> &Data) const {
+ return consume_numeric(Data, 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);
+}
+
+template <typename T>
+serialize_array_tail_impl<T> serialize_array_tail(std::vector<T> &Item) {
+ return serialize_array_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)
+
+#define CV_NUMERIC_FIELD(I) serialize_numeric(I)
+
+template <typename T, typename U>
+std::error_code consume(ArrayRef<uint8_t> &Data,
+ const serialize_conditional_impl<T, U> &Item) {
+ return Item.deserialize(Data);
+}
+
+template <typename T, typename U>
+std::error_code consume(ArrayRef<uint8_t> &Data,
+ const serialize_array_impl<T, U> &Item) {
+ return Item.deserialize(Data);
+}
+
+template <typename T>
+std::error_code consume(ArrayRef<uint8_t> &Data,
+ const serialize_array_tail_impl<T> &Item) {
+ return Item.deserialize(Data);
+}
+
+template <typename T>
+std::error_code consume(ArrayRef<uint8_t> &Data,
+ const serialize_numeric_impl<T> &Item) {
+ return Item.deserialize(Data);
+}
+
+template <typename T, typename U, typename... Args>
+std::error_code consume(ArrayRef<uint8_t> &Data, T &&X, U &&Y,
+ Args &&... Rest) {
+ if (auto EC = consume(Data, X))
+ return EC;
+ return consume(Data, Y, std::forward<Args>(Rest)...);
+}
+
+#define CV_DESERIALIZE(...) \
+ if (auto EC = consume(__VA_ARGS__)) \
+ return EC;
+}
+}
+
+#endif
Modified: llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h?rev=269315&r1=269314&r2=269315&view=diff
==============================================================================
--- llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h (original)
+++ llvm/trunk/include/llvm/DebugInfo/CodeView/TypeRecord.h Thu May 12 12:45:44 2016
@@ -14,10 +14,10 @@
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
#include "llvm/Support/ErrorOr.h"
#include <cinttypes>
-#include <tuple>
namespace llvm {
namespace codeview {
@@ -26,79 +26,6 @@ using llvm::support::little32_t;
using llvm::support::ulittle16_t;
using llvm::support::ulittle32_t;
-/// 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.
-bool decodeNumericLeaf(ArrayRef<uint8_t> &Data, APSInt &Num);
-
-inline bool decodeNumericLeaf(StringRef &Data, APSInt &Num) {
- ArrayRef<uint8_t> Bytes(reinterpret_cast<const uint8_t *>(Data.data()),
- Data.size());
- bool Success = decodeNumericLeaf(Bytes, Num);
- Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
- return Success;
-}
-
-/// Decode a numeric leaf value that is known to be a uint32_t.
-bool decodeUIntLeaf(ArrayRef<uint8_t> &Data, uint64_t &Num);
-
-/// 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.
-inline StringRef getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {
- return StringRef(reinterpret_cast<const char *>(LeafData.data()),
- LeafData.size());
-}
-
-inline StringRef getBytesAsCString(ArrayRef<uint8_t> LeafData) {
- return getBytesAsCharacters(LeafData).split('\0').first;
-}
-
-/// Consumes sizeof(T) bytes from the given byte sequence. Returns an error if
-/// there are not enough bytes remaining. Reinterprets the consumed bytes as a
-/// T object and points 'Res' at them.
-template <typename T, typename U>
-inline std::error_code consumeObject(U &Data, const T *&Res) {
- if (Data.size() < sizeof(*Res))
- return std::make_error_code(std::errc::illegal_byte_sequence);
- Res = reinterpret_cast<const T *>(Data.data());
- Data = Data.drop_front(sizeof(*Res));
- return std::error_code();
-}
-
-inline std::error_code consumeCString(ArrayRef<uint8_t> &Data, StringRef &Str) {
- if (Data.empty())
- return std::make_error_code(std::errc::illegal_byte_sequence);
-
- StringRef Rest;
- std::tie(Str, Rest) = getBytesAsCharacters(Data).split('\0');
- // We expect this to be null terminated. If it was not, it is an error.
- if (Data.size() == Str.size())
- return std::make_error_code(std::errc::illegal_byte_sequence);
-
- Data = ArrayRef<uint8_t>(Rest.bytes_begin(), Rest.bytes_end());
- return std::error_code();
-}
-
-template <typename T>
-inline std::error_code consumeArray(ArrayRef<uint8_t> &Data,
- ArrayRef<T> &Result, uint32_t N) {
- uint32_t Size = sizeof(T) * N;
- if (Data.size() < Size)
- return std::make_error_code(std::errc::illegal_byte_sequence);
-
- Result = ArrayRef<T>(reinterpret_cast<const T *>(Data.data()), N);
- Data = Data.drop_front(Size);
- return std::error_code();
-}
-
-inline std::error_code consumeUInt32(StringRef &Data, uint32_t &Res) {
- const support::ulittle32_t *IntPtr;
- if (auto EC = consumeObject(Data, IntPtr))
- return EC;
- Res = *IntPtr;
- return std::error_code();
-}
/// Equvalent to CV_fldattr_t in cvinfo.h.
struct MemberAttributes {
@@ -278,8 +205,7 @@ public:
static ErrorOr<MemberFunctionRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
+ CV_DESERIALIZE(Data, L);
return MemberFunctionRecord(L->ReturnType, L->ClassType, L->ThisType,
L->CallConv, L->Options, L->NumParameters,
@@ -328,12 +254,9 @@ public:
static ErrorOr<MemberFunctionIdRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
-
StringRef Name;
- if (auto EC = consumeCString(Data, Name))
- return EC;
+ CV_DESERIALIZE(Data, L, Name);
+
return MemberFunctionIdRecord(L->ClassType, L->FunctionType, Name);
}
@@ -365,12 +288,9 @@ public:
return std::make_error_code(std::errc::illegal_byte_sequence);
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
-
ArrayRef<TypeIndex> Indices;
- if (auto EC = consumeArray(Data, Indices, L->NumArgs))
- return EC;
+ CV_DESERIALIZE(Data, L, CV_ARRAY_FIELD_N(Indices, L->NumArgs));
+
return StringListRecord(Kind, Indices);
}
@@ -505,12 +425,9 @@ public:
static ErrorOr<NestedTypeRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
-
StringRef Name;
- if (auto EC = consumeCString(Data, Name))
- return EC;
+ CV_DESERIALIZE(Data, L, Name);
+
return NestedTypeRecord(L->Type, Name);
}
@@ -539,15 +456,10 @@ public:
static ErrorOr<ArrayRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
-
uint64_t Size;
- if (!decodeUIntLeaf(Data, Size))
- return std::make_error_code(std::errc::illegal_byte_sequence);
StringRef Name;
- if (auto EC = consumeCString(Data, Name))
- return EC;
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Size), Name);
+
return ArrayRecord(L->ElementType, L->IndexType, Size, Name);
}
@@ -614,10 +526,10 @@ public:
StringRef Name;
StringRef UniqueName;
uint16_t Props;
-
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
+
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Size), Name,
+ CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName()));
Props = L->Properties;
uint16_t WrtValue = (Props & WinRTKindMask) >> WinRTKindShift;
@@ -625,15 +537,6 @@ public:
uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift;
HfaKind Hfa = static_cast<HfaKind>(HfaMask);
- if (!decodeUIntLeaf(Data, Size))
- return std::make_error_code(std::errc::illegal_byte_sequence);
- if (auto EC = consumeCString(Data, Name))
- return EC;
- if (Props & uint16_t(ClassOptions::HasUniqueName)) {
- if (auto EC = consumeCString(Data, UniqueName))
- return EC;
- }
-
ClassOptions Options = static_cast<ClassOptions>(Props);
return ClassRecord(Kind, L->MemberCount, Options, Hfa, WRT, L->FieldList,
L->DerivedFrom, L->VShape, Size, Name, UniqueName);
@@ -655,6 +558,10 @@ private:
// SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC
// integer.
// Name: The null-terminated name follows.
+
+ bool hasUniqueName() const {
+ return Properties & uint16_t(ClassOptions::HasUniqueName);
+ }
};
HfaKind Hfa;
@@ -681,23 +588,13 @@ struct UnionRecord : public TagRecord {
uint16_t Props;
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Size), Name,
+ CV_CONDITIONAL_FIELD(UniqueName, L->hasUniqueName()));
Props = L->Properties;
uint16_t HfaMask = (Props & HfaKindMask) >> HfaKindShift;
HfaKind Hfa = static_cast<HfaKind>(HfaMask);
-
- if (!decodeUIntLeaf(Data, Size))
- return std::make_error_code(std::errc::illegal_byte_sequence);
- if (auto EC = consumeCString(Data, Name))
- return EC;
- if (Props & uint16_t(ClassOptions::HasUniqueName)) {
- if (auto EC = consumeCString(Data, UniqueName))
- return EC;
- }
-
ClassOptions Options = static_cast<ClassOptions>(Props);
return UnionRecord(L->MemberCount, Options, Hfa, L->FieldList, Size, Name,
UniqueName);
@@ -714,6 +611,10 @@ private:
// SizeOf: The 'sizeof' the UDT in bytes is encoded as an LF_NUMERIC
// integer.
// Name: The null-terminated name follows.
+
+ bool hasUniqueName() const {
+ return Properties & uint16_t(ClassOptions::HasUniqueName);
+ }
};
HfaKind Hfa;
@@ -732,14 +633,11 @@ public:
static ErrorOr<EnumRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
+ StringRef Name;
+ CV_DESERIALIZE(Data, L, Name);
uint16_t P = L->Properties;
ClassOptions Options = static_cast<ClassOptions>(P);
- StringRef Name;
- if (auto EC = consumeCString(Data, Name))
- return EC;
return EnumRecord(L->NumEnumerators, Options, L->FieldListType, Name, Name,
L->UnderlyingType);
}
@@ -839,12 +737,9 @@ public:
static ErrorOr<TypeServer2Record> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
-
StringRef Name;
- if (auto EC = consumeCString(Data, Name))
- return EC;
+ CV_DESERIALIZE(Data, L, Name);
+
return TypeServer2Record(StringRef(L->Guid, 16), L->Age, Name);
}
@@ -875,12 +770,9 @@ public:
static ErrorOr<StringIdRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
-
StringRef Name;
- if (auto EC = consumeCString(Data, Name))
- return EC;
+ CV_DESERIALIZE(Data, L, Name);
+
return StringIdRecord(L->id, Name);
}
@@ -908,12 +800,8 @@ public:
static ErrorOr<FuncIdRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
-
StringRef Name;
- if (auto EC = consumeCString(Data, Name))
- return EC;
+ CV_DESERIALIZE(Data, L, Name);
return FuncIdRecord(L->ParentScope, L->FunctionType, Name);
}
@@ -946,8 +834,7 @@ public:
static ErrorOr<UdtSourceLineRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
+ CV_DESERIALIZE(Data, L);
return UdtSourceLineRecord(L->UDT, L->SourceFile, L->LineNumber);
}
@@ -977,12 +864,9 @@ public:
static ErrorOr<BuildInfoRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
-
ArrayRef<TypeIndex> Indices;
- if (auto EC = consumeArray(Data, Indices, L->NumArgs))
- return EC;
+ CV_DESERIALIZE(Data, L, CV_ARRAY_FIELD_N(Indices, L->NumArgs));
+
return BuildInfoRecord(Indices);
}
@@ -1015,19 +899,10 @@ public:
static ErrorOr<VirtualTableRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
-
StringRef Name;
- if (auto EC = consumeCString(Data, Name))
- return EC;
-
std::vector<StringRef> Names;
- while (!Data.empty()) {
- if (auto EC = consumeCString(Data, Name))
- return EC;
- Names.push_back(Name);
- }
+ CV_DESERIALIZE(Data, L, Name, CV_ARRAY_FIELD_TAIL(Names));
+
return VirtualTableRecord(L->CompleteClass, L->OverriddenVFTable,
L->VFPtrOffset, Name, Names);
}
@@ -1072,23 +947,16 @@ public:
static ErrorOr<OneMethodRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
+ StringRef Name;
+ int32_t VFTableOffset = 0;
+
+ CV_DESERIALIZE(Data, L, CV_CONDITIONAL_FIELD(
+ VFTableOffset, L->Attrs.isIntroducedVirtual()),
+ Name);
MethodOptions Options = L->Attrs.getFlags();
MethodKind MethKind = L->Attrs.getMethodKind();
MemberAccess Access = L->Attrs.getAccess();
- int32_t VFTableOffset = 0;
- if (L->Attrs.isIntroducedVirtual()) {
- const little32_t *L;
- if (consumeObject(Data, L))
- return std::make_error_code(std::errc::illegal_byte_sequence);
- VFTableOffset = *L;
- }
- StringRef Name;
- if (auto EC = consumeCString(Data, Name))
- return EC;
-
return OneMethodRecord(L->Type, MethKind, Options, Access, VFTableOffset,
Name);
}
@@ -1135,19 +1003,13 @@ public:
static ErrorOr<MethodListRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
+ int32_t VFTableOffset = 0;
+ CV_DESERIALIZE(Data, L, CV_CONDITIONAL_FIELD(
+ VFTableOffset, L->Attrs.isIntroducedVirtual()));
MethodOptions Options = L->Attrs.getFlags();
MethodKind MethKind = L->Attrs.getMethodKind();
MemberAccess Access = L->Attrs.getAccess();
- int32_t VFTableOffset = 0;
- if (L->Attrs.isIntroducedVirtual()) {
- const little32_t *L;
- if (consumeObject(Data, L))
- return std::make_error_code(std::errc::illegal_byte_sequence);
- VFTableOffset = *L;
- }
return MethodListRecord(L->Type, MethKind, Options, Access, VFTableOffset);
}
@@ -1186,11 +1048,8 @@ public:
static ErrorOr<OverloadedMethodRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
StringRef Name;
- if (auto EC = consumeCString(Data, Name))
- return EC;
+ CV_DESERIALIZE(Data, L, Name);
return OverloadedMethodRecord(L->MethodCount, L->MethList, Name);
}
@@ -1222,15 +1081,9 @@ public:
static ErrorOr<DataMemberRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
-
uint64_t Offset;
- if (!decodeUIntLeaf(Data, Offset))
- return std::make_error_code(std::errc::illegal_byte_sequence);
StringRef Name;
- if (auto EC = consumeCString(Data, Name))
- return EC;
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset), Name);
return DataMemberRecord(L->Attrs.getAccess(), L->Type, Offset, Name);
}
@@ -1264,12 +1117,8 @@ public:
static ErrorOr<StaticDataMemberRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
-
StringRef Name;
- if (auto EC = consumeCString(Data, Name))
- return EC;
+ CV_DESERIALIZE(Data, L, Name);
return StaticDataMemberRecord(L->Attrs.getAccess(), L->Type, Name);
}
@@ -1300,18 +1149,9 @@ public:
static ErrorOr<EnumeratorRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
-
- if (Data.empty())
- return std::make_error_code(std::errc::illegal_byte_sequence);
APSInt Value;
- if (!decodeNumericLeaf(Data, Value))
- return std::make_error_code(std::errc::illegal_byte_sequence);
-
StringRef Name;
- if (auto EC = consumeCString(Data, Name))
- return EC;
+ CV_DESERIALIZE(Data, L, Value, Name);
return EnumeratorRecord(L->Attrs.getAccess(), Value, Name);
}
@@ -1366,12 +1206,8 @@ public:
static ErrorOr<BaseClassRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
-
uint64_t Offset;
- if (!decodeUIntLeaf(Data, Offset))
- return std::make_error_code(std::errc::illegal_byte_sequence);
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset));
return BaseClassRecord(L->Attrs.getAccess(), L->BaseType, Offset);
}
@@ -1403,15 +1239,9 @@ public:
static ErrorOr<VirtualBaseClassRecord> deserialize(TypeRecordKind Kind,
ArrayRef<uint8_t> &Data) {
const Layout *L = nullptr;
- if (auto EC = consumeObject(Data, L))
- return EC;
-
uint64_t Offset;
uint64_t Index;
- if (!decodeUIntLeaf(Data, Offset))
- return std::make_error_code(std::errc::illegal_byte_sequence);
- if (!decodeUIntLeaf(Data, Index))
- return std::make_error_code(std::errc::illegal_byte_sequence);
+ CV_DESERIALIZE(Data, L, CV_NUMERIC_FIELD(Offset), CV_NUMERIC_FIELD(Index));
return VirtualBaseClassRecord(L->Attrs.getAccess(), L->BaseType,
L->VBPtrType, Offset, Index);
Modified: llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt?rev=269315&r1=269314&r2=269315&view=diff
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/CMakeLists.txt Thu May 12 12:45:44 2016
@@ -4,10 +4,10 @@ add_llvm_library(LLVMDebugInfoCodeView
ListRecordBuilder.cpp
MemoryTypeTableBuilder.cpp
MethodListRecordBuilder.cpp
+ RecordSerialization.cpp
TypeDumper.cpp
TypeRecordBuilder.cpp
TypeTableBuilder.cpp
- TypeStream.cpp
ADDITIONAL_HEADER_DIRS
${LLVM_MAIN_INCLUDE_DIR}/llvm/DebugInfo/CodeView
Added: llvm/trunk/lib/DebugInfo/CodeView/RecordSerialization.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/RecordSerialization.cpp?rev=269315&view=auto
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/RecordSerialization.cpp (added)
+++ llvm/trunk/lib/DebugInfo/CodeView/RecordSerialization.cpp Thu May 12 12:45:44 2016
@@ -0,0 +1,157 @@
+//===-- RecordSerialization.cpp -------------------------------------------===//
+//
+// The LLVM Compiler Infrastructure
+//
+// This file is distributed under the University of Illinois Open Source
+// License. See LICENSE.TXT for details.
+//
+//===----------------------------------------------------------------------===//
+//
+// Utilities for serializing and deserializing CodeView records.
+//
+//===----------------------------------------------------------------------===//
+
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
+#include "llvm/ADT/APInt.h"
+#include "llvm/ADT/APSInt.h"
+#include "llvm/DebugInfo/CodeView/TypeRecord.h"
+
+using namespace llvm;
+using namespace llvm::codeview;
+using namespace llvm::support;
+
+/// 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 llvm::codeview::getBytesAsCharacters(ArrayRef<uint8_t> LeafData) {
+ return StringRef(reinterpret_cast<const char *>(LeafData.data()),
+ LeafData.size());
+}
+
+StringRef llvm::codeview::getBytesAsCString(ArrayRef<uint8_t> LeafData) {
+ return getBytesAsCharacters(LeafData).split('\0').first;
+}
+
+std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data, APSInt &Num) {
+ // Used to avoid overload ambiguity on APInt construtor.
+ bool FalseVal = false;
+ if (Data.size() < 2)
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ uint16_t Short = *reinterpret_cast<const ulittle16_t *>(Data.data());
+ Data = Data.drop_front(2);
+ if (Short < LF_NUMERIC) {
+ Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false),
+ /*isUnsigned=*/true);
+ return std::error_code();
+ }
+ switch (Short) {
+ case LF_CHAR:
+ Num = APSInt(APInt(/*numBits=*/8,
+ *reinterpret_cast<const int8_t *>(Data.data()),
+ /*isSigned=*/true),
+ /*isUnsigned=*/false);
+ Data = Data.drop_front(1);
+ return std::error_code();
+ case LF_SHORT:
+ Num = APSInt(APInt(/*numBits=*/16,
+ *reinterpret_cast<const little16_t *>(Data.data()),
+ /*isSigned=*/true),
+ /*isUnsigned=*/false);
+ Data = Data.drop_front(2);
+ return std::error_code();
+ case LF_USHORT:
+ Num = APSInt(APInt(/*numBits=*/16,
+ *reinterpret_cast<const ulittle16_t *>(Data.data()),
+ /*isSigned=*/false),
+ /*isUnsigned=*/true);
+ Data = Data.drop_front(2);
+ return std::error_code();
+ case LF_LONG:
+ Num = APSInt(APInt(/*numBits=*/32,
+ *reinterpret_cast<const little32_t *>(Data.data()),
+ /*isSigned=*/true),
+ /*isUnsigned=*/false);
+ Data = Data.drop_front(4);
+ return std::error_code();
+ case LF_ULONG:
+ Num = APSInt(APInt(/*numBits=*/32,
+ *reinterpret_cast<const ulittle32_t *>(Data.data()),
+ /*isSigned=*/FalseVal),
+ /*isUnsigned=*/true);
+ Data = Data.drop_front(4);
+ return std::error_code();
+ case LF_QUADWORD:
+ Num = APSInt(APInt(/*numBits=*/64,
+ *reinterpret_cast<const little64_t *>(Data.data()),
+ /*isSigned=*/true),
+ /*isUnsigned=*/false);
+ Data = Data.drop_front(8);
+ return std::error_code();
+ case LF_UQUADWORD:
+ Num = APSInt(APInt(/*numBits=*/64,
+ *reinterpret_cast<const ulittle64_t *>(Data.data()),
+ /*isSigned=*/false),
+ /*isUnsigned=*/true);
+ Data = Data.drop_front(8);
+ return std::error_code();
+ }
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+}
+
+std::error_code llvm::codeview::consume(StringRef &Data, APSInt &Num) {
+ ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
+ auto EC = consume(Bytes, Num);
+ Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
+ return EC;
+}
+
+/// Decode a numeric leaf value that is known to be a uint64_t.
+std::error_code llvm::codeview::consume_numeric(ArrayRef<uint8_t> &Data,
+ uint64_t &Num) {
+ APSInt N;
+ if (auto EC = consume(Data, N))
+ return EC;
+ if (N.isSigned() || !N.isIntN(64))
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+ Num = N.getLimitedValue();
+ return std::error_code();
+}
+
+std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
+ uint32_t &Item) {
+ const support::ulittle32_t *IntPtr;
+ if (auto EC = consumeObject(Data, IntPtr))
+ return EC;
+ Item = *IntPtr;
+ return std::error_code();
+}
+
+std::error_code llvm::codeview::consume(StringRef &Data, uint32_t &Item) {
+ ArrayRef<uint8_t> Bytes(Data.bytes_begin(), Data.bytes_end());
+ auto EC = consume(Bytes, Item);
+ Data = StringRef(reinterpret_cast<const char *>(Bytes.data()), Bytes.size());
+ return EC;
+}
+
+std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
+ int32_t &Item) {
+ const support::little32_t *IntPtr;
+ if (auto EC = consumeObject(Data, IntPtr))
+ return EC;
+ Item = *IntPtr;
+ return std::error_code();
+}
+
+std::error_code llvm::codeview::consume(ArrayRef<uint8_t> &Data,
+ StringRef &Item) {
+ if (Data.empty())
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+
+ StringRef Rest;
+ std::tie(Item, Rest) = getBytesAsCharacters(Data).split('\0');
+ // We expect this to be null terminated. If it was not, it is an error.
+ if (Data.size() == Item.size())
+ return std::make_error_code(std::errc::illegal_byte_sequence);
+
+ Data = ArrayRef<uint8_t>(Rest.bytes_begin(), Rest.bytes_end());
+ return std::error_code();
+}
Removed: llvm/trunk/lib/DebugInfo/CodeView/TypeStream.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/DebugInfo/CodeView/TypeStream.cpp?rev=269314&view=auto
==============================================================================
--- llvm/trunk/lib/DebugInfo/CodeView/TypeStream.cpp (original)
+++ llvm/trunk/lib/DebugInfo/CodeView/TypeStream.cpp (removed)
@@ -1,97 +0,0 @@
-//===-- TypeStream.cpp ----------------------------------------------------===//
-//
-// The LLVM Compiler Infrastructure
-//
-// This file is distributed under the University of Illinois Open Source
-// License. See LICENSE.TXT for details.
-//
-//===----------------------------------------------------------------------===//
-//
-// Utilities for parsing CodeView type streams.
-//
-//===----------------------------------------------------------------------===//
-
-#include "llvm/ADT/APInt.h"
-#include "llvm/ADT/APSInt.h"
-#include "llvm/DebugInfo/CodeView/TypeRecord.h"
-
-using namespace llvm;
-using namespace llvm::codeview;
-using namespace llvm::support;
-
-bool llvm::codeview::decodeNumericLeaf(ArrayRef<uint8_t> &Data, APSInt &Num) {
- // Used to avoid overload ambiguity on APInt construtor.
- bool FalseVal = false;
- if (Data.size() < 2)
- return false;
- uint16_t Short = *reinterpret_cast<const ulittle16_t *>(Data.data());
- Data = Data.drop_front(2);
- if (Short < LF_NUMERIC) {
- Num = APSInt(APInt(/*numBits=*/16, Short, /*isSigned=*/false),
- /*isUnsigned=*/true);
- return true;
- }
- switch (Short) {
- case LF_CHAR:
- Num = APSInt(APInt(/*numBits=*/8,
- *reinterpret_cast<const int8_t *>(Data.data()),
- /*isSigned=*/true),
- /*isUnsigned=*/false);
- Data = Data.drop_front(1);
- return true;
- case LF_SHORT:
- Num = APSInt(APInt(/*numBits=*/16,
- *reinterpret_cast<const little16_t *>(Data.data()),
- /*isSigned=*/true),
- /*isUnsigned=*/false);
- Data = Data.drop_front(2);
- return true;
- case LF_USHORT:
- Num = APSInt(APInt(/*numBits=*/16,
- *reinterpret_cast<const ulittle16_t *>(Data.data()),
- /*isSigned=*/false),
- /*isUnsigned=*/true);
- Data = Data.drop_front(2);
- return true;
- case LF_LONG:
- Num = APSInt(APInt(/*numBits=*/32,
- *reinterpret_cast<const little32_t *>(Data.data()),
- /*isSigned=*/true),
- /*isUnsigned=*/false);
- Data = Data.drop_front(4);
- return true;
- case LF_ULONG:
- Num = APSInt(APInt(/*numBits=*/32,
- *reinterpret_cast<const ulittle32_t *>(Data.data()),
- /*isSigned=*/FalseVal),
- /*isUnsigned=*/true);
- Data = Data.drop_front(4);
- return true;
- case LF_QUADWORD:
- Num = APSInt(APInt(/*numBits=*/64,
- *reinterpret_cast<const little64_t *>(Data.data()),
- /*isSigned=*/true),
- /*isUnsigned=*/false);
- Data = Data.drop_front(8);
- return true;
- case LF_UQUADWORD:
- Num = APSInt(APInt(/*numBits=*/64,
- *reinterpret_cast<const ulittle64_t *>(Data.data()),
- /*isSigned=*/false),
- /*isUnsigned=*/true);
- Data = Data.drop_front(8);
- return true;
- }
- return false;
-}
-
-/// Decode a numeric leaf value that is known to be a uint32_t.
-bool llvm::codeview::decodeUIntLeaf(ArrayRef<uint8_t> &Data, uint64_t &Num) {
- APSInt N;
- if (!decodeNumericLeaf(Data, N))
- return false;
- if (N.isSigned() || !N.isIntN(64))
- return false;
- Num = N.getLimitedValue();
- return true;
-}
Modified: llvm/trunk/tools/llvm-readobj/COFFDumper.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/tools/llvm-readobj/COFFDumper.cpp?rev=269315&r1=269314&r2=269315&view=diff
==============================================================================
--- llvm/trunk/tools/llvm-readobj/COFFDumper.cpp (original)
+++ llvm/trunk/tools/llvm-readobj/COFFDumper.cpp Thu May 12 12:45:44 2016
@@ -24,6 +24,7 @@
#include "llvm/ADT/StringExtras.h"
#include "llvm/DebugInfo/CodeView/CodeView.h"
#include "llvm/DebugInfo/CodeView/Line.h"
+#include "llvm/DebugInfo/CodeView/RecordSerialization.h"
#include "llvm/DebugInfo/CodeView/SymbolRecord.h"
#include "llvm/DebugInfo/CodeView/TypeDumper.h"
#include "llvm/DebugInfo/CodeView/TypeIndex.h"
@@ -770,8 +771,8 @@ void COFFDumper::initializeFileAndString
// The section consists of a number of subsection in the following format:
// |SubSectionType|SubSectionSize|Contents...|
uint32_t SubType, SubSectionSize;
- error(consumeUInt32(Data, SubType));
- error(consumeUInt32(Data, SubSectionSize));
+ error(consume(Data, SubType));
+ error(consume(Data, SubSectionSize));
if (SubSectionSize > Data.size())
return error(object_error::parse_failed);
switch (ModuleSubstreamKind(SubType)) {
@@ -802,7 +803,7 @@ void COFFDumper::printCodeViewSymbolSect
W.printNumber("Section", SectionName, Obj->getSectionID(Section));
uint32_t Magic;
- error(consumeUInt32(Data, Magic));
+ error(consume(Data, Magic));
W.printHex("Magic", Magic);
if (Magic != COFF::DEBUG_SECTION_MAGIC)
return error(object_error::parse_failed);
@@ -813,8 +814,8 @@ void COFFDumper::printCodeViewSymbolSect
// The section consists of a number of subsection in the following format:
// |SubSectionType|SubSectionSize|Contents...|
uint32_t SubType, SubSectionSize;
- error(consumeUInt32(Data, SubType));
- error(consumeUInt32(Data, SubSectionSize));
+ error(consume(Data, SubType));
+ error(consume(Data, SubSectionSize));
ListScope S(W, "Subsection");
W.printEnum("SubSectionType", SubType, makeArrayRef(SubSectionTypes));
@@ -1211,7 +1212,7 @@ void COFFDumper::printCodeViewSymbolsSub
case S_CALLEES: {
ListScope S(W, Kind == S_CALLEES ? "Callees" : "Callers");
uint32_t Count;
- error(consumeUInt32(SymData, Count));
+ error(consume(SymData, Count));
for (uint32_t I = 0; I < Count; ++I) {
const TypeIndex *FuncID;
error(consumeObject(SymData, FuncID));
@@ -1500,7 +1501,7 @@ void COFFDumper::printCodeViewSymbolsSub
error(consumeObject(SymData, Constant));
printTypeIndex("Type", Constant->Type);
APSInt Value;
- if (!decodeNumericLeaf(SymData, Value))
+ if (consume(SymData, Value))
error(object_error::parse_failed);
W.printNumber("Value", Value);
StringRef Name = SymData.split('\0').first;
@@ -1551,7 +1552,7 @@ void COFFDumper::printCodeViewFileChecks
void COFFDumper::printCodeViewInlineeLines(StringRef Subsection) {
StringRef Data = Subsection;
uint32_t Signature;
- error(consumeUInt32(Data, Signature));
+ error(consume(Data, Signature));
bool HasExtraFiles = Signature == unsigned(InlineeLinesSignature::ExtraFiles);
while (!Data.empty()) {
@@ -1564,12 +1565,12 @@ void COFFDumper::printCodeViewInlineeLin
if (HasExtraFiles) {
uint32_t ExtraFileCount;
- error(consumeUInt32(Data, ExtraFileCount));
+ error(consume(Data, ExtraFileCount));
W.printNumber("ExtraFileCount", ExtraFileCount);
ListScope ExtraFiles(W, "ExtraFiles");
for (unsigned I = 0; I < ExtraFileCount; ++I) {
uint32_t FileID;
- error(consumeUInt32(Data, FileID));
+ error(consume(Data, FileID));
printFileNameForOffset("FileID", FileID);
}
}
@@ -1606,7 +1607,7 @@ StringRef COFFDumper::getFileNameForFile
// The string table offset comes first before the file checksum.
StringRef Data = CVFileChecksumTable.drop_front(FileOffset);
uint32_t StringOffset;
- error(consumeUInt32(Data, StringOffset));
+ error(consume(Data, StringOffset));
// Check if the string table offset is valid.
if (StringOffset >= CVStringTable.size())
@@ -1631,7 +1632,7 @@ void COFFDumper::printCodeViewTypeSectio
W.printBinaryBlock("Data", Data);
uint32_t Magic;
- error(consumeUInt32(Data, Magic));
+ error(consume(Data, Magic));
W.printHex("Magic", Magic);
if (Magic != COFF::DEBUG_SECTION_MAGIC)
return error(object_error::parse_failed);
More information about the llvm-commits
mailing list