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:
parent
ee2ad61263
commit
fe35cd43f2
3 changed files with 49 additions and 13 deletions
|
@ -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
|
||||||
|
|
|
@ -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[]) {
|
||||||
|
|
BIN
src/processor/testdata/tiny-exe-with-cet-xsave.dmp
vendored
Normal file
BIN
src/processor/testdata/tiny-exe-with-cet-xsave.dmp
vendored
Normal file
Binary file not shown.
Loading…
Reference in a new issue