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
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/lldb-commits