[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