[llvm] r360350 - MinidumpYAML: add support for the ThreadList stream

Pavel Labath via llvm-commits llvm-commits at lists.llvm.org
Thu May 9 08:13:53 PDT 2019


Author: labath
Date: Thu May  9 08:13:53 2019
New Revision: 360350

URL: http://llvm.org/viewvc/llvm-project?rev=360350&view=rev
Log:
MinidumpYAML: add support for the ThreadList stream

Summary:
The implementation is a pretty straightforward extension of the pattern
used for (de)serializing the ModuleList stream. Since there are other
streams which use the same format (MemoryList and MemoryList64, at
least). I tried to generalize the code a bit so that adding future
streams of this type can be done with less code.

Reviewers: amccarth, jhenderson, clayborg

Subscribers: markmentovai, lldb-commits, llvm-commits

Tags: #llvm

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

Modified:
    llvm/trunk/include/llvm/ObjectYAML/MinidumpYAML.h
    llvm/trunk/lib/ObjectYAML/MinidumpYAML.cpp
    llvm/trunk/test/tools/obj2yaml/basic-minidump.yaml

Modified: llvm/trunk/include/llvm/ObjectYAML/MinidumpYAML.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/ObjectYAML/MinidumpYAML.h?rev=360350&r1=360349&r2=360350&view=diff
==============================================================================
--- llvm/trunk/include/llvm/ObjectYAML/MinidumpYAML.h (original)
+++ llvm/trunk/include/llvm/ObjectYAML/MinidumpYAML.h Thu May  9 08:13:53 2019
@@ -30,6 +30,7 @@ struct Stream {
     RawContent,
     SystemInfo,
     TextContent,
+    ThreadList,
   };
 
   Stream(StreamKind Kind, minidump::StreamType Type) : Kind(Kind), Type(Type) {}
@@ -50,30 +51,46 @@ struct Stream {
          const object::MinidumpFile &File);
 };
 
-/// A stream representing the list of modules loaded in the process. On disk, it
-/// is represented as a sequence of minidump::Module structures. These contain
-/// pointers to other data structures, like the module's name and CodeView
-/// record. In memory, we represent these as the ParsedModule struct, which
-/// groups minidump::Module with all of its dependant structures in a single
-/// entity.
-struct ModuleListStream : public Stream {
-  struct ParsedModule {
-    minidump::Module Module;
-    std::string Name;
-    yaml::BinaryRef CvRecord;
-    yaml::BinaryRef MiscRecord;
-  };
-  std::vector<ParsedModule> Modules;
+namespace detail {
+/// A stream representing a list of abstract entries in a minidump stream. Its
+/// instantiations can be used to represent the ModuleList stream and other
+/// streams with a similar structure.
+template <typename EntryT> struct ListStream : public Stream {
+  using entry_type = EntryT;
 
-  ModuleListStream(std::vector<ParsedModule> Modules = {})
-      : Stream(StreamKind::ModuleList, minidump::StreamType::ModuleList),
-        Modules(std::move(Modules)) {}
+  std::vector<entry_type> Entries;
 
-  static bool classof(const Stream *S) {
-    return S->Kind == StreamKind::ModuleList;
-  }
+  explicit ListStream(std::vector<entry_type> Entries = {})
+      : Stream(EntryT::Kind, EntryT::Type), Entries(std::move(Entries)) {}
+
+  static bool classof(const Stream *S) { return S->Kind == EntryT::Kind; }
 };
 
+/// A structure containing all data belonging to a single minidump module.
+struct ParsedModule {
+  static constexpr Stream::StreamKind Kind = Stream::StreamKind::ModuleList;
+  static constexpr minidump::StreamType Type = minidump::StreamType::ModuleList;
+
+  minidump::Module Entry;
+  std::string Name;
+  yaml::BinaryRef CvRecord;
+  yaml::BinaryRef MiscRecord;
+};
+
+/// A structure containing all data belonging to a single minidump thread.
+struct ParsedThread {
+  static constexpr Stream::StreamKind Kind = Stream::StreamKind::ThreadList;
+  static constexpr minidump::StreamType Type = minidump::StreamType::ThreadList;
+
+  minidump::Thread Entry;
+  yaml::BinaryRef Stack;
+  yaml::BinaryRef Context;
+};
+} // namespace detail
+
+using ModuleListStream = detail::ListStream<detail::ParsedModule>;
+using ThreadListStream = detail::ListStream<detail::ParsedThread>;
+
 /// A minidump stream represented as a sequence of hex bytes. This is used as a
 /// fallback when no other stream kind is suitable.
 struct RawContentStream : public Stream {
@@ -176,6 +193,11 @@ template <> struct MappingTraits<std::un
   static StringRef validate(IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S);
 };
 
+template <> struct MappingContextTraits<minidump::MemoryDescriptor, BinaryRef> {
+  static void mapping(IO &IO, minidump::MemoryDescriptor &Memory,
+                      BinaryRef &Content);
+};
+
 } // namespace yaml
 
 } // namespace llvm
@@ -188,11 +210,15 @@ LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::m
 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::OtherInfo)
 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::CPUInfo::X86Info)
 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::minidump::VSFixedFileInfo)
+
+LLVM_YAML_DECLARE_MAPPING_TRAITS(
+    llvm::MinidumpYAML::ModuleListStream::entry_type)
 LLVM_YAML_DECLARE_MAPPING_TRAITS(
-    llvm::MinidumpYAML::ModuleListStream::ParsedModule)
+    llvm::MinidumpYAML::ThreadListStream::entry_type)
 
 LLVM_YAML_IS_SEQUENCE_VECTOR(std::unique_ptr<llvm::MinidumpYAML::Stream>)
-LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ModuleListStream::ParsedModule)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ModuleListStream::entry_type)
+LLVM_YAML_IS_SEQUENCE_VECTOR(llvm::MinidumpYAML::ThreadListStream::entry_type)
 
 LLVM_YAML_DECLARE_MAPPING_TRAITS(llvm::MinidumpYAML::Object)
 

Modified: llvm/trunk/lib/ObjectYAML/MinidumpYAML.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/ObjectYAML/MinidumpYAML.cpp?rev=360350&r1=360349&r2=360350&view=diff
==============================================================================
--- llvm/trunk/lib/ObjectYAML/MinidumpYAML.cpp (original)
+++ llvm/trunk/lib/ObjectYAML/MinidumpYAML.cpp Thu May  9 08:13:53 2019
@@ -180,6 +180,8 @@ Stream::StreamKind Stream::getKind(Strea
   case StreamType::LinuxProcStat:
   case StreamType::LinuxProcUptime:
     return StreamKind::TextContent;
+  case StreamType::ThreadList:
+    return StreamKind::ThreadList;
   default:
     return StreamKind::RawContent;
   }
@@ -196,6 +198,8 @@ std::unique_ptr<Stream> Stream::create(S
     return llvm::make_unique<SystemInfoStream>();
   case StreamKind::TextContent:
     return llvm::make_unique<TextContentStream>(Type);
+  case StreamKind::ThreadList:
+    return llvm::make_unique<ThreadListStream>();
   }
   llvm_unreachable("Unhandled stream kind!");
 }
@@ -323,19 +327,19 @@ void yaml::MappingTraits<VSFixedFileInfo
   mapOptionalHex(IO, "File Date Low", Info.FileDateLow, 0);
 }
 
-void yaml::MappingTraits<ModuleListStream::ParsedModule>::mapping(
-    IO &IO, ModuleListStream::ParsedModule &M) {
-  mapRequiredHex(IO, "Base of Image", M.Module.BaseOfImage);
-  mapRequiredHex(IO, "Size of Image", M.Module.SizeOfImage);
-  mapOptionalHex(IO, "Checksum", M.Module.Checksum, 0);
-  IO.mapOptional("Time Date Stamp", M.Module.TimeDateStamp,
+void yaml::MappingTraits<ModuleListStream::entry_type>::mapping(
+    IO &IO, ModuleListStream::entry_type &M) {
+  mapRequiredHex(IO, "Base of Image", M.Entry.BaseOfImage);
+  mapRequiredHex(IO, "Size of Image", M.Entry.SizeOfImage);
+  mapOptionalHex(IO, "Checksum", M.Entry.Checksum, 0);
+  IO.mapOptional("Time Date Stamp", M.Entry.TimeDateStamp,
                  support::ulittle32_t(0));
   IO.mapRequired("Module Name", M.Name);
-  IO.mapOptional("Version Info", M.Module.VersionInfo, VSFixedFileInfo());
+  IO.mapOptional("Version Info", M.Entry.VersionInfo, VSFixedFileInfo());
   IO.mapRequired("CodeView Record", M.CvRecord);
   IO.mapOptional("Misc Record", M.MiscRecord, yaml::BinaryRef());
-  mapOptionalHex(IO, "Reserved0", M.Module.Reserved0, 0);
-  mapOptionalHex(IO, "Reserved1", M.Module.Reserved1, 0);
+  mapOptionalHex(IO, "Reserved0", M.Entry.Reserved0, 0);
+  mapOptionalHex(IO, "Reserved1", M.Entry.Reserved1, 0);
 }
 
 static void streamMapping(yaml::IO &IO, RawContentStream &Stream) {
@@ -350,7 +354,7 @@ static StringRef streamValidate(RawConte
 }
 
 static void streamMapping(yaml::IO &IO, ModuleListStream &Stream) {
-  IO.mapRequired("Modules", Stream.Modules);
+  IO.mapRequired("Modules", Stream.Entries);
 }
 
 static void streamMapping(yaml::IO &IO, SystemInfoStream &Stream) {
@@ -386,6 +390,27 @@ static void streamMapping(yaml::IO &IO,
   IO.mapOptional("Text", Stream.Text);
 }
 
+void yaml::MappingContextTraits<MemoryDescriptor, yaml::BinaryRef>::mapping(
+    IO &IO, MemoryDescriptor &Memory, BinaryRef &Content) {
+  mapRequiredHex(IO, "Start of Memory Range", Memory.StartOfMemoryRange);
+  IO.mapRequired("Content", Content);
+}
+
+void yaml::MappingTraits<ThreadListStream::entry_type>::mapping(
+    IO &IO, ThreadListStream::entry_type &T) {
+  mapRequiredHex(IO, "Thread Id", T.Entry.ThreadId);
+  mapOptionalHex(IO, "Suspend Count", T.Entry.SuspendCount, 0);
+  mapOptionalHex(IO, "Priority Class", T.Entry.PriorityClass, 0);
+  mapOptionalHex(IO, "Priority", T.Entry.Priority, 0);
+  mapOptionalHex(IO, "Environment Block", T.Entry.EnvironmentBlock, 0);
+  IO.mapRequired("Context", T.Context);
+  IO.mapRequired("Stack", T.Entry.Stack, T.Stack);
+}
+
+static void streamMapping(yaml::IO &IO, ThreadListStream &Stream) {
+  IO.mapRequired("Threads", Stream.Entries);
+}
+
 void yaml::MappingTraits<std::unique_ptr<Stream>>::mapping(
     yaml::IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S) {
   StreamType Type;
@@ -408,6 +433,9 @@ void yaml::MappingTraits<std::unique_ptr
   case MinidumpYAML::Stream::StreamKind::TextContent:
     streamMapping(IO, llvm::cast<TextContentStream>(*S));
     break;
+  case MinidumpYAML::Stream::StreamKind::ThreadList:
+    streamMapping(IO, llvm::cast<ThreadListStream>(*S));
+    break;
   }
 }
 
@@ -419,6 +447,7 @@ StringRef yaml::MappingTraits<std::uniqu
   case MinidumpYAML::Stream::StreamKind::ModuleList:
   case MinidumpYAML::Stream::StreamKind::SystemInfo:
   case MinidumpYAML::Stream::StreamKind::TextContent:
+  case MinidumpYAML::Stream::StreamKind::ThreadList:
     return "";
   }
   llvm_unreachable("Fully covered switch above!");
@@ -432,32 +461,50 @@ void yaml::MappingTraits<Object>::mappin
   IO.mapRequired("Streams", O.Streams);
 }
 
+static LocationDescriptor layout(BlobAllocator &File, yaml::BinaryRef Data) {
+  return {support::ulittle32_t(Data.binary_size()),
+          support::ulittle32_t(File.allocateBytes(Data))};
+}
+
+static void layout(BlobAllocator &File, ModuleListStream::entry_type &M) {
+  M.Entry.ModuleNameRVA = File.allocateString(M.Name);
+
+  M.Entry.CvRecord = layout(File, M.CvRecord);
+  M.Entry.MiscRecord = layout(File, M.MiscRecord);
+}
+
+static void layout(BlobAllocator &File, ThreadListStream::entry_type &T) {
+  T.Entry.Stack.Memory = layout(File, T.Stack);
+  T.Entry.Context = layout(File, T.Context);
+}
+
+template <typename EntryT>
+static size_t layout(BlobAllocator &File,
+                     MinidumpYAML::detail::ListStream<EntryT> &S) {
+
+  File.allocateNewObject<support::ulittle32_t>(S.Entries.size());
+  for (auto &E : S.Entries)
+    File.allocateObject(E.Entry);
+
+  size_t DataEnd = File.tell();
+
+  // Lay out the auxiliary data, (which is not a part of the stream).
+  DataEnd = File.tell();
+  for (auto &E : S.Entries)
+    layout(File, E);
+
+  return DataEnd;
+}
+
 static Directory layout(BlobAllocator &File, Stream &S) {
   Directory Result;
   Result.Type = S.Type;
   Result.Location.RVA = File.tell();
   Optional<size_t> DataEnd;
   switch (S.Kind) {
-  case Stream::StreamKind::ModuleList: {
-    ModuleListStream &List = cast<ModuleListStream>(S);
-
-    File.allocateNewObject<support::ulittle32_t>(List.Modules.size());
-    for (ModuleListStream::ParsedModule &M : List.Modules)
-      File.allocateObject(M.Module);
-
-    // Module names and CodeView/Misc records are not a part of the stream.
-    DataEnd = File.tell();
-    for (ModuleListStream::ParsedModule &M : List.Modules) {
-      M.Module.ModuleNameRVA = File.allocateString(M.Name);
-
-      M.Module.CvRecord.RVA = File.allocateBytes(M.CvRecord);
-      M.Module.CvRecord.DataSize = M.CvRecord.binary_size();
-
-      M.Module.MiscRecord.RVA = File.allocateBytes(M.MiscRecord);
-      M.Module.MiscRecord.DataSize = M.MiscRecord.binary_size();
-    }
+  case Stream::StreamKind::ModuleList:
+    DataEnd = layout(File, cast<ModuleListStream>(S));
     break;
-  }
   case Stream::StreamKind::RawContent: {
     RawContentStream &Raw = cast<RawContentStream>(S);
     File.allocateCallback(Raw.Size, [&Raw](raw_ostream &OS) {
@@ -478,6 +525,9 @@ static Directory layout(BlobAllocator &F
   case Stream::StreamKind::TextContent:
     File.allocateArray(arrayRefFromStringRef(cast<TextContentStream>(S).Text));
     break;
+  case Stream::StreamKind::ThreadList:
+    DataEnd = layout(File, cast<ThreadListStream>(S));
+    break;
   }
   // If DataEnd is not set, we assume everything we generated is a part of the
   // stream.
@@ -520,7 +570,7 @@ Stream::create(const Directory &StreamDe
     auto ExpectedList = File.getModuleList();
     if (!ExpectedList)
       return ExpectedList.takeError();
-    std::vector<ModuleListStream::ParsedModule> Modules;
+    std::vector<ModuleListStream::entry_type> Modules;
     for (const Module &M : *ExpectedList) {
       auto ExpectedName = File.getString(M.ModuleNameRVA);
       if (!ExpectedName)
@@ -552,6 +602,22 @@ Stream::create(const Directory &StreamDe
   case StreamKind::TextContent:
     return llvm::make_unique<TextContentStream>(
         StreamDesc.Type, toStringRef(File.getRawStream(StreamDesc)));
+  case StreamKind::ThreadList: {
+    auto ExpectedList = File.getThreadList();
+    if (!ExpectedList)
+      return ExpectedList.takeError();
+    std::vector<ThreadListStream::entry_type> Threads;
+    for (const Thread &T : *ExpectedList) {
+      auto ExpectedStack = File.getRawData(T.Stack.Memory);
+      if (!ExpectedStack)
+        return ExpectedStack.takeError();
+      auto ExpectedContext = File.getRawData(T.Context);
+      if (!ExpectedContext)
+        return ExpectedContext.takeError();
+      Threads.push_back({T, *ExpectedStack, *ExpectedContext});
+    }
+    return llvm::make_unique<ThreadListStream>(std::move(Threads));
+  }
   }
   llvm_unreachable("Unhandled stream kind!");
 }

Modified: llvm/trunk/test/tools/obj2yaml/basic-minidump.yaml
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/tools/obj2yaml/basic-minidump.yaml?rev=360350&r1=360349&r2=360350&view=diff
==============================================================================
--- llvm/trunk/test/tools/obj2yaml/basic-minidump.yaml (original)
+++ llvm/trunk/test/tools/obj2yaml/basic-minidump.yaml Thu May  9 08:13:53 2019
@@ -1,12 +1,12 @@
 # RUN: yaml2obj %s | obj2yaml - | FileCheck %s
 
 --- !minidump
-Streams:         
+Streams:
   - Type:            SystemInfo
     Processor Arch:  ARM64
     Platform ID:     Linux
     CSD Version:     Linux 3.13.0-91-generic
-    CPU:             
+    CPU:
       CPUID:           0x05060708
   - Type:            LinuxAuxv
     Content:         DEADBEEFBAADF00D
@@ -16,41 +16,50 @@ Streams:
       400db000-400dc000 r--p 00001000 b3:04 227        /system/bin/app_process
 
   - Type:            ModuleList
-    Modules:         
+    Modules:
       - Base of Image:   0x0001020304050607
         Size of Image:   0x08090A0B
         Checksum:        0x0C0D0E0F
         Time Date Stamp: 47
         Module Name:     a.out
-        Version Info:    
-          Signature:       0x10111213
-          Struct Version:  0x14151617
-          File Version High: 0x18191A1B
-          File Version Low: 0x1C1D1E1F
+        Version Info:
+          Signature:            0x10111213
+          Struct Version:       0x14151617
+          File Version High:    0x18191A1B
+          File Version Low:     0x1C1D1E1F
           Product Version High: 0x20212223
-          Product Version Low: 0x24252627
-          File Flags Mask: 0x28292A2B
-          File Flags:      0x2C2D2E2F
-          File OS:         0x30313233
-          File Type:       0x34353637
-          File Subtype:    0x38393A3B
-          File Date High:  0x3C3D3E3F
-          File Date Low:   0x40414243
+          Product Version Low:  0x24252627
+          File Flags Mask:      0x28292A2B
+          File Flags:           0x2C2D2E2F
+          File OS:              0x30313233
+          File Type:            0x34353637
+          File Subtype:         0x38393A3B
+          File Date High:       0x3C3D3E3F
+          File Date Low:        0x40414243
         CodeView Record: '44454647'
         Misc Record:     48494A4B
       - Base of Image:   0x4C4D4E4F50515253
         Size of Image:   0x54555657
         Module Name:     libb.so
         CodeView Record: 58595A5B
+  - Type:            ThreadList
+    Threads:
+      - Thread Id:         0x5C5D5E5F
+        Priority Class:    0x60616263
+        Environment Block: 0x6465666768696A6B
+        Context:         7C7D7E7F80818283
+        Stack:
+          Start of Memory Range: 0x6C6D6E6F70717273
+          Content:         7475767778797A7B
 ...
 
 # CHECK:      --- !minidump
-# CHECK-NEXT: Streams:         
+# CHECK-NEXT: Streams:
 # CHECK-NEXT:   - Type:            SystemInfo
 # CHECK-NEXT:     Processor Arch:  ARM64
 # CHECK-NEXT:     Platform ID:     Linux
 # CHECK-NEXT:     CSD Version:     Linux 3.13.0-91-generic
-# CHECK-NEXT:     CPU:             
+# CHECK-NEXT:     CPU:
 # CHECK-NEXT:       CPUID:           0x05060708
 # CHECK-NEXT:   - Type:            LinuxAuxv
 # CHECK-NEXT:     Content:         DEADBEEFBAADF00D
@@ -60,30 +69,39 @@ Streams:
 # CHECK-NEXT:       400db000-400dc000 r--p 00001000 b3:04 227        /system/bin/app_process
 # CHECK-EMPTY:
 # CHECK-NEXT:   - Type:            ModuleList
-# CHECK-NEXT:     Modules:         
+# CHECK-NEXT:     Modules:
 # CHECK-NEXT:       - Base of Image:   0x0001020304050607
 # CHECK-NEXT:         Size of Image:   0x08090A0B
 # CHECK-NEXT:         Checksum:        0x0C0D0E0F
 # CHECK-NEXT:         Time Date Stamp: 47
 # CHECK-NEXT:         Module Name:     a.out
-# CHECK-NEXT:         Version Info:    
-# CHECK-NEXT:           Signature:       0x10111213
-# CHECK-NEXT:           Struct Version:  0x14151617
-# CHECK-NEXT:           File Version High: 0x18191A1B
-# CHECK-NEXT:           File Version Low: 0x1C1D1E1F
+# CHECK-NEXT:         Version Info:
+# CHECK-NEXT:           Signature:            0x10111213
+# CHECK-NEXT:           Struct Version:       0x14151617
+# CHECK-NEXT:           File Version High:    0x18191A1B
+# CHECK-NEXT:           File Version Low:     0x1C1D1E1F
 # CHECK-NEXT:           Product Version High: 0x20212223
-# CHECK-NEXT:           Product Version Low: 0x24252627
-# CHECK-NEXT:           File Flags Mask: 0x28292A2B
-# CHECK-NEXT:           File Flags:      0x2C2D2E2F
-# CHECK-NEXT:           File OS:         0x30313233
-# CHECK-NEXT:           File Type:       0x34353637
-# CHECK-NEXT:           File Subtype:    0x38393A3B
-# CHECK-NEXT:           File Date High:  0x3C3D3E3F
-# CHECK-NEXT:           File Date Low:   0x40414243
+# CHECK-NEXT:           Product Version Low:  0x24252627
+# CHECK-NEXT:           File Flags Mask:      0x28292A2B
+# CHECK-NEXT:           File Flags:           0x2C2D2E2F
+# CHECK-NEXT:           File OS:              0x30313233
+# CHECK-NEXT:           File Type:            0x34353637
+# CHECK-NEXT:           File Subtype:         0x38393A3B
+# CHECK-NEXT:           File Date High:       0x3C3D3E3F
+# CHECK-NEXT:           File Date Low:        0x40414243
 # CHECK-NEXT:         CodeView Record: '44454647'
 # CHECK-NEXT:         Misc Record:     48494A4B
 # CHECK-NEXT:       - Base of Image:   0x4C4D4E4F50515253
 # CHECK-NEXT:         Size of Image:   0x54555657
 # CHECK-NEXT:         Module Name:     libb.so
 # CHECK-NEXT:         CodeView Record: 58595A5B
+# CHECK-NEXT:   - Type:            ThreadList
+# CHECK-NEXT:     Threads:
+# CHECK-NEXT:       - Thread Id:       0x5C5D5E5F
+# CHECK-NEXT:         Priority Class:  0x60616263
+# CHECK-NEXT:         Environment Block: 0x6465666768696A6B
+# CHECK-NEXT:         Context:         7C7D7E7F80818283
+# CHECK-NEXT:         Stack:
+# CHECK-NEXT:           Start of Memory Range: 0x6C6D6E6F70717273
+# CHECK-NEXT:           Content:         7475767778797A7B
 # CHECK-NEXT: ...




More information about the llvm-commits mailing list