JosephTremoulet updated this revision to Diff 224469.
JosephTremoulet added a comment.
Herald added a project: LLDB.
Herald added a subscriber: lldb-commits.

- Update test input yaml Exception stream


Repository:
  rG LLVM Github Monorepo

CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D68657/new/

https://reviews.llvm.org/D68657

Files:
  
lldb/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64.yaml
  llvm/include/llvm/ObjectYAML/MinidumpYAML.h
  llvm/lib/ObjectYAML/MinidumpEmitter.cpp
  llvm/lib/ObjectYAML/MinidumpYAML.cpp
  llvm/unittests/ObjectYAML/MinidumpYAMLTest.cpp

Index: llvm/unittests/ObjectYAML/MinidumpYAMLTest.cpp
===================================================================
--- llvm/unittests/ObjectYAML/MinidumpYAMLTest.cpp
+++ llvm/unittests/ObjectYAML/MinidumpYAMLTest.cpp
@@ -139,3 +139,197 @@
       (ArrayRef<uint8_t>{0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15}),
       makeArrayRef(SysInfo.CPU.Other.ProcessorFeatures));
 }
+
+TEST(MinidumpYAML, ExceptionStream) {
+  SmallString<0> Storage;
+  auto ExpectedFile = toBinary(Storage, R"(
+--- !minidump
+Streams:
+  - Type:            Exception
+    Thread ID:  0x7
+    Exception Record:
+      Exception Code:  0x23
+      Exception Flags: 0x5
+      Exception Record: 0x0102030405060708
+      Exception Address: 0x0a0b0c0d0e0f1011
+      Number Parameters: 2
+      Parameter 0: 0x22
+      Parameter 1: 0x24
+    Thread Context:  3DeadBeefDefacedABadCafe)");
+  ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
+  object::MinidumpFile &File = **ExpectedFile;
+
+  ASSERT_EQ(1u, File.streams().size());
+
+  Expected<const minidump::ExceptionStream &> ExpectedStream =
+      File.getExceptionStream();
+
+  ASSERT_THAT_EXPECTED(ExpectedStream, Succeeded());
+
+  const minidump::ExceptionStream &Stream = *ExpectedStream;
+  EXPECT_EQ(0x7u, Stream.ThreadId);
+  const minidump::Exception &Exception = Stream.ExceptionRecord;
+  EXPECT_EQ(0x23u, Exception.ExceptionCode);
+  EXPECT_EQ(0x5u, Exception.ExceptionFlags);
+  EXPECT_EQ(0x0102030405060708u, Exception.ExceptionRecord);
+  EXPECT_EQ(0x0a0b0c0d0e0f1011u, Exception.ExceptionAddress);
+  EXPECT_EQ(2u, Exception.NumberParameters);
+  EXPECT_EQ(0x22u, Exception.ExceptionInformation[0]);
+  EXPECT_EQ(0x24u, Exception.ExceptionInformation[1]);
+
+  Expected<ArrayRef<uint8_t>> ExpectedContext =
+      File.getRawData(Stream.ThreadContext);
+  ASSERT_THAT_EXPECTED(ExpectedContext, Succeeded());
+  EXPECT_EQ((ArrayRef<uint8_t>{0x3d, 0xea, 0xdb, 0xee, 0xfd, 0xef, 0xac, 0xed,
+                               0xab, 0xad, 0xca, 0xfe}),
+            *ExpectedContext);
+}
+
+TEST(MinidumpYAML, ExceptionStream_NoParameters) {
+  SmallString<0> Storage;
+  auto ExpectedFile = toBinary(Storage, R"(
+--- !minidump
+Streams:
+  - Type:            Exception
+    Thread ID:  0x7
+    Exception Record:
+      Exception Code:  0x23
+      Exception Flags: 0x5
+      Exception Record: 0x0102030405060708
+      Exception Address: 0x0a0b0c0d0e0f1011
+    Thread Context:  3DeadBeefDefacedABadCafe)");
+  ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
+  object::MinidumpFile &File = **ExpectedFile;
+
+  ASSERT_EQ(1u, File.streams().size());
+
+  Expected<const minidump::ExceptionStream &> ExpectedStream =
+      File.getExceptionStream();
+
+  ASSERT_THAT_EXPECTED(ExpectedStream, Succeeded());
+
+  const minidump::ExceptionStream &Stream = *ExpectedStream;
+  EXPECT_EQ(0x7u, Stream.ThreadId);
+  const minidump::Exception &Exception = Stream.ExceptionRecord;
+  EXPECT_EQ(0x23u, Exception.ExceptionCode);
+  EXPECT_EQ(0x5u, Exception.ExceptionFlags);
+  EXPECT_EQ(0x0102030405060708u, Exception.ExceptionRecord);
+  EXPECT_EQ(0x0a0b0c0d0e0f1011u, Exception.ExceptionAddress);
+  EXPECT_EQ(0u, Exception.NumberParameters);
+
+  Expected<ArrayRef<uint8_t>> ExpectedContext =
+      File.getRawData(Stream.ThreadContext);
+  ASSERT_THAT_EXPECTED(ExpectedContext, Succeeded());
+  EXPECT_EQ((ArrayRef<uint8_t>{0x3d, 0xea, 0xdb, 0xee, 0xfd, 0xef, 0xac, 0xed,
+                               0xab, 0xad, 0xca, 0xfe}),
+            *ExpectedContext);
+}
+
+TEST(MinidumpYAML, ExceptionStream_TooManyParameters) {
+  SmallString<0> Storage;
+  auto ExpectedFile = toBinary(Storage, R"(
+--- !minidump
+Streams:
+  - Type:            Exception
+    Thread ID:  0x8
+    Exception Record:
+      Exception Code: 0
+      Number Parameters: 16
+      Parameter 0: 0x0
+      Parameter 1: 0xff
+      Parameter 2: 0xee
+      Parameter 3: 0xdd
+      Parameter 4: 0xcc
+      Parameter 5: 0xbb
+      Parameter 6: 0xaa
+      Parameter 7: 0x99
+      Parameter 8: 0x88
+      Parameter 9: 0x77
+      Parameter 10: 0x66
+      Parameter 11: 0x55
+      Parameter 12: 0x44
+      Parameter 13: 0x33
+      Parameter 14: 0x22
+      Parameter 15: 0x11
+    Thread Context:  3DeadBeefDefacedABadCafe)");
+  ASSERT_FALSE(ExpectedFile);
+  auto Unhandled =
+      handleErrors(ExpectedFile.takeError(), [](const StringError &error) {
+        EXPECT_EQ(static_cast<int>(std::errc::invalid_argument),
+                  error.convertToErrorCode().value());
+      });
+  EXPECT_THAT_ERROR(std::move(Unhandled), Succeeded());
+}
+
+TEST(MinidumpYAML, ExceptionStream_MissingParameter) {
+  SmallString<0> Storage;
+  auto ExpectedFile = toBinary(Storage, R"(
+--- !minidump
+Streams:
+  - Type:            Exception
+    Thread ID:  0x7
+    Exception Record:
+      Exception Code:  0x23
+      Exception Flags: 0x5
+      Exception Record: 0x0102030405060708
+      Exception Address: 0x0a0b0c0d0e0f1011
+      Number Parameters: 4
+      Parameter 0: 0x99
+      Parameter 1: 0x23
+      Parameter 2: 0x42
+    Thread Context:  3DeadBeefDefacedABadCafe)");
+  ASSERT_FALSE(ExpectedFile);
+  auto Unhandled =
+      handleErrors(ExpectedFile.takeError(), [](const StringError &error) {
+        EXPECT_EQ(static_cast<int>(std::errc::invalid_argument),
+                  error.convertToErrorCode().value());
+      });
+  EXPECT_THAT_ERROR(std::move(Unhandled), Succeeded());
+}
+
+TEST(MinidumpYAML, ExceptionStream_ExtraParameter) {
+  SmallString<0> Storage;
+  auto ExpectedFile = toBinary(Storage, R"(
+--- !minidump
+Streams:
+  - Type:            Exception
+    Thread ID:  0x7
+    Exception Record:
+      Exception Code:  0x23
+      Exception Flags: 0x5
+      Exception Record: 0x0102030405060708
+      Exception Address: 0x0a0b0c0d0e0f1011
+      Number Parameters: 2
+      Parameter 0: 0x99
+      Parameter 1: 0x23
+      Parameter 2: 0x42
+    Thread Context:  3DeadBeefDefacedABadCafe)");
+  ASSERT_THAT_EXPECTED(ExpectedFile, Succeeded());
+  object::MinidumpFile &File = **ExpectedFile;
+
+  ASSERT_EQ(1u, File.streams().size());
+
+  Expected<const minidump::ExceptionStream &> ExpectedStream =
+      File.getExceptionStream();
+
+  ASSERT_THAT_EXPECTED(ExpectedStream, Succeeded());
+
+  const minidump::ExceptionStream &Stream = *ExpectedStream;
+  EXPECT_EQ(0x7u, Stream.ThreadId);
+  const minidump::Exception &Exception = Stream.ExceptionRecord;
+  EXPECT_EQ(0x23u, Exception.ExceptionCode);
+  EXPECT_EQ(0x5u, Exception.ExceptionFlags);
+  EXPECT_EQ(0x0102030405060708u, Exception.ExceptionRecord);
+  EXPECT_EQ(0x0a0b0c0d0e0f1011u, Exception.ExceptionAddress);
+  EXPECT_EQ(2u, Exception.NumberParameters);
+  EXPECT_EQ(0x99u, Exception.ExceptionInformation[0]);
+  EXPECT_EQ(0x23u, Exception.ExceptionInformation[1]);
+  EXPECT_EQ(0x42u, Exception.ExceptionInformation[2]);
+
+  Expected<ArrayRef<uint8_t>> ExpectedContext =
+      File.getRawData(Stream.ThreadContext);
+  ASSERT_THAT_EXPECTED(ExpectedContext, Succeeded());
+  EXPECT_EQ((ArrayRef<uint8_t>{0x3d, 0xea, 0xdb, 0xee, 0xfd, 0xef, 0xac, 0xed,
+                               0xab, 0xad, 0xca, 0xfe}),
+            *ExpectedContext);
+}
Index: llvm/lib/ObjectYAML/MinidumpYAML.cpp
===================================================================
--- llvm/lib/ObjectYAML/MinidumpYAML.cpp
+++ llvm/lib/ObjectYAML/MinidumpYAML.cpp
@@ -8,6 +8,7 @@
 
 #include "llvm/ObjectYAML/MinidumpYAML.h"
 #include "llvm/Support/Allocator.h"
+#include "llvm/Support/FormatVariadic.h"
 
 using namespace llvm;
 using namespace llvm::MinidumpYAML;
@@ -69,6 +70,8 @@
 
 Stream::StreamKind Stream::getKind(StreamType Type) {
   switch (Type) {
+  case StreamType::Exception:
+    return StreamKind::Exception;
   case StreamType::MemoryInfoList:
     return StreamKind::MemoryInfoList;
   case StreamType::MemoryList:
@@ -95,6 +98,8 @@
 std::unique_ptr<Stream> Stream::create(StreamType Type) {
   StreamKind Kind = getKind(Type);
   switch (Kind) {
+  case StreamKind::Exception:
+    return std::make_unique<ExceptionStream>();
   case StreamKind::MemoryInfoList:
     return std::make_unique<MemoryInfoListStream>();
   case StreamKind::MemoryList:
@@ -367,6 +372,46 @@
   IO.mapRequired("Threads", Stream.Entries);
 }
 
+static void streamMapping(yaml::IO &IO, MinidumpYAML::ExceptionStream &Stream) {
+  mapRequiredHex(IO, "Thread ID", Stream.MDExceptionStream.ThreadId);
+  IO.mapRequired("Exception Record", Stream.MDExceptionStream.ExceptionRecord);
+  // TODO: We could provide a reasonable default for ThreadContext by searching
+  // the Thread stream for a thread with the given ID and using its Context.
+  // That would require a couple changes:
+  //   1. We'd need to pass the whole dump around as a context argument.
+  //   2. We'd need to ensure that the Thread stream got processed before
+  //      the Exception stream (or make Exception's ThreadContext required
+  //      when the Exception stream is processed before the Thread stream).
+  IO.mapRequired("Thread Context", Stream.ThreadContext);
+}
+
+void yaml::MappingTraits<minidump::Exception>::mapping(
+    yaml::IO &IO, minidump::Exception &Exception) {
+  mapRequiredHex(IO, "Exception Code", Exception.ExceptionCode);
+  mapOptionalHex(IO, "Exception Flags", Exception.ExceptionFlags, 0);
+  mapOptionalHex(IO, "Exception Record", Exception.ExceptionRecord, 0);
+  mapOptionalHex(IO, "Exception Address", Exception.ExceptionAddress, 0);
+  IO.mapOptional("Number Parameters", Exception.NumberParameters,
+                 support::ulittle32_t(0u));
+
+  for (size_t Index = 0; Index < Exception.MaxParameters; ++Index) {
+    SmallString<16> Name = formatv("Parameter {0}", Index);
+    support::ulittle64_t &Field = Exception.ExceptionInformation[Index];
+
+    if (Index < Exception.NumberParameters)
+      mapRequiredHex(IO, Name.c_str(), Field);
+    else
+      mapOptionalHex(IO, Name.c_str(), Field, 0);
+  }
+}
+
+StringRef yaml::MappingTraits<minidump::Exception>::validate(
+    yaml::IO &IO, minidump::Exception &Exception) {
+  if (Exception.NumberParameters > Exception::MaxParameters)
+    return "Exception reports too many parameters";
+  return "";
+}
+
 void yaml::MappingTraits<std::unique_ptr<Stream>>::mapping(
     yaml::IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S) {
   StreamType Type;
@@ -377,6 +422,9 @@
   if (!IO.outputting())
     S = MinidumpYAML::Stream::create(Type);
   switch (S->Kind) {
+  case MinidumpYAML::Stream::StreamKind::Exception:
+    streamMapping(IO, llvm::cast<MinidumpYAML::ExceptionStream>(*S));
+    break;
   case MinidumpYAML::Stream::StreamKind::MemoryInfoList:
     streamMapping(IO, llvm::cast<MemoryInfoListStream>(*S));
     break;
@@ -406,6 +454,7 @@
   switch (S->Kind) {
   case MinidumpYAML::Stream::StreamKind::RawContent:
     return streamValidate(cast<RawContentStream>(*S));
+  case MinidumpYAML::Stream::StreamKind::Exception:
   case MinidumpYAML::Stream::StreamKind::MemoryInfoList:
   case MinidumpYAML::Stream::StreamKind::MemoryList:
   case MinidumpYAML::Stream::StreamKind::ModuleList:
@@ -481,6 +530,17 @@
     return std::make_unique<SystemInfoStream>(*ExpectedInfo,
                                                std::move(*ExpectedCSDVersion));
   }
+  case StreamKind::Exception: {
+    auto ExpectedExceptionStream = File.getExceptionStream();
+    if (!ExpectedExceptionStream)
+      return ExpectedExceptionStream.takeError();
+    auto ExpectedThreadContext =
+        File.getRawData(ExpectedExceptionStream->ThreadContext);
+    if (!ExpectedThreadContext)
+      return ExpectedThreadContext.takeError();
+    return std::make_unique<ExceptionStream>(*ExpectedExceptionStream,
+                                             *ExpectedThreadContext);
+  }
   case StreamKind::TextContent:
     return std::make_unique<TextContentStream>(
         StreamDesc.Type, toStringRef(File.getRawStream(StreamDesc)));
Index: llvm/lib/ObjectYAML/MinidumpEmitter.cpp
===================================================================
--- llvm/lib/ObjectYAML/MinidumpEmitter.cpp
+++ llvm/lib/ObjectYAML/MinidumpEmitter.cpp
@@ -118,6 +118,23 @@
           support::ulittle32_t(File.allocateBytes(Data))};
 }
 
+static size_t layout(BlobAllocator &File, MinidumpYAML::ExceptionStream &S) {
+  File.allocateObject(S.MDExceptionStream);
+
+  size_t DataEnd = File.tell();
+
+  // Lay out the thread context data, (which is not a part of the stream).
+  // TODO: This usually (always?) matches the thread context of the
+  // corresponding thread, and may overlap memory regions as well.  We could
+  // add a level of indirection to the MinidumpYAML format (like an array of
+  // Blobs that the LocationDescriptors index into) to be able to distinguish
+  // the cases where location descriptions overlap vs happen to reference
+  // identical data.
+  S.MDExceptionStream.ThreadContext = layout(File, S.ThreadContext);
+
+  return DataEnd;
+}
+
 static void layout(BlobAllocator &File, MemoryListStream::entry_type &Range) {
   Range.Entry.Memory = layout(File, Range.Content);
 }
@@ -158,6 +175,9 @@
   Result.Location.RVA = File.tell();
   Optional<size_t> DataEnd;
   switch (S.Kind) {
+  case Stream::StreamKind::Exception:
+    DataEnd = layout(File, cast<MinidumpYAML::ExceptionStream>(S));
+    break;
   case Stream::StreamKind::MemoryInfoList: {
     MemoryInfoListStream &InfoList = cast<MemoryInfoListStream>(S);
     File.allocateNewObject<minidump::MemoryInfoListHeader>(
Index: llvm/include/llvm/ObjectYAML/MinidumpYAML.h
===================================================================
--- llvm/include/llvm/ObjectYAML/MinidumpYAML.h
+++ llvm/include/llvm/ObjectYAML/MinidumpYAML.h
@@ -26,6 +26,7 @@
 /// from Types to Kinds is fixed and given by the static getKind function.
 struct Stream {
   enum class StreamKind {
+    Exception,
     MemoryInfoList,
     MemoryList,
     ModuleList,
@@ -158,6 +159,26 @@
   }
 };
 
+/// ExceptionStream minidump stream.
+struct ExceptionStream : public Stream {
+  minidump::ExceptionStream MDExceptionStream;
+  yaml::BinaryRef ThreadContext;
+
+  explicit ExceptionStream(const minidump::ExceptionStream &MDExceptionStream,
+                           ArrayRef<uint8_t> ThreadContext)
+      : Stream(StreamKind::Exception, minidump::StreamType::Exception),
+        MDExceptionStream(MDExceptionStream), ThreadContext(ThreadContext) {}
+
+  ExceptionStream()
+      : Stream(StreamKind::Exception, minidump::StreamType::Exception) {
+    memset(&MDExceptionStream, 0, sizeof(minidump::ExceptionStream));
+  }
+
+  static bool classof(const Stream *S) {
+    return S->Kind == StreamKind::Exception;
+  }
+};
+
 /// A StringRef, which is printed using YAML block notation.
 LLVM_YAML_STRONG_TYPEDEF(StringRef, BlockStringRef)
 
@@ -219,6 +240,11 @@
   static StringRef validate(IO &IO, std::unique_ptr<MinidumpYAML::Stream> &S);
 };
 
+template <> struct MappingTraits<minidump::Exception> {
+  static void mapping(IO &IO, minidump::Exception &Exception);
+  static StringRef validate(IO &IO, minidump::Exception &Exception);
+};
+
 template <> struct MappingContextTraits<minidump::MemoryDescriptor, BinaryRef> {
   static void mapping(IO &IO, minidump::MemoryDescriptor &Memory,
                       BinaryRef &Content);
Index: lldb/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64.yaml
===================================================================
--- lldb/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64.yaml
+++ lldb/packages/Python/lldbsuite/test/functionalities/postmortem/minidump-new/linux-x86_64.yaml
@@ -14,7 +14,10 @@
         Module Name:     '/tmp/test/linux-x86_64'
         CodeView Record: 4C457042E35C283BC327C28762DB788BF5A4078BE2351448
   - Type:            Exception
-    Content:         DD740000000000000B00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000D0040000F8310000
+    Thread ID:       0x000074DD
+    Exception Record:
+      Exception Code:  0x0000000B
+    Thread Context:  00000000
   - Type:            SystemInfo
     Processor Arch:  AMD64
     Processor Level: 6
_______________________________________________
lldb-commits mailing list
lldb-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits

Reply via email to