diff --git a/src/processor/minidump.cc b/src/processor/minidump.cc index 1f479558..aa63fe47 100644 --- a/src/processor/minidump.cc +++ b/src/processor/minidump.cc @@ -444,140 +444,30 @@ MinidumpContext::MinidumpContext(Minidump* minidump) MinidumpContext::~MinidumpContext() { } bool MinidumpContext::Read(uint32_t expected_size) { valid_ = false; // Certain raw context types are currently assumed to have unique sizes. - if (!IsContextSizeUnique(sizeof(MDRawContextAMD64))) { - BPLOG(ERROR) << "sizeof(MDRawContextAMD64) cannot match the size of any " - << "other raw context"; - return false; - } if (!IsContextSizeUnique(sizeof(MDRawContextPPC64))) { BPLOG(ERROR) << "sizeof(MDRawContextPPC64) cannot match the size of any " << "other raw context"; return false; } if (!IsContextSizeUnique(sizeof(MDRawContextARM64_Old))) { BPLOG(ERROR) << "sizeof(MDRawContextARM64_Old) cannot match the size of any " << "other raw context"; return false; } FreeContext(); - // 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)) { - BPLOG(INFO) << "MinidumpContext: looks like AMD64 context"; - - scoped_ptr context_amd64(new MDRawContextAMD64()); - if (!minidump_->ReadBytes(context_amd64.get(), - sizeof(MDRawContextAMD64))) { - BPLOG(ERROR) << "MinidumpContext could not read amd64 context"; - 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; - } - } - - if (cpu_type != MD_CONTEXT_AMD64) { - // TODO: Fall through to switch below. - // https://bugs.chromium.org/p/google-breakpad/issues/detail?id=550 - BPLOG(ERROR) << "MinidumpContext not actually amd64 context"; - return false; - } - - // Do this after reading the entire MDRawContext structure because - // GetSystemInfo may seek minidump to a new position. - if (!CheckAgainstSystemInfo(cpu_type)) { - BPLOG(ERROR) << "MinidumpContext amd64 does not match system info"; - return false; - } - - // Normalize the 128-bit types in the dump. - // Since this is AMD64, by definition, the values are little-endian. - for (unsigned int vr_index = 0; - vr_index < MD_CONTEXT_AMD64_VR_COUNT; - ++vr_index) - Normalize128(&context_amd64->vector_register[vr_index], false); - - if (minidump_->swap()) { - Swap(&context_amd64->p1_home); - Swap(&context_amd64->p2_home); - Swap(&context_amd64->p3_home); - Swap(&context_amd64->p4_home); - Swap(&context_amd64->p5_home); - Swap(&context_amd64->p6_home); - // context_flags is already swapped - Swap(&context_amd64->mx_csr); - Swap(&context_amd64->cs); - Swap(&context_amd64->ds); - Swap(&context_amd64->es); - Swap(&context_amd64->fs); - Swap(&context_amd64->ss); - Swap(&context_amd64->eflags); - Swap(&context_amd64->dr0); - Swap(&context_amd64->dr1); - Swap(&context_amd64->dr2); - Swap(&context_amd64->dr3); - Swap(&context_amd64->dr6); - Swap(&context_amd64->dr7); - Swap(&context_amd64->rax); - Swap(&context_amd64->rcx); - Swap(&context_amd64->rdx); - Swap(&context_amd64->rbx); - Swap(&context_amd64->rsp); - Swap(&context_amd64->rbp); - Swap(&context_amd64->rsi); - Swap(&context_amd64->rdi); - Swap(&context_amd64->r8); - Swap(&context_amd64->r9); - Swap(&context_amd64->r10); - Swap(&context_amd64->r11); - Swap(&context_amd64->r12); - Swap(&context_amd64->r13); - Swap(&context_amd64->r14); - Swap(&context_amd64->r15); - Swap(&context_amd64->rip); - // FIXME: I'm not sure what actually determines - // which member of the union {flt_save, sse_registers} - // is valid. We're not currently using either, - // but it would be good to have them swapped properly. - - for (unsigned int vr_index = 0; - vr_index < MD_CONTEXT_AMD64_VR_COUNT; - ++vr_index) - Swap(&context_amd64->vector_register[vr_index]); - Swap(&context_amd64->vector_control); - Swap(&context_amd64->debug_control); - Swap(&context_amd64->last_branch_to_rip); - Swap(&context_amd64->last_branch_from_rip); - Swap(&context_amd64->last_exception_to_rip); - Swap(&context_amd64->last_exception_from_rip); - } - - SetContextFlags(context_amd64->context_flags); - - SetContextAMD64(context_amd64.release()); - } else if (expected_size == sizeof(MDRawContextPPC64)) { + if (expected_size == sizeof(MDRawContextPPC64)) { // |context_flags| of MDRawContextPPC64 is 64 bits, but other MDRawContext // in the else case have 32 bits |context_flags|, so special case it here. uint64_t context_flags; if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) { BPLOG(ERROR) << "MinidumpContext could not read context flags"; return false; } if (minidump_->swap()) @@ -739,56 +629,152 @@ bool MinidumpContext::Read(uint32_t expected_size) { } } scoped_ptr new_context(new MDRawContextARM64()); ConvertOldARM64Context(*context_arm64.get(), new_context.get()); SetContextFlags(new_context->context_flags); SetContextARM64(new_context.release()); } else { - uint32_t context_flags; - if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) { - BPLOG(ERROR) << "MinidumpContext could not read context flags"; + uint32_t cpu_type = 0; + if (!minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { + BPLOG(ERROR) << "Failed to preserve the current stream position"; return false; } - if (minidump_->swap()) - Swap(&context_flags); - uint32_t cpu_type = context_flags & MD_CONTEXT_CPU_MASK; - if (cpu_type == 0) { - // Unfortunately the flag for MD_CONTEXT_ARM that was taken - // from a Windows CE SDK header conflicts in practice with - // the CONTEXT_XSTATE flag. MD_CONTEXT_ARM has been renumbered, - // but handle dumps with the legacy value gracefully here. - if (context_flags & MD_CONTEXT_ARM_OLD) { - context_flags |= MD_CONTEXT_ARM; - context_flags &= ~MD_CONTEXT_ARM_OLD; - cpu_type = MD_CONTEXT_ARM; + uint32_t context_flags = 0; + if ((cpu_type == 0) || cpu_type != MD_CONTEXT_AMD64) { + if (!minidump_->ReadBytes(&context_flags, sizeof(context_flags))) { + BPLOG(ERROR) << "MinidumpContext could not read context flags"; + return false; } - } - if (cpu_type == 0) { - if (minidump_->GetContextCPUFlagsFromSystemInfo(&cpu_type)) { - context_flags |= cpu_type; + if (minidump_->swap()) + Swap(&context_flags); + + if ((context_flags & MD_CONTEXT_CPU_MASK) == 0) { + // Unfortunately the flag for MD_CONTEXT_ARM that was taken + // from a Windows CE SDK header conflicts in practice with + // the CONTEXT_XSTATE flag. MD_CONTEXT_ARM has been renumbered, + // but handle dumps with the legacy value gracefully here. + if (context_flags & MD_CONTEXT_ARM_OLD) { + context_flags |= MD_CONTEXT_ARM; + context_flags &= ~MD_CONTEXT_ARM_OLD; + cpu_type = MD_CONTEXT_ARM; + } else { + context_flags |= cpu_type; + } } else { - BPLOG(ERROR) << "Failed to preserve the current stream position"; - return false; + cpu_type = context_flags & MD_CONTEXT_CPU_MASK; } } // Allocate the context structure for the correct CPU and fill it. The // casts are slightly unorthodox, but it seems better to do that than to // maintain a separate pointer for each type of CPU context structure // when only one of them will be used. switch (cpu_type) { + case MD_CONTEXT_AMD64: { + if (expected_size != sizeof(MDRawContextAMD64)) { + BPLOG(INFO) << "MinidumpContext AMD64 size mismatch, " << + expected_size << " != " << sizeof(MDRawContextAMD64); + } + BPLOG(INFO) << "MinidumpContext: looks like AMD64 context"; + + scoped_ptr context_amd64(new MDRawContextAMD64()); + if (!minidump_->ReadBytes(context_amd64.get(), + sizeof(MDRawContextAMD64))) { + BPLOG(ERROR) << "MinidumpContext could not read amd64 context"; + return false; + } + + if (minidump_->swap()) + Swap(&context_amd64->context_flags); + + // Update context_flags since we haven't done it yet + context_flags = context_amd64->context_flags; + + if (cpu_type != (context_flags & MD_CONTEXT_CPU_MASK)) { + BPLOG(ERROR) << "MinidumpContext amd64 does not match system info"; + return false; + } + + // Normalize the 128-bit types in the dump. + // Since this is AMD64, by definition, the values are little-endian. + for (unsigned int vr_index = 0; + vr_index < MD_CONTEXT_AMD64_VR_COUNT; + ++vr_index) + Normalize128(&context_amd64->vector_register[vr_index], false); + + if (minidump_->swap()) { + Swap(&context_amd64->p1_home); + Swap(&context_amd64->p2_home); + Swap(&context_amd64->p3_home); + Swap(&context_amd64->p4_home); + Swap(&context_amd64->p5_home); + Swap(&context_amd64->p6_home); + // context_flags is already swapped + Swap(&context_amd64->mx_csr); + Swap(&context_amd64->cs); + Swap(&context_amd64->ds); + Swap(&context_amd64->es); + Swap(&context_amd64->fs); + Swap(&context_amd64->ss); + Swap(&context_amd64->eflags); + Swap(&context_amd64->dr0); + Swap(&context_amd64->dr1); + Swap(&context_amd64->dr2); + Swap(&context_amd64->dr3); + Swap(&context_amd64->dr6); + Swap(&context_amd64->dr7); + Swap(&context_amd64->rax); + Swap(&context_amd64->rcx); + Swap(&context_amd64->rdx); + Swap(&context_amd64->rbx); + Swap(&context_amd64->rsp); + Swap(&context_amd64->rbp); + Swap(&context_amd64->rsi); + Swap(&context_amd64->rdi); + Swap(&context_amd64->r8); + Swap(&context_amd64->r9); + Swap(&context_amd64->r10); + Swap(&context_amd64->r11); + Swap(&context_amd64->r12); + Swap(&context_amd64->r13); + Swap(&context_amd64->r14); + Swap(&context_amd64->r15); + Swap(&context_amd64->rip); + // FIXME: I'm not sure what actually determines + // which member of the union {flt_save, sse_registers} + // is valid. We're not currently using either, + // but it would be good to have them swapped properly. + + for (unsigned int vr_index = 0; + vr_index < MD_CONTEXT_AMD64_VR_COUNT; + ++vr_index) + Swap(&context_amd64->vector_register[vr_index]); + Swap(&context_amd64->vector_control); + Swap(&context_amd64->debug_control); + Swap(&context_amd64->last_branch_to_rip); + Swap(&context_amd64->last_branch_from_rip); + Swap(&context_amd64->last_exception_to_rip); + Swap(&context_amd64->last_exception_from_rip); + } + + SetContextFlags(context_amd64->context_flags); + + SetContextAMD64(context_amd64.release()); + minidump_->SeekSet( + (minidump_->Tell() - sizeof(MDRawContextAMD64)) + expected_size); + break; + } case MD_CONTEXT_X86: { if (expected_size != sizeof(MDRawContextX86)) { - BPLOG(ERROR) << "MinidumpContext x86 size mismatch, " << + BPLOG(INFO) << "MinidumpContext x86 size mismatch, " << expected_size << " != " << sizeof(MDRawContextX86); - return false; } scoped_ptr context_x86(new MDRawContextX86()); // Set the context_flags member, which has already been read, and // read the rest of the structure beginning with the first member // after context_flags. context_x86->context_flags = context_flags; @@ -843,16 +829,18 @@ bool MinidumpContext::Read(uint32_t expected_size) { Swap(&context_x86->eflags); Swap(&context_x86->esp); Swap(&context_x86->ss); // context_x86->extended_registers[] contains 8-bit quantities and // does not need to be swapped. } SetContextX86(context_x86.release()); + minidump_->SeekSet( + (minidump_->Tell() - sizeof(MDRawContextX86)) + expected_size); break; } case MD_CONTEXT_PPC: { if (expected_size != sizeof(MDRawContextPPC)) { BPLOG(ERROR) << "MinidumpContext ppc size mismatch, " << expected_size << " != " << sizeof(MDRawContextPPC); -- 2.26.2