crashpad/minidump/minidump_context_writer.cc

605 lines
21 KiB
C++
Raw Normal View History

// Copyright 2014 The Crashpad Authors
//
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
// http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.
#include "minidump/minidump_context_writer.h"
#include <windows.h>
#include <dbghelp.h>
#include <stdint.h>
#include <string.h>
#include "base/compiler_specific.h"
#include "base/logging.h"
Use BUILDFLAG for OS checking Use BUILDFLAG(IS_*) instead of defined(OS_*). This was generated mostly mechnically by performing the following steps: - sed -i '' -E -e 's/defined\(OS_/BUILDFLAG(IS_/g' \ -e 's%([ !])OS_([A-Z]+)%\1BUILDFLAG(IS_\2)%g' \ $(git grep -l 'OS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - sed -i '' -e 's/#ifdef BUILDFLAG(/#if BUILDFLAG(/' \ $(git grep -l '#ifdef BUILDFLAG(' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - gsed -i -z -E -e \ 's%(.*)#include "%\1#include "build/buildflag.h"\n#include "%' \ $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - Spot checks to move #include "build/buildflag.h" to the correct parts of files. - sed -i '' -E -e \ 's%^(#include "build/buildflag.h")$%#include "build/build_config.h"\n\1%' \ $(grep -L '^#include "build/build_config.h"$' $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm')) - Add “clang-format off” around tool usage messages. - git cl format - Update mini_chromium to 85ba51f98278 (intermediate step). TESTING ONLY). - for f in $(git grep -l '^#include "build/buildflag.h"$' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm'); do \ grep -v '^#include "build/buildflag.h"$' "${f}" > /tmp/z; \ cp /tmp/z "${f}"; done - git cl format - Update mini_chromium to 735143774c5f (intermediate step). - Update mini_chromium to f41420eb45fa (as checked in). - Update mini_chromium to 6e2f204b4ae1 (as checked in). For ease of review and inspection, each of these steps is uploaded as a new patch set in a review series. This includes an update of mini_chromium to 6e2f204b4ae1: f41420eb45fa Use BUILDFLAG for OS checking 6e2f204b4ae1 Include what you use: string_util.h uses build_config.h Bug: chromium:1234043 Change-Id: Ieef86186f094c64e59b853729737e36982f8cf69 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3400258 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org>
2022-01-19 15:00:24 -05:00
#include "build/build_config.h"
#include "snapshot/cpu_context.h"
#include "util/file/file_writer.h"
Heap-allocate MinidumpContextAMD64Writer objects with proper alignment While making crashpad_minidump_test run in Chromium’s try- and buildbots (https://crbug.com/779790), crashes in the MinidumpThreadWriter.OneThread_AMD64_Stack test were observed in 32-bit x86 Windows builds produced by Clang in the release configuration. These crashes occurred in crashpad::test::InitializeMinidumpContextAMD64, which heap-allocates a MinidumpContextAMD64Writer object. These objects have an alignment requirement of 16, based on the alignment requirement of their MinidumpContextAMD64 member. Although this problem was never observed with MSVC, Clang was making use of the known strict alignment and producing code that depended on it. This code crashed if the requirement was not met. MSVC had raised a warning about this usage (C4316), but the warning was disabled as it did not appear to have any ill effect on code produced by that compiler. The problem surfaced in test code, but heap-allocated MinidumpContextAMD64Writer objects are created in non-test code as well. The impact is limited, because a 32-bit Windows Crashpad handler would not have a need to allocate one of these objects. As a fix, MinidumpContextAMD64Writer is given a custom allocation function (a static “operator new()” member and matching “operator delete()”) that returns properly aligned memory. Change-Id: I0cb924da91716eb01b88ec2ae952a69262cc2de6 Reviewed-on: https://chromium-review.googlesource.com/746539 Reviewed-by: Leonard Mosescu <mosescu@chromium.org>
2017-10-31 22:25:34 -04:00
#include "util/stdlib/aligned_allocator.h"
namespace crashpad {
namespace {
// Sanity-check complex structures to ensure interoperability.
static_assert(sizeof(MinidumpContextX86) == 716, "MinidumpContextX86 size");
static_assert(sizeof(MinidumpContextAMD64) == 1232,
"MinidumpContextAMD64 size");
// These structures can also be checked against definitions in the Windows SDK.
Use BUILDFLAG for OS checking Use BUILDFLAG(IS_*) instead of defined(OS_*). This was generated mostly mechnically by performing the following steps: - sed -i '' -E -e 's/defined\(OS_/BUILDFLAG(IS_/g' \ -e 's%([ !])OS_([A-Z]+)%\1BUILDFLAG(IS_\2)%g' \ $(git grep -l 'OS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - sed -i '' -e 's/#ifdef BUILDFLAG(/#if BUILDFLAG(/' \ $(git grep -l '#ifdef BUILDFLAG(' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - gsed -i -z -E -e \ 's%(.*)#include "%\1#include "build/buildflag.h"\n#include "%' \ $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - Spot checks to move #include "build/buildflag.h" to the correct parts of files. - sed -i '' -E -e \ 's%^(#include "build/buildflag.h")$%#include "build/build_config.h"\n\1%' \ $(grep -L '^#include "build/build_config.h"$' $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm')) - Add “clang-format off” around tool usage messages. - git cl format - Update mini_chromium to 85ba51f98278 (intermediate step). TESTING ONLY). - for f in $(git grep -l '^#include "build/buildflag.h"$' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm'); do \ grep -v '^#include "build/buildflag.h"$' "${f}" > /tmp/z; \ cp /tmp/z "${f}"; done - git cl format - Update mini_chromium to 735143774c5f (intermediate step). - Update mini_chromium to f41420eb45fa (as checked in). - Update mini_chromium to 6e2f204b4ae1 (as checked in). For ease of review and inspection, each of these steps is uploaded as a new patch set in a review series. This includes an update of mini_chromium to 6e2f204b4ae1: f41420eb45fa Use BUILDFLAG for OS checking 6e2f204b4ae1 Include what you use: string_util.h uses build_config.h Bug: chromium:1234043 Change-Id: Ieef86186f094c64e59b853729737e36982f8cf69 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3400258 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org>
2022-01-19 15:00:24 -05:00
#if BUILDFLAG(IS_WIN)
#if defined(ARCH_CPU_X86_FAMILY)
static_assert(sizeof(MinidumpContextX86) == sizeof(WOW64_CONTEXT),
"WOW64_CONTEXT size");
#if defined(ARCH_CPU_X86)
static_assert(sizeof(MinidumpContextX86) == sizeof(CONTEXT), "CONTEXT size");
#elif defined(ARCH_CPU_X86_64)
static_assert(sizeof(MinidumpContextAMD64) == sizeof(CONTEXT), "CONTEXT size");
#endif
#endif // ARCH_CPU_X86_FAMILY
Use BUILDFLAG for OS checking Use BUILDFLAG(IS_*) instead of defined(OS_*). This was generated mostly mechnically by performing the following steps: - sed -i '' -E -e 's/defined\(OS_/BUILDFLAG(IS_/g' \ -e 's%([ !])OS_([A-Z]+)%\1BUILDFLAG(IS_\2)%g' \ $(git grep -l 'OS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - sed -i '' -e 's/#ifdef BUILDFLAG(/#if BUILDFLAG(/' \ $(git grep -l '#ifdef BUILDFLAG(' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - gsed -i -z -E -e \ 's%(.*)#include "%\1#include "build/buildflag.h"\n#include "%' \ $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm') - Spot checks to move #include "build/buildflag.h" to the correct parts of files. - sed -i '' -E -e \ 's%^(#include "build/buildflag.h")$%#include "build/build_config.h"\n\1%' \ $(grep -L '^#include "build/build_config.h"$' $(git grep -l 'BUILDFLAG(IS_' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm')) - Add “clang-format off” around tool usage messages. - git cl format - Update mini_chromium to 85ba51f98278 (intermediate step). TESTING ONLY). - for f in $(git grep -l '^#include "build/buildflag.h"$' '**/*.c' '**/*.cc' '**/*.h' '**/*.m' '**/*.mm'); do \ grep -v '^#include "build/buildflag.h"$' "${f}" > /tmp/z; \ cp /tmp/z "${f}"; done - git cl format - Update mini_chromium to 735143774c5f (intermediate step). - Update mini_chromium to f41420eb45fa (as checked in). - Update mini_chromium to 6e2f204b4ae1 (as checked in). For ease of review and inspection, each of these steps is uploaded as a new patch set in a review series. This includes an update of mini_chromium to 6e2f204b4ae1: f41420eb45fa Use BUILDFLAG for OS checking 6e2f204b4ae1 Include what you use: string_util.h uses build_config.h Bug: chromium:1234043 Change-Id: Ieef86186f094c64e59b853729737e36982f8cf69 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3400258 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Mark Mentovai <mark@chromium.org>
2022-01-19 15:00:24 -05:00
#endif // BUILDFLAG(IS_WIN)
} // namespace
MinidumpContextWriter::~MinidumpContextWriter() {
}
// static
std::unique_ptr<MinidumpContextWriter>
MinidumpContextWriter::CreateFromSnapshot(const CPUContext* context_snapshot) {
std::unique_ptr<MinidumpContextWriter> context;
switch (context_snapshot->architecture) {
case kCPUArchitectureX86: {
MinidumpContextX86Writer* context_x86 = new MinidumpContextX86Writer();
context.reset(context_x86);
context_x86->InitializeFromSnapshot(context_snapshot->x86);
break;
}
case kCPUArchitectureX86_64: {
MinidumpContextAMD64Writer* context_amd64 =
new MinidumpContextAMD64Writer();
context.reset(context_amd64);
context_amd64->InitializeFromSnapshot(context_snapshot->x86_64);
break;
}
case kCPUArchitectureARM: {
context = std::make_unique<MinidumpContextARMWriter>();
reinterpret_cast<MinidumpContextARMWriter*>(context.get())
->InitializeFromSnapshot(context_snapshot->arm);
break;
}
case kCPUArchitectureARM64: {
context = std::make_unique<MinidumpContextARM64Writer>();
reinterpret_cast<MinidumpContextARM64Writer*>(context.get())
->InitializeFromSnapshot(context_snapshot->arm64);
break;
}
case kCPUArchitectureMIPSEL: {
context = std::make_unique<MinidumpContextMIPSWriter>();
reinterpret_cast<MinidumpContextMIPSWriter*>(context.get())
->InitializeFromSnapshot(context_snapshot->mipsel);
break;
}
case kCPUArchitectureMIPS64EL: {
context = std::make_unique<MinidumpContextMIPS64Writer>();
reinterpret_cast<MinidumpContextMIPS64Writer*>(context.get())
->InitializeFromSnapshot(context_snapshot->mips64);
break;
}
case kCPUArchitectureRISCV64: {
context = std::make_unique<MinidumpContextRISCV64Writer>();
reinterpret_cast<MinidumpContextRISCV64Writer*>(context.get())
->InitializeFromSnapshot(context_snapshot->riscv64);
break;
}
default: {
LOG(ERROR) << "unknown context architecture "
<< context_snapshot->architecture;
break;
}
}
return context;
}
size_t MinidumpContextWriter::SizeOfObject() {
DCHECK_GE(state(), kStateFrozen);
return ContextSize();
}
Write compacted xsave contexts in minidumps Adds new structures and offsets for minidump extended contexts. This information will be captured from threads in a later CL so this CL does not yet write different dumps, except in testing. Minidump format for extended compacted contexts has been determined by experiment. Offsets for where to write various parts of the context are hardcoded to 0x550 as this matches values seen in Windows. Offsets for misc_info_5 match those seen in working minidumps that can be opened in windbg. Our hope is that while these could change in future, CPU and OS vendors are unlikely to change them. See doc[0] for a discussion of these fields and offsets in the minidump. See "MANAGING STATE USING THE XSAVE FEATURE SET" Chapter 13 in the Intel SDM[1]. Many of the offsets and sizes of the extended features are provided by cpu specific values. We can access these in Windows using the SDK, and transfer these to the saved extended context which in turn is understandable by windbg. Further information is available from AMD Ch. 18 "Shadow Stacks"[2]. [0] https://docs.google.com/document/d/1Dn8n97r5B7kxYouvujNnPIYd_7QeVHpahSRmB92Qn6g/edit#heading=h.hivqj2jg39y [1] https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4.html. [2] https://www.amd.com/system/files/TechDocs/24593.pdf Bug: 1250098 Change-Id: Ia9041acc379c6d38329ee99737a2a0a77f7a1ee0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3536964 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Alex Gough <ajgo@chromium.org>
2022-05-14 22:40:24 -07:00
size_t MinidumpContextWriter::FreezeAndGetSizeOfObject() {
Freeze();
return SizeOfObject();
}
MinidumpContextX86Writer::MinidumpContextX86Writer()
: MinidumpContextWriter(), context_() {
context_.context_flags = kMinidumpContextX86;
}
MinidumpContextX86Writer::~MinidumpContextX86Writer() {
}
void MinidumpContextX86Writer::InitializeFromSnapshot(
const CPUContextX86* context_snapshot) {
DCHECK_EQ(state(), kStateMutable);
DCHECK_EQ(context_.context_flags, kMinidumpContextX86);
context_.context_flags = kMinidumpContextX86All;
context_.dr0 = context_snapshot->dr0;
context_.dr1 = context_snapshot->dr1;
context_.dr2 = context_snapshot->dr2;
context_.dr3 = context_snapshot->dr3;
context_.dr6 = context_snapshot->dr6;
context_.dr7 = context_snapshot->dr7;
// The contents of context_.fsave effectively alias everything in
// context_.fxsave thats related to x87 FPU state. context_.fsave doesnt
// carry state specific to SSE (or later), such as mxcsr and the xmm
// registers.
CPUContextX86::FxsaveToFsave(context_snapshot->fxsave, &context_.fsave);
context_.gs = context_snapshot->gs;
context_.fs = context_snapshot->fs;
context_.es = context_snapshot->es;
context_.ds = context_snapshot->ds;
context_.edi = context_snapshot->edi;
context_.esi = context_snapshot->esi;
context_.ebx = context_snapshot->ebx;
context_.edx = context_snapshot->edx;
context_.ecx = context_snapshot->ecx;
context_.eax = context_snapshot->eax;
context_.ebp = context_snapshot->ebp;
context_.eip = context_snapshot->eip;
context_.cs = context_snapshot->cs;
context_.eflags = context_snapshot->eflags;
context_.esp = context_snapshot->esp;
context_.ss = context_snapshot->ss;
// This is effectively a memcpy() of a big structure.
context_.fxsave = context_snapshot->fxsave;
}
bool MinidumpContextX86Writer::WriteObject(FileWriterInterface* file_writer) {
DCHECK_EQ(state(), kStateWritable);
return file_writer->Write(&context_, sizeof(context_));
}
size_t MinidumpContextX86Writer::ContextSize() const {
DCHECK_GE(state(), kStateFrozen);
return sizeof(context_);
}
Heap-allocate MinidumpContextAMD64Writer objects with proper alignment While making crashpad_minidump_test run in Chromium’s try- and buildbots (https://crbug.com/779790), crashes in the MinidumpThreadWriter.OneThread_AMD64_Stack test were observed in 32-bit x86 Windows builds produced by Clang in the release configuration. These crashes occurred in crashpad::test::InitializeMinidumpContextAMD64, which heap-allocates a MinidumpContextAMD64Writer object. These objects have an alignment requirement of 16, based on the alignment requirement of their MinidumpContextAMD64 member. Although this problem was never observed with MSVC, Clang was making use of the known strict alignment and producing code that depended on it. This code crashed if the requirement was not met. MSVC had raised a warning about this usage (C4316), but the warning was disabled as it did not appear to have any ill effect on code produced by that compiler. The problem surfaced in test code, but heap-allocated MinidumpContextAMD64Writer objects are created in non-test code as well. The impact is limited, because a 32-bit Windows Crashpad handler would not have a need to allocate one of these objects. As a fix, MinidumpContextAMD64Writer is given a custom allocation function (a static “operator new()” member and matching “operator delete()”) that returns properly aligned memory. Change-Id: I0cb924da91716eb01b88ec2ae952a69262cc2de6 Reviewed-on: https://chromium-review.googlesource.com/746539 Reviewed-by: Leonard Mosescu <mosescu@chromium.org>
2017-10-31 22:25:34 -04:00
static_assert(alignof(MinidumpContextAMD64) >= 16,
"MinidumpContextAMD64 alignment");
static_assert(alignof(MinidumpContextAMD64Writer) >=
alignof(MinidumpContextAMD64),
"MinidumpContextAMD64Writer alignment");
MinidumpContextAMD64Writer::MinidumpContextAMD64Writer()
: MinidumpContextWriter(), context_() {
context_.context_flags = kMinidumpContextAMD64;
}
MinidumpContextAMD64Writer::~MinidumpContextAMD64Writer() {
}
Heap-allocate MinidumpContextAMD64Writer objects with proper alignment While making crashpad_minidump_test run in Chromium’s try- and buildbots (https://crbug.com/779790), crashes in the MinidumpThreadWriter.OneThread_AMD64_Stack test were observed in 32-bit x86 Windows builds produced by Clang in the release configuration. These crashes occurred in crashpad::test::InitializeMinidumpContextAMD64, which heap-allocates a MinidumpContextAMD64Writer object. These objects have an alignment requirement of 16, based on the alignment requirement of their MinidumpContextAMD64 member. Although this problem was never observed with MSVC, Clang was making use of the known strict alignment and producing code that depended on it. This code crashed if the requirement was not met. MSVC had raised a warning about this usage (C4316), but the warning was disabled as it did not appear to have any ill effect on code produced by that compiler. The problem surfaced in test code, but heap-allocated MinidumpContextAMD64Writer objects are created in non-test code as well. The impact is limited, because a 32-bit Windows Crashpad handler would not have a need to allocate one of these objects. As a fix, MinidumpContextAMD64Writer is given a custom allocation function (a static “operator new()” member and matching “operator delete()”) that returns properly aligned memory. Change-Id: I0cb924da91716eb01b88ec2ae952a69262cc2de6 Reviewed-on: https://chromium-review.googlesource.com/746539 Reviewed-by: Leonard Mosescu <mosescu@chromium.org>
2017-10-31 22:25:34 -04:00
// static
void* MinidumpContextAMD64Writer::operator new(size_t size) {
// MinidumpContextAMD64 requests an alignment of 16, which can be larger than
// what standard new provides. This may trigger MSVC warning C4316. As a
// workaround to this language deficiency, provide a custom allocation
// function to allocate a block meeting the alignment requirement.
return AlignedAllocate(alignof(MinidumpContextAMD64Writer), size);
}
// static
void MinidumpContextAMD64Writer::operator delete(void* pointer) {
return AlignedFree(pointer);
}
void MinidumpContextAMD64Writer::InitializeFromSnapshot(
const CPUContextX86_64* context_snapshot) {
DCHECK_EQ(state(), kStateMutable);
DCHECK_EQ(context_.context_flags, kMinidumpContextAMD64);
Write compacted xsave contexts in minidumps Adds new structures and offsets for minidump extended contexts. This information will be captured from threads in a later CL so this CL does not yet write different dumps, except in testing. Minidump format for extended compacted contexts has been determined by experiment. Offsets for where to write various parts of the context are hardcoded to 0x550 as this matches values seen in Windows. Offsets for misc_info_5 match those seen in working minidumps that can be opened in windbg. Our hope is that while these could change in future, CPU and OS vendors are unlikely to change them. See doc[0] for a discussion of these fields and offsets in the minidump. See "MANAGING STATE USING THE XSAVE FEATURE SET" Chapter 13 in the Intel SDM[1]. Many of the offsets and sizes of the extended features are provided by cpu specific values. We can access these in Windows using the SDK, and transfer these to the saved extended context which in turn is understandable by windbg. Further information is available from AMD Ch. 18 "Shadow Stacks"[2]. [0] https://docs.google.com/document/d/1Dn8n97r5B7kxYouvujNnPIYd_7QeVHpahSRmB92Qn6g/edit#heading=h.hivqj2jg39y [1] https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4.html. [2] https://www.amd.com/system/files/TechDocs/24593.pdf Bug: 1250098 Change-Id: Ia9041acc379c6d38329ee99737a2a0a77f7a1ee0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3536964 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Alex Gough <ajgo@chromium.org>
2022-05-14 22:40:24 -07:00
if (context_snapshot->xstate.enabled_features != 0) {
// Extended context.
context_.context_flags =
kMinidumpContextAMD64All | kMinidumpContextAMD64Xstate;
} else {
// Fixed size context - no xsave components.
context_.context_flags = kMinidumpContextAMD64All;
}
context_.mx_csr = context_snapshot->fxsave.mxcsr;
context_.cs = context_snapshot->cs;
context_.fs = context_snapshot->fs;
context_.gs = context_snapshot->gs;
// The top 32 bits of rflags are reserved/unused.
context_.eflags = static_cast<uint32_t>(context_snapshot->rflags);
context_.dr0 = context_snapshot->dr0;
context_.dr1 = context_snapshot->dr1;
context_.dr2 = context_snapshot->dr2;
context_.dr3 = context_snapshot->dr3;
context_.dr6 = context_snapshot->dr6;
context_.dr7 = context_snapshot->dr7;
context_.rax = context_snapshot->rax;
context_.rcx = context_snapshot->rcx;
context_.rdx = context_snapshot->rdx;
context_.rbx = context_snapshot->rbx;
context_.rsp = context_snapshot->rsp;
context_.rbp = context_snapshot->rbp;
context_.rsi = context_snapshot->rsi;
context_.rdi = context_snapshot->rdi;
context_.r8 = context_snapshot->r8;
context_.r9 = context_snapshot->r9;
context_.r10 = context_snapshot->r10;
context_.r11 = context_snapshot->r11;
context_.r12 = context_snapshot->r12;
context_.r13 = context_snapshot->r13;
context_.r14 = context_snapshot->r14;
context_.r15 = context_snapshot->r15;
context_.rip = context_snapshot->rip;
// This is effectively a memcpy() of a big structure.
context_.fxsave = context_snapshot->fxsave;
Write compacted xsave contexts in minidumps Adds new structures and offsets for minidump extended contexts. This information will be captured from threads in a later CL so this CL does not yet write different dumps, except in testing. Minidump format for extended compacted contexts has been determined by experiment. Offsets for where to write various parts of the context are hardcoded to 0x550 as this matches values seen in Windows. Offsets for misc_info_5 match those seen in working minidumps that can be opened in windbg. Our hope is that while these could change in future, CPU and OS vendors are unlikely to change them. See doc[0] for a discussion of these fields and offsets in the minidump. See "MANAGING STATE USING THE XSAVE FEATURE SET" Chapter 13 in the Intel SDM[1]. Many of the offsets and sizes of the extended features are provided by cpu specific values. We can access these in Windows using the SDK, and transfer these to the saved extended context which in turn is understandable by windbg. Further information is available from AMD Ch. 18 "Shadow Stacks"[2]. [0] https://docs.google.com/document/d/1Dn8n97r5B7kxYouvujNnPIYd_7QeVHpahSRmB92Qn6g/edit#heading=h.hivqj2jg39y [1] https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4.html. [2] https://www.amd.com/system/files/TechDocs/24593.pdf Bug: 1250098 Change-Id: Ia9041acc379c6d38329ee99737a2a0a77f7a1ee0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3536964 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Alex Gough <ajgo@chromium.org>
2022-05-14 22:40:24 -07:00
// If XSave features are being recorded store in xsave_entries in xcomp_bv
// order. We will not see features we do not support as we provide flags
// to the OS when first obtaining a snapshot.
if (context_snapshot->xstate.enabled_features & XSTATE_MASK_CET_U) {
auto cet_u = std::make_unique<MinidumpXSaveAMD64CetU>();
cet_u->InitializeFromSnapshot(context_snapshot);
xsave_entries_.push_back(std::move(cet_u));
}
}
size_t MinidumpContextAMD64Writer::Alignment() {
DCHECK_GE(state(), kStateFrozen);
// Match the alignment of MinidumpContextAMD64.
return 16;
}
bool MinidumpContextAMD64Writer::WriteObject(FileWriterInterface* file_writer) {
DCHECK_EQ(state(), kStateWritable);
Write compacted xsave contexts in minidumps Adds new structures and offsets for minidump extended contexts. This information will be captured from threads in a later CL so this CL does not yet write different dumps, except in testing. Minidump format for extended compacted contexts has been determined by experiment. Offsets for where to write various parts of the context are hardcoded to 0x550 as this matches values seen in Windows. Offsets for misc_info_5 match those seen in working minidumps that can be opened in windbg. Our hope is that while these could change in future, CPU and OS vendors are unlikely to change them. See doc[0] for a discussion of these fields and offsets in the minidump. See "MANAGING STATE USING THE XSAVE FEATURE SET" Chapter 13 in the Intel SDM[1]. Many of the offsets and sizes of the extended features are provided by cpu specific values. We can access these in Windows using the SDK, and transfer these to the saved extended context which in turn is understandable by windbg. Further information is available from AMD Ch. 18 "Shadow Stacks"[2]. [0] https://docs.google.com/document/d/1Dn8n97r5B7kxYouvujNnPIYd_7QeVHpahSRmB92Qn6g/edit#heading=h.hivqj2jg39y [1] https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4.html. [2] https://www.amd.com/system/files/TechDocs/24593.pdf Bug: 1250098 Change-Id: Ia9041acc379c6d38329ee99737a2a0a77f7a1ee0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3536964 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Alex Gough <ajgo@chromium.org>
2022-05-14 22:40:24 -07:00
// Note: all sizes here come from our constants, not from untrustworthy data.
std::vector<unsigned char> data(ContextSize());
unsigned char* const buf = data.data();
// CONTEXT always comes first.
DCHECK_LE(sizeof(context_), data.size());
memcpy(buf, &context_, sizeof(context_));
if (xsave_entries_.size() > 0) {
MinidumpContextExHeader context_ex = {{0, 0}, {0, 0}, {0, 0}};
MinidumpXSaveAreaHeader xsave_header = {0, 0, {}};
Write compacted xsave contexts in minidumps Adds new structures and offsets for minidump extended contexts. This information will be captured from threads in a later CL so this CL does not yet write different dumps, except in testing. Minidump format for extended compacted contexts has been determined by experiment. Offsets for where to write various parts of the context are hardcoded to 0x550 as this matches values seen in Windows. Offsets for misc_info_5 match those seen in working minidumps that can be opened in windbg. Our hope is that while these could change in future, CPU and OS vendors are unlikely to change them. See doc[0] for a discussion of these fields and offsets in the minidump. See "MANAGING STATE USING THE XSAVE FEATURE SET" Chapter 13 in the Intel SDM[1]. Many of the offsets and sizes of the extended features are provided by cpu specific values. We can access these in Windows using the SDK, and transfer these to the saved extended context which in turn is understandable by windbg. Further information is available from AMD Ch. 18 "Shadow Stacks"[2]. [0] https://docs.google.com/document/d/1Dn8n97r5B7kxYouvujNnPIYd_7QeVHpahSRmB92Qn6g/edit#heading=h.hivqj2jg39y [1] https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4.html. [2] https://www.amd.com/system/files/TechDocs/24593.pdf Bug: 1250098 Change-Id: Ia9041acc379c6d38329ee99737a2a0a77f7a1ee0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3536964 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Alex Gough <ajgo@chromium.org>
2022-05-14 22:40:24 -07:00
// CONTEXT_EX goes directly after the CONTEXT. |offset| is relative to
// &CONTEXT_EX.
context_ex.all.offset = -static_cast<int32_t>(sizeof(context_));
context_ex.all.size = static_cast<uint32_t>(ContextSize());
context_ex.legacy.offset = context_ex.all.offset;
context_ex.legacy.size = sizeof(context_);
// Then... there is a gap.
//
// In the compacted format the XSave area header goes just before
// the first xsave entry. It has a total size given by the header
// + (padded) sizes of all the entries.
context_ex.xstate.offset = static_cast<int32_t>(
kMinidumpAMD64XSaveOffset - sizeof(MinidumpXSaveAreaHeader) -
sizeof(context_));
context_ex.xstate.size =
static_cast<uint32_t>(sizeof(MinidumpXSaveAreaHeader) + ContextSize() -
kMinidumpAMD64XSaveOffset);
// Store CONTEXT_EX now it is complete.
DCHECK_LE(sizeof(context_) + sizeof(context_ex), data.size());
memcpy(&buf[sizeof(context_)], &context_ex, sizeof(context_ex));
// Calculate flags for xsave header & write entries (they will be
// *after* the xsave header).
size_t cursor = kMinidumpAMD64XSaveOffset;
for (auto const& entry : xsave_entries_) {
xsave_header.mask |= 1ull << entry->XCompBVBit();
DCHECK_LE(cursor + entry->Size(), data.size());
entry->Copy(&buf[cursor]);
cursor += entry->Size();
}
Write compacted xsave contexts in minidumps Adds new structures and offsets for minidump extended contexts. This information will be captured from threads in a later CL so this CL does not yet write different dumps, except in testing. Minidump format for extended compacted contexts has been determined by experiment. Offsets for where to write various parts of the context are hardcoded to 0x550 as this matches values seen in Windows. Offsets for misc_info_5 match those seen in working minidumps that can be opened in windbg. Our hope is that while these could change in future, CPU and OS vendors are unlikely to change them. See doc[0] for a discussion of these fields and offsets in the minidump. See "MANAGING STATE USING THE XSAVE FEATURE SET" Chapter 13 in the Intel SDM[1]. Many of the offsets and sizes of the extended features are provided by cpu specific values. We can access these in Windows using the SDK, and transfer these to the saved extended context which in turn is understandable by windbg. Further information is available from AMD Ch. 18 "Shadow Stacks"[2]. [0] https://docs.google.com/document/d/1Dn8n97r5B7kxYouvujNnPIYd_7QeVHpahSRmB92Qn6g/edit#heading=h.hivqj2jg39y [1] https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4.html. [2] https://www.amd.com/system/files/TechDocs/24593.pdf Bug: 1250098 Change-Id: Ia9041acc379c6d38329ee99737a2a0a77f7a1ee0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3536964 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Alex Gough <ajgo@chromium.org>
2022-05-14 22:40:24 -07:00
xsave_header.compaction_mask =
xsave_header.mask | XSTATE_COMPACTION_ENABLE_MASK;
// Store xsave header at its calculated offset. It is before the entries
// above, but we need to add the |mask| bits before writing it.
DCHECK_LE(
context_ex.xstate.offset + sizeof(context_) + sizeof(xsave_header),
data.size());
memcpy(&buf[context_ex.xstate.offset + sizeof(context_)],
&xsave_header,
sizeof(xsave_header));
}
if (!file_writer->Write(data.data(), data.size()))
return false;
return true;
}
size_t MinidumpContextAMD64Writer::ContextSize() const {
DCHECK_GE(state(), kStateFrozen);
Write compacted xsave contexts in minidumps Adds new structures and offsets for minidump extended contexts. This information will be captured from threads in a later CL so this CL does not yet write different dumps, except in testing. Minidump format for extended compacted contexts has been determined by experiment. Offsets for where to write various parts of the context are hardcoded to 0x550 as this matches values seen in Windows. Offsets for misc_info_5 match those seen in working minidumps that can be opened in windbg. Our hope is that while these could change in future, CPU and OS vendors are unlikely to change them. See doc[0] for a discussion of these fields and offsets in the minidump. See "MANAGING STATE USING THE XSAVE FEATURE SET" Chapter 13 in the Intel SDM[1]. Many of the offsets and sizes of the extended features are provided by cpu specific values. We can access these in Windows using the SDK, and transfer these to the saved extended context which in turn is understandable by windbg. Further information is available from AMD Ch. 18 "Shadow Stacks"[2]. [0] https://docs.google.com/document/d/1Dn8n97r5B7kxYouvujNnPIYd_7QeVHpahSRmB92Qn6g/edit#heading=h.hivqj2jg39y [1] https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4.html. [2] https://www.amd.com/system/files/TechDocs/24593.pdf Bug: 1250098 Change-Id: Ia9041acc379c6d38329ee99737a2a0a77f7a1ee0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3536964 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Alex Gough <ajgo@chromium.org>
2022-05-14 22:40:24 -07:00
if (xsave_entries_.size() == 0) {
return sizeof(context_);
} else {
DCHECK_EQ(context_.context_flags,
kMinidumpContextAMD64All | kMinidumpContextAMD64Xstate);
DCHECK(xsave_entries_.size() != 0);
size_t size = kMinidumpAMD64XSaveOffset;
for (auto& entry : xsave_entries_) {
size += entry->Size();
}
return size;
}
}
Write compacted xsave contexts in minidumps Adds new structures and offsets for minidump extended contexts. This information will be captured from threads in a later CL so this CL does not yet write different dumps, except in testing. Minidump format for extended compacted contexts has been determined by experiment. Offsets for where to write various parts of the context are hardcoded to 0x550 as this matches values seen in Windows. Offsets for misc_info_5 match those seen in working minidumps that can be opened in windbg. Our hope is that while these could change in future, CPU and OS vendors are unlikely to change them. See doc[0] for a discussion of these fields and offsets in the minidump. See "MANAGING STATE USING THE XSAVE FEATURE SET" Chapter 13 in the Intel SDM[1]. Many of the offsets and sizes of the extended features are provided by cpu specific values. We can access these in Windows using the SDK, and transfer these to the saved extended context which in turn is understandable by windbg. Further information is available from AMD Ch. 18 "Shadow Stacks"[2]. [0] https://docs.google.com/document/d/1Dn8n97r5B7kxYouvujNnPIYd_7QeVHpahSRmB92Qn6g/edit#heading=h.hivqj2jg39y [1] https://software.intel.com/content/www/us/en/develop/download/intel-64-and-ia-32-architectures-sdm-combined-volumes-1-2a-2b-2c-2d-3a-3b-3c-3d-and-4.html. [2] https://www.amd.com/system/files/TechDocs/24593.pdf Bug: 1250098 Change-Id: Ia9041acc379c6d38329ee99737a2a0a77f7a1ee0 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3536964 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Alex Gough <ajgo@chromium.org>
2022-05-14 22:40:24 -07:00
bool MinidumpXSaveAMD64CetU::InitializeFromSnapshot(
const CPUContextX86_64* context_snapshot) {
DCHECK_EQ(context_snapshot->xstate.cet_u.cetmsr, 1ull);
cet_u_.cetmsr = context_snapshot->xstate.cet_u.cetmsr;
cet_u_.ssp = context_snapshot->xstate.cet_u.ssp;
return true;
}
bool MinidumpXSaveAMD64CetU::Copy(void* dst) const {
memcpy(dst, &cet_u_, sizeof(cet_u_));
return true;
}
MinidumpContextARMWriter::MinidumpContextARMWriter()
: MinidumpContextWriter(), context_() {
context_.context_flags = kMinidumpContextARM;
}
MinidumpContextARMWriter::~MinidumpContextARMWriter() = default;
void MinidumpContextARMWriter::InitializeFromSnapshot(
const CPUContextARM* context_snapshot) {
DCHECK_EQ(state(), kStateMutable);
DCHECK_EQ(context_.context_flags, kMinidumpContextARM);
context_.context_flags = kMinidumpContextARMAll;
static_assert(sizeof(context_.regs) == sizeof(context_snapshot->regs),
"GPRS size mismatch");
memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs));
context_.fp = context_snapshot->fp;
context_.ip = context_snapshot->ip;
context_.sp = context_snapshot->sp;
context_.lr = context_snapshot->lr;
context_.pc = context_snapshot->pc;
context_.cpsr = context_snapshot->cpsr;
context_.fpscr = context_snapshot->vfp_regs.fpscr;
static_assert(sizeof(context_.vfp) == sizeof(context_snapshot->vfp_regs.vfp),
"VFP size mismatch");
memcpy(context_.vfp, context_snapshot->vfp_regs.vfp, sizeof(context_.vfp));
memset(context_.extra, 0, sizeof(context_.extra));
}
bool MinidumpContextARMWriter::WriteObject(FileWriterInterface* file_writer) {
DCHECK_EQ(state(), kStateWritable);
return file_writer->Write(&context_, sizeof(context_));
}
size_t MinidumpContextARMWriter::ContextSize() const {
DCHECK_GE(state(), kStateFrozen);
return sizeof(context_);
}
MinidumpContextARM64Writer::MinidumpContextARM64Writer()
: MinidumpContextWriter(), context_() {
context_.context_flags = kMinidumpContextARM64;
}
MinidumpContextARM64Writer::~MinidumpContextARM64Writer() = default;
void MinidumpContextARM64Writer::InitializeFromSnapshot(
const CPUContextARM64* context_snapshot) {
DCHECK_EQ(state(), kStateMutable);
DCHECK_EQ(context_.context_flags, kMinidumpContextARM64);
context_.context_flags = kMinidumpContextARM64Full;
static_assert(
sizeof(context_.regs) == sizeof(context_snapshot->regs) -
2 * sizeof(context_snapshot->regs[0]),
"GPRs size mismatch");
memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs));
context_.fp = context_snapshot->regs[29];
context_.lr = context_snapshot->regs[30];
context_.sp = context_snapshot->sp;
context_.pc = context_snapshot->pc;
context_.cpsr = context_snapshot->spsr;
static_assert(sizeof(context_.fpsimd) == sizeof(context_snapshot->fpsimd),
"FPSIMD size mismatch");
memcpy(context_.fpsimd, context_snapshot->fpsimd, sizeof(context_.fpsimd));
context_.fpcr = context_snapshot->fpcr;
context_.fpsr = context_snapshot->fpsr;
memset(context_.bcr, 0, sizeof(context_.bcr));
memset(context_.bvr, 0, sizeof(context_.bvr));
memset(context_.wcr, 0, sizeof(context_.wcr));
memset(context_.wvr, 0, sizeof(context_.wvr));
}
bool MinidumpContextARM64Writer::WriteObject(FileWriterInterface* file_writer) {
DCHECK_EQ(state(), kStateWritable);
return file_writer->Write(&context_, sizeof(context_));
}
size_t MinidumpContextARM64Writer::ContextSize() const {
DCHECK_GE(state(), kStateFrozen);
return sizeof(context_);
}
MinidumpContextMIPSWriter::MinidumpContextMIPSWriter()
: MinidumpContextWriter(), context_() {
context_.context_flags = kMinidumpContextMIPS;
}
MinidumpContextMIPSWriter::~MinidumpContextMIPSWriter() = default;
void MinidumpContextMIPSWriter::InitializeFromSnapshot(
const CPUContextMIPS* context_snapshot) {
DCHECK_EQ(state(), kStateMutable);
DCHECK_EQ(context_.context_flags, kMinidumpContextMIPS);
context_.context_flags = kMinidumpContextMIPSAll;
static_assert(sizeof(context_.regs) == sizeof(context_snapshot->regs),
"GPRs size mismatch");
memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs));
context_.mdhi = context_snapshot->mdhi;
context_.mdlo = context_snapshot->mdlo;
context_.epc = context_snapshot->cp0_epc;
context_.badvaddr = context_snapshot->cp0_badvaddr;
context_.status = context_snapshot->cp0_status;
context_.cause = context_snapshot->cp0_cause;
static_assert(sizeof(context_.fpregs) == sizeof(context_snapshot->fpregs),
"FPRs size mismatch");
memcpy(&context_.fpregs, &context_snapshot->fpregs, sizeof(context_.fpregs));
context_.fpcsr = context_snapshot->fpcsr;
context_.fir = context_snapshot->fir;
for (size_t index = 0; index < 3; ++index) {
context_.hi[index] = context_snapshot->hi[index];
context_.lo[index] = context_snapshot->lo[index];
}
context_.dsp_control = context_snapshot->dsp_control;
}
bool MinidumpContextMIPSWriter::WriteObject(FileWriterInterface* file_writer) {
DCHECK_EQ(state(), kStateWritable);
return file_writer->Write(&context_, sizeof(context_));
}
size_t MinidumpContextMIPSWriter::ContextSize() const {
DCHECK_GE(state(), kStateFrozen);
return sizeof(context_);
}
MinidumpContextMIPS64Writer::MinidumpContextMIPS64Writer()
: MinidumpContextWriter(), context_() {
context_.context_flags = kMinidumpContextMIPS64;
}
MinidumpContextMIPS64Writer::~MinidumpContextMIPS64Writer() = default;
void MinidumpContextMIPS64Writer::InitializeFromSnapshot(
const CPUContextMIPS64* context_snapshot) {
DCHECK_EQ(state(), kStateMutable);
DCHECK_EQ(context_.context_flags, kMinidumpContextMIPS64);
context_.context_flags = kMinidumpContextMIPS64All;
static_assert(sizeof(context_.regs) == sizeof(context_snapshot->regs),
"GPRs size mismatch");
memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs));
context_.mdhi = context_snapshot->mdhi;
context_.mdlo = context_snapshot->mdlo;
context_.epc = context_snapshot->cp0_epc;
context_.badvaddr = context_snapshot->cp0_badvaddr;
context_.status = context_snapshot->cp0_status;
context_.cause = context_snapshot->cp0_cause;
static_assert(sizeof(context_.fpregs) == sizeof(context_snapshot->fpregs),
"FPRs size mismatch");
memcpy(context_.fpregs.dregs,
context_snapshot->fpregs.dregs,
sizeof(context_.fpregs.dregs));
context_.fpcsr = context_snapshot->fpcsr;
context_.fir = context_snapshot->fir;
for (size_t index = 0; index < 3; ++index) {
context_.hi[index] = context_snapshot->hi[index];
context_.lo[index] = context_snapshot->lo[index];
}
context_.dsp_control = context_snapshot->dsp_control;
}
bool MinidumpContextMIPS64Writer::WriteObject(
FileWriterInterface* file_writer) {
DCHECK_EQ(state(), kStateWritable);
return file_writer->Write(&context_, sizeof(context_));
}
size_t MinidumpContextMIPS64Writer::ContextSize() const {
DCHECK_GE(state(), kStateFrozen);
return sizeof(context_);
}
MinidumpContextRISCV64Writer::MinidumpContextRISCV64Writer()
: MinidumpContextWriter(), context_() {
context_.context_flags = kMinidumpContextRISCV64;
context_.version = MinidumpContextRISCV64::kVersion;
}
MinidumpContextRISCV64Writer::~MinidumpContextRISCV64Writer() = default;
void MinidumpContextRISCV64Writer::InitializeFromSnapshot(
const CPUContextRISCV64* context_snapshot) {
DCHECK_EQ(state(), kStateMutable);
DCHECK_EQ(context_.context_flags, kMinidumpContextRISCV64);
context_.context_flags = kMinidumpContextRISCV64All;
context_.version = MinidumpContextRISCV64::kVersion;
context_.pc = context_snapshot->pc;
static_assert(sizeof(context_.regs) == sizeof(context_snapshot->regs),
"GPRs size mismatch");
memcpy(context_.regs, context_snapshot->regs, sizeof(context_.regs));
static_assert(sizeof(context_.fpregs) == sizeof(context_snapshot->fpregs),
"FPRs size mismatch");
memcpy(context_.fpregs, context_snapshot->fpregs, sizeof(context_.fpregs));
context_.fcsr = context_snapshot->fcsr;
}
bool MinidumpContextRISCV64Writer::WriteObject(
FileWriterInterface* file_writer) {
DCHECK_EQ(state(), kStateWritable);
return file_writer->Write(&context_, sizeof(context_));
}
size_t MinidumpContextRISCV64Writer::ContextSize() const {
DCHECK_GE(state(), kStateFrozen);
return sizeof(context_);
}
} // namespace crashpad