From fe35cd43f2c7386704837b686f91a4e3c882664d Mon Sep 17 00:00:00 2001 From: Alex Gough Date: Tue, 2 Nov 2021 20:14:52 +0000 Subject: [PATCH] Allow breakpad to read extended amd64 contexts Minidumps can contain extended, and compacted extended, contexts to include xstate data such as the state of the cet registers cetumsr and cetussp. Previously breakpad would reject dumps with contexts larger than expected. With this chage, breakpad now accepts and reads these minidumps. This change does not yet add processing for this extra data, but will allow any minidumps to be passed on to other processing tools, or be available for manual inspection. See chromium-review.googlesource.com/c/crashpad/crashpad/+/2575920 for motivation. Bug: 1250098 Change-Id: Id67649738ef1c7fb6308e05e6cd8fde790771cb2 Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/3256483 Reviewed-by: Robert Sesek --- src/processor/minidump.cc | 39 ++++++++++++------ src/processor/minidump_processor_unittest.cc | 23 +++++++++++ .../testdata/tiny-exe-with-cet-xsave.dmp | Bin 0 -> 92736 bytes 3 files changed, 49 insertions(+), 13 deletions(-) create mode 100644 src/processor/testdata/tiny-exe-with-cet-xsave.dmp diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc index 11a5fc4c..572c717c 100644 --- a/src/processor/minidump.cc +++ b/src/processor/minidump.cc @@ -470,7 +470,16 @@ bool MinidumpContext::Read(uint32_t expected_size) { // First, figure out what type of CPU this context structure is for. // For some reason, the AMD64 Context doesn't have context_flags // at the beginning of the structure, so special case it here. - if (expected_size == sizeof(MDRawContextAMD64)) { + + uint32_t sysinfo_cpu_type = 0; + if (!minidump_->GetContextCPUFlagsFromSystemInfo(&sysinfo_cpu_type)) { + BPLOG(ERROR) << "Failed to preserve the current stream position"; + return false; + } + + if (expected_size == sizeof(MDRawContextAMD64) || + (sysinfo_cpu_type == MD_CONTEXT_AMD64 && + expected_size >= sizeof(MDRawContextAMD64))) { BPLOG(INFO) << "MinidumpContext: looks like AMD64 context"; scoped_ptr context_amd64(new MDRawContextAMD64()); @@ -480,17 +489,24 @@ bool MinidumpContext::Read(uint32_t expected_size) { return false; } + // Context may include xsave registers and so be larger than + // sizeof(MDRawContextAMD64). For now we skip this extended data. + if (expected_size > sizeof(MDRawContextAMD64)) { + size_t bytes_left = expected_size - sizeof(MDRawContextAMD64); + std::vector xstate(bytes_left); + if (!minidump_->ReadBytes(xstate.data(), + bytes_left)) { + BPLOG(ERROR) << "MinidumpContext could not skip amd64 xstate"; + return false; + } + } + if (minidump_->swap()) Swap(&context_amd64->context_flags); uint32_t cpu_type = context_amd64->context_flags & MD_CONTEXT_CPU_MASK; if (cpu_type == 0) { - if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { - context_amd64->context_flags |= cpu_type; - } else { - BPLOG(ERROR) << "Failed to preserve the current stream position"; - return false; - } + context_amd64->context_flags |= sysinfo_cpu_type; } if (cpu_type != MD_CONTEXT_AMD64) { @@ -765,13 +781,10 @@ bool MinidumpContext::Read(uint32_t expected_size) { } } + // Fixup if we were not provided a cpu type. if (cpu_type == 0) { - if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { - context_flags |= cpu_type; - } else { - BPLOG(ERROR) << "Failed to preserve the current stream position"; - return false; - } + cpu_type = sysinfo_cpu_type; + context_flags |= cpu_type; } // Allocate the context structure for the correct CPU and fill it. The diff --git a/src/processor/minidump_processor_unittest.cc b/src/processor/minidump_processor_unittest.cc index 306c2f0b..775a48ea 100644 --- a/src/processor/minidump_processor_unittest.cc +++ b/src/processor/minidump_processor_unittest.cc @@ -761,6 +761,29 @@ TEST_F(MinidumpProcessorTest, Test32BitCrashingAddress) { ASSERT_EQ(state.crash_address(), 0x45U); } +TEST_F(MinidumpProcessorTest, TestXStateAmd64ContextMinidump) { + // This tests if we can passively process a minidump with cet registers in its + // context. Dump is captured from a toy executable and is readable by windbg. + MinidumpProcessor processor(nullptr, nullptr /*&supplier, &resolver*/); + + string minidump_file = GetTestDataPath() + + "tiny-exe-with-cet-xsave.dmp"; + + ProcessState state; + ASSERT_EQ(processor.Process(minidump_file, &state), + google_breakpad::PROCESS_OK); + ASSERT_EQ(state.system_info()->os, "Windows NT"); + ASSERT_EQ(state.system_info()->os_version, "10.0.22000 282"); + ASSERT_EQ(state.system_info()->cpu, "amd64"); + ASSERT_EQ(state.system_info()->cpu_info, + "family 6 model 140 stepping 1"); + ASSERT_FALSE(state.crashed()); + ASSERT_EQ(state.threads()->size(), size_t(1)); + + // TODO: verify cetumsr and cetussp once these are supported by + // breakpad. +} + } // namespace int main(int argc, char* argv[]) { diff --git a/src/processor/testdata/tiny-exe-with-cet-xsave.dmp b/src/processor/testdata/tiny-exe-with-cet-xsave.dmp new file mode 100644 index 0000000000000000000000000000000000000000..9b641afb64a5022569364de3875d8d24d9f0c692 GIT binary patch literal 92736 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