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 <rsesek@chromium.org>
This commit is contained in:
Alex Gough 2021-11-02 20:14:52 +00:00 committed by Robert Sesek
parent ee2ad61263
commit fe35cd43f2
3 changed files with 49 additions and 13 deletions

View file

@ -470,7 +470,16 @@ bool MinidumpContext::Read(uint32_t expected_size) {
// First, figure out what type of CPU this context structure is for. // First, figure out what type of CPU this context structure is for.
// For some reason, the AMD64 Context doesn't have context_flags // For some reason, the AMD64 Context doesn't have context_flags
// at the beginning of the structure, so special case it here. // 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"; BPLOG(INFO) << "MinidumpContext: looks like AMD64 context";
scoped_ptr<MDRawContextAMD64> context_amd64(new MDRawContextAMD64()); scoped_ptr<MDRawContextAMD64> context_amd64(new MDRawContextAMD64());
@ -480,17 +489,24 @@ bool MinidumpContext::Read(uint32_t expected_size) {
return false; 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<uint8_t> xstate(bytes_left);
if (!minidump_->ReadBytes(xstate.data(),
bytes_left)) {
BPLOG(ERROR) << "MinidumpContext could not skip amd64 xstate";
return false;
}
}
if (minidump_->swap()) if (minidump_->swap())
Swap(&context_amd64->context_flags); Swap(&context_amd64->context_flags);
uint32_t cpu_type = context_amd64->context_flags & MD_CONTEXT_CPU_MASK; uint32_t cpu_type = context_amd64->context_flags & MD_CONTEXT_CPU_MASK;
if (cpu_type == 0) { if (cpu_type == 0) {
if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { context_amd64->context_flags |= sysinfo_cpu_type;
context_amd64->context_flags |= cpu_type;
} else {
BPLOG(ERROR) << "Failed to preserve the current stream position";
return false;
}
} }
if (cpu_type != MD_CONTEXT_AMD64) { 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 (cpu_type == 0) {
if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { cpu_type = sysinfo_cpu_type;
context_flags |= cpu_type; context_flags |= cpu_type;
} else {
BPLOG(ERROR) << "Failed to preserve the current stream position";
return false;
}
} }
// Allocate the context structure for the correct CPU and fill it. The // Allocate the context structure for the correct CPU and fill it. The

View file

@ -761,6 +761,29 @@ TEST_F(MinidumpProcessorTest, Test32BitCrashingAddress) {
ASSERT_EQ(state.crash_address(), 0x45U); 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 } // namespace
int main(int argc, char* argv[]) { int main(int argc, char* argv[]) {

Binary file not shown.