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 00000000..9b641afb Binary files /dev/null and b/src/processor/testdata/tiny-exe-with-cet-xsave.dmp differ