Index: minidump/minidump_thread_writer_test.cc |
diff --git a/minidump/minidump_thread_writer_test.cc b/minidump/minidump_thread_writer_test.cc |
index 6dc065e76b6abdff31d3d03ac611f8c65dd90482..a74307e90222c0ef5889c229b5b7daeaea481013 100644 |
--- a/minidump/minidump_thread_writer_test.cc |
+++ b/minidump/minidump_thread_writer_test.cc |
@@ -17,14 +17,19 @@ |
#include <dbghelp.h> |
#include <sys/types.h> |
+#include "base/strings/stringprintf.h" |
#include "gtest/gtest.h" |
#include "minidump/minidump_context_writer.h" |
#include "minidump/minidump_memory_writer.h" |
#include "minidump/minidump_file_writer.h" |
+#include "minidump/minidump_thread_id_map.h" |
#include "minidump/test/minidump_context_test_util.h" |
#include "minidump/test/minidump_memory_writer_test_util.h" |
#include "minidump/test/minidump_file_writer_test_util.h" |
#include "minidump/test/minidump_writable_test_util.h" |
+#include "snapshot/test/test_cpu_context.h" |
+#include "snapshot/test/test_memory_snapshot.h" |
+#include "snapshot/test/test_thread_snapshot.h" |
#include "util/file/string_file_writer.h" |
namespace crashpad { |
@@ -475,6 +480,186 @@ TEST(MinidumpThreadWriter, ThreeThreads_x86_MemoryList) { |
} |
} |
+struct InitializeFromSnapshotX86Traits { |
+ typedef MinidumpContextX86 MinidumpContextType; |
+ static void InitializeCPUContext(CPUContext* context, uint32_t seed) { |
+ return InitializeCPUContextX86(context, seed); |
+ } |
+ static void ExpectMinidumpContext( |
+ uint32_t expect_seed, const MinidumpContextX86* observed, bool snapshot) { |
+ return ExpectMinidumpContextX86(expect_seed, observed, snapshot); |
+ } |
+}; |
+ |
+struct InitializeFromSnapshotAMD64Traits { |
+ typedef MinidumpContextAMD64 MinidumpContextType; |
+ static void InitializeCPUContext(CPUContext* context, uint32_t seed) { |
+ return InitializeCPUContextX86_64(context, seed); |
+ } |
+ static void ExpectMinidumpContext(uint32_t expect_seed, |
+ const MinidumpContextAMD64* observed, |
+ bool snapshot) { |
+ return ExpectMinidumpContextAMD64(expect_seed, observed, snapshot); |
+ } |
+}; |
+ |
+struct InitializeFromSnapshotNoContextTraits { |
+ typedef MinidumpContextX86 MinidumpContextType; |
+ static void InitializeCPUContext(CPUContext* context, uint32_t seed) { |
+ context->architecture = kCPUArchitectureUnknown; |
+ } |
+ static void ExpectMinidumpContext(uint32_t expect_seed, |
+ const MinidumpContextX86* observed, |
+ bool snapshot) { |
+ FAIL(); |
+ } |
+}; |
+ |
+template <typename Traits> |
+void RunInitializeFromSnapshotTest(bool thread_id_collision) { |
+ typedef typename Traits::MinidumpContextType MinidumpContextType; |
+ MINIDUMP_THREAD expect_threads[3] = {}; |
+ uint64_t thread_ids[arraysize(expect_threads)] = {}; |
+ uint8_t memory_values[arraysize(expect_threads)] = {}; |
+ uint32_t context_seeds[arraysize(expect_threads)] = {}; |
+ |
+ expect_threads[0].ThreadId = 1; |
+ expect_threads[0].SuspendCount = 2; |
+ expect_threads[0].Priority = 3; |
+ expect_threads[0].Teb = 0x0123456789abcdef; |
+ expect_threads[0].Stack.StartOfMemoryRange = 0x1000; |
+ expect_threads[0].Stack.Memory.DataSize = 0x100; |
+ expect_threads[0].ThreadContext.DataSize = sizeof(MinidumpContextType); |
+ memory_values[0] = 'A'; |
+ context_seeds[0] = 0x80000000; |
+ |
+ // The thread at index 1 has no stack. |
+ expect_threads[1].ThreadId = 11; |
+ expect_threads[1].SuspendCount = 12; |
+ expect_threads[1].Priority = 13; |
+ expect_threads[1].Teb = 0xfedcba9876543210; |
+ expect_threads[1].ThreadContext.DataSize = sizeof(MinidumpContextType); |
+ context_seeds[1] = 0x40000001; |
+ |
+ expect_threads[2].ThreadId = 21; |
+ expect_threads[2].SuspendCount = 22; |
+ expect_threads[2].Priority = 23; |
+ expect_threads[2].Teb = 0x1111111111111111; |
+ expect_threads[2].Stack.StartOfMemoryRange = 0x3000; |
+ expect_threads[2].Stack.Memory.DataSize = 0x300; |
+ expect_threads[2].ThreadContext.DataSize = sizeof(MinidumpContextType); |
+ memory_values[2] = 'd'; |
+ context_seeds[2] = 0x20000002; |
+ |
+ if (thread_id_collision) { |
+ thread_ids[0] = 0x0123456700000001; |
+ thread_ids[1] = 0x89abcdef00000001; |
+ thread_ids[2] = 4; |
+ expect_threads[0].ThreadId = 0; |
+ expect_threads[1].ThreadId = 1; |
+ expect_threads[2].ThreadId = 2; |
+ } else { |
+ thread_ids[0] = 1; |
+ thread_ids[1] = 11; |
+ thread_ids[2] = 22; |
+ expect_threads[0].ThreadId = thread_ids[0]; |
+ expect_threads[1].ThreadId = thread_ids[1]; |
+ expect_threads[2].ThreadId = thread_ids[2]; |
+ } |
+ |
+ PointerVector<TestThreadSnapshot> thread_snapshots_owner; |
+ std::vector<const ThreadSnapshot*> thread_snapshots; |
+ for (size_t index = 0; index < arraysize(expect_threads); ++index) { |
+ TestThreadSnapshot* thread_snapshot = new TestThreadSnapshot(); |
+ thread_snapshots_owner.push_back(thread_snapshot); |
+ |
+ thread_snapshot->SetThreadID(thread_ids[index]); |
+ thread_snapshot->SetSuspendCount(expect_threads[index].SuspendCount); |
+ thread_snapshot->SetPriority(expect_threads[index].Priority); |
+ thread_snapshot->SetThreadSpecificDataAddress(expect_threads[index].Teb); |
+ |
+ if (expect_threads[index].Stack.Memory.DataSize) { |
+ auto memory_snapshot = make_scoped_ptr(new TestMemorySnapshot()); |
+ memory_snapshot->SetAddress( |
+ expect_threads[index].Stack.StartOfMemoryRange); |
+ memory_snapshot->SetSize(expect_threads[index].Stack.Memory.DataSize); |
+ memory_snapshot->SetValue(memory_values[index]); |
+ thread_snapshot->SetStack(memory_snapshot.Pass()); |
+ } |
+ |
+ Traits::InitializeCPUContext(thread_snapshot->MutableContext(), |
+ context_seeds[index]); |
+ |
+ thread_snapshots.push_back(thread_snapshot); |
+ } |
+ |
+ auto thread_list_writer = make_scoped_ptr(new MinidumpThreadListWriter()); |
+ auto memory_list_writer = make_scoped_ptr(new MinidumpMemoryListWriter()); |
+ thread_list_writer->SetMemoryListWriter(memory_list_writer.get()); |
+ MinidumpThreadIDMap thread_id_map; |
+ thread_list_writer->InitializeFromSnapshot(thread_snapshots, &thread_id_map); |
+ |
+ MinidumpFileWriter minidump_file_writer; |
+ minidump_file_writer.AddStream(thread_list_writer.Pass()); |
+ minidump_file_writer.AddStream(memory_list_writer.Pass()); |
+ |
+ StringFileWriter file_writer; |
+ ASSERT_TRUE(minidump_file_writer.WriteEverything(&file_writer)); |
+ |
+ const MINIDUMP_THREAD_LIST* thread_list; |
+ const MINIDUMP_MEMORY_LIST* memory_list; |
+ ASSERT_NO_FATAL_FAILURE( |
+ GetThreadListStream(file_writer.string(), &thread_list, &memory_list)); |
+ |
+ ASSERT_EQ(3u, thread_list->NumberOfThreads); |
+ ASSERT_EQ(2u, memory_list->NumberOfMemoryRanges); |
+ |
+ size_t memory_index = 0; |
+ for (size_t index = 0; index < thread_list->NumberOfThreads; ++index) { |
+ SCOPED_TRACE(base::StringPrintf("index %zu", index)); |
+ |
+ const MINIDUMP_MEMORY_DESCRIPTOR* observed_stack; |
+ const MINIDUMP_MEMORY_DESCRIPTOR** observed_stack_p = |
+ expect_threads[index].Stack.Memory.DataSize ? &observed_stack : nullptr; |
+ const MinidumpContextType* observed_context; |
+ ASSERT_NO_FATAL_FAILURE( |
+ ExpectThread(&expect_threads[index], |
+ &thread_list->Threads[index], |
+ file_writer.string(), |
+ observed_stack_p, |
+ reinterpret_cast<const void**>(&observed_context))); |
+ |
+ ASSERT_NO_FATAL_FAILURE(Traits::ExpectMinidumpContext( |
+ context_seeds[index], observed_context, true)); |
+ |
+ if (observed_stack_p) { |
+ ASSERT_NO_FATAL_FAILURE(ExpectMinidumpMemoryDescriptorAndContents( |
+ &expect_threads[index].Stack, |
+ observed_stack, |
+ file_writer.string(), |
+ memory_values[index], |
+ index == thread_list->NumberOfThreads - 1)); |
+ |
+ ASSERT_NO_FATAL_FAILURE(ExpectMinidumpMemoryDescriptor( |
+ observed_stack, &memory_list->MemoryRanges[memory_index])); |
+ |
+ ++memory_index; |
+ } |
+ } |
+} |
+ |
+TEST(MinidumpThreadWriter, InitializeFromSnapshot_x86) { |
+ RunInitializeFromSnapshotTest<InitializeFromSnapshotX86Traits>(false); |
+} |
+ |
+TEST(MinidumpThreadWriter, InitializeFromSnapshot_AMD64) { |
+ RunInitializeFromSnapshotTest<InitializeFromSnapshotAMD64Traits>(false); |
+} |
+ |
+TEST(MinidumpThreadWriter, InitializeFromSnapshot_ThreadIDCollision) { |
+ RunInitializeFromSnapshotTest<InitializeFromSnapshotX86Traits>(true); |
+} |
+ |
TEST(MinidumpThreadWriterDeathTest, NoContext) { |
MinidumpFileWriter minidump_file_writer; |
auto thread_list_writer = make_scoped_ptr(new MinidumpThreadListWriter()); |
@@ -488,6 +673,12 @@ TEST(MinidumpThreadWriterDeathTest, NoContext) { |
ASSERT_DEATH(minidump_file_writer.WriteEverything(&file_writer), "context_"); |
} |
+TEST(MinidumpThreadWriterDeathTest, InitializeFromSnapshot_NoContext) { |
+ ASSERT_DEATH( |
+ RunInitializeFromSnapshotTest<InitializeFromSnapshotNoContextTraits>( |
+ false), "context_"); |
+} |
+ |
} // namespace |
} // namespace test |
} // namespace crashpad |