From cb2288d1748c7cb51f0c934b51714e7b6d387967 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Wed, 24 Sep 2014 13:34:45 -0400 Subject: [PATCH] Add MinidumpContext (X86 and AMD64 variants) and their writers. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit These are fairly simple classes and it’s not valuable to test them individually. They will be tested as part of MinidumpThreadWriter and MinidumpExceptionWriter. R=rsesek@chromium.org Review URL: https://codereview.chromium.org/593583004 --- minidump/minidump.gyp | 3 + minidump/minidump_context.h | 363 ++++++++++++++++++++++++++++ minidump/minidump_context_writer.cc | 77 ++++++ minidump/minidump_context_writer.h | 115 +++++++++ 4 files changed, 558 insertions(+) create mode 100644 minidump/minidump_context.h create mode 100644 minidump/minidump_context_writer.cc create mode 100644 minidump/minidump_context_writer.h diff --git a/minidump/minidump.gyp b/minidump/minidump.gyp index b39257d5..63db0325 100644 --- a/minidump/minidump.gyp +++ b/minidump/minidump.gyp @@ -29,6 +29,9 @@ '..', ], 'sources': [ + 'minidump_context.h', + 'minidump_context_writer.cc', + 'minidump_context_writer.h', 'minidump_extensions.cc', 'minidump_extensions.h', 'minidump_file_writer.cc', diff --git a/minidump/minidump_context.h b/minidump/minidump_context.h new file mode 100644 index 00000000..0c65216e --- /dev/null +++ b/minidump/minidump_context.h @@ -0,0 +1,363 @@ +// Copyright 2014 The Crashpad Authors. All rights reserved. +// +// 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. + +#ifndef CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_H_ +#define CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_H_ + +#include + +#include "util/numeric/int128.h" + +namespace crashpad { + +//! \brief Architecture-independent flags for `context_flags` fields in Minidump +//! context structures. +// +// http://zachsaw.blogspot.com/2010/11/wow64-bug-getthreadcontext-may-return.html#c5639760895973344002 +enum MinidumpContextFlags : uint32_t { + //! \brief The thread was executing a trap handler in kernel mode + //! (`CONTEXT_EXCEPTION_ACTIVE`). + //! + //! If this bit is set, it indicates that the context is from a thread that + //! was executing a trap handler in the kernel. This bit is only valid when + //! ::kMinidumpContextExceptionReporting is also set. This bit is only used on + //! Windows. + kMinidumpContextExceptionActive = 0x08000000, + + //! \brief The thread was executing a system call in kernel mode + //! (`CONTEXT_SERVICE_ACTIVE`). + //! + //! If this bit is set, it indicates that the context is from a thread that + //! was executing a system call in the kernel. This bit is only valid when + //! ::kMinidumpContextExceptionReporting is also set. This bit is only used on + //! Windows. + kMinidumpContextServiceActive = 0x10000000, + + //! \brief Kernel-mode state reporting is desired + //! (`CONTEXT_EXCEPTION_REQUEST`). + //! + //! This bit is not used in context structures containing snapshots of thread + //! CPU context. It used when calling `GetThreadContext()` on Windows to + //! specify that kernel-mode state reporting + //! (::kMinidumpContextExceptionReporting) is desired in the returned context + //! structure. + kMinidumpContextExceptionRequest = 0x40000000, + + //! \brief Kernel-mode state reporting is provided + //! (`CONTEXT_EXCEPTION_REPORTING`). + //! + //! If this bit is set, it indicates that the bits indicating how the thread + //! had entered kernel mode (::kMinidumpContextExceptionActive and + //! and ::kMinidumpContextServiceActive) are valid. This bit is only used on + //! Windows. + kMinidumpContextExceptionReporting = 0x80000000, +}; + +//! \brief 32-bit x86-specifc flags for MinidumpContextX86::context_flags. +enum MinidumpContextX86Flags : uint32_t { + //! \brief Identifies the context structure as 32-bit x86. This is the same as + //! `CONTEXT_i386` and `CONTEXT_i486` on Windows for this architecture. + kMinidumpContextX86 = 0x00010000, + + //! \brief Indicates the validity of control registers (`CONTEXT_CONTROL`). + //! + //! The `ebp`, `eip`, `cs`, `eflags`, `esp`, and `ss` fields are valid. + kMinidumpContextX86Control = kMinidumpContextX86 | 0x00000001, + + //! \brief Indicates the validity of non-control integer registers + //! (`CONTEXT_INTEGER`). + //! + //! The `edi`, `esi`, `ebx`, `edx`, `ecx, and `eax` fields are valid. + kMinidumpContextX86Integer = kMinidumpContextX86 | 0x00000002, + + //! \brief Indicates the validity of non-control segment registers + //! (`CONTEXT_SEGMENTS`). + //! + //! The `gs`, `fs`, `es`, and `ds` fields are valid. + kMinidumpContextX86Segment = kMinidumpContextX86 | 0x00000004, + + //! \brief Indicates the validity of floating-point state + //! (`CONTEXT_FLOATING_POINT`). + //! + //! The `float_save` field is valid. + kMinidumpContextX86FloatingPoint = kMinidumpContextX86 | 0x00000008, + + //! \brief Indicates the validity of debug registers + //! (`CONTEXT_DEBUG_REGISTERS`). + //! + //! The `dr0` through `dr3`, `dr6`, and `dr7` fields are valid. + kMinidumpContextX86Debug = kMinidumpContextX86 | 0x00000010, + + //! \brief Indicates the validity of extended registers in `fxsave` format + //! (`CONTEXT_EXTENDED_REGISTERS`). + //! + //! The `extended_registers` field is valid and contains `fxsave` data. + kMinidumpContextX86Extended = kMinidumpContextX86 | 0x00000020, + + //! \brief Indicates the validity of `xsave` data (`CONTEXT_XSTATE`). + //! + //! The context contains `xsave` data. This is used with an extended context + //! structure not currently defined here. + kMinidumpContextX86Xstate = kMinidumpContextX86 | 0x00000040, + + //! \brief Indicates the validity of control, integer, and segment registers. + kMinidumpContextX86Full = kMinidumpContextX86Control | + kMinidumpContextX86Integer | + kMinidumpContextX86Segment, + + //! \brief Indicates the validity of all registers except `xsave` data. + kMinidumpContextX86All = kMinidumpContextX86Full | + kMinidumpContextX86FloatingPoint | + kMinidumpContextX86Debug | + kMinidumpContextX86Extended, +}; + +//! \brief A 32-bit x86 CPU context (register state) carried in a minidump file. +//! +//! This is analogous to the `CONTEXT` structure on Windows when targeting +//! 32-bit x86. This structure is used instead of `CONTEXT` to make it available +//! when targeting other architectures. +struct MinidumpContextX86 { + //! \brief A bitfield composed of values of #MinidumpContextFlags and + //! #MinidumpContextX86Flags. + //! + //! This field identifies the context structure as a 32-bit x86 CPU context, + //! and indicates which other fields in the structure are valid. + uint32_t context_flags; + + uint32_t dr0; + uint32_t dr1; + uint32_t dr2; + uint32_t dr3; + uint32_t dr6; + uint32_t dr7; + + struct { + uint32_t control_word; + uint32_t status_word; + uint32_t tag_word; + uint32_t error_offset; + uint32_t error_selector; + uint32_t data_offset; + uint32_t data_selector; + uint8_t register_area[80]; + uint32_t spare_0; + } float_save; + + uint32_t gs; + uint32_t fs; + uint32_t es; + uint32_t ds; + + uint32_t edi; + uint32_t esi; + uint32_t ebx; + uint32_t edx; + uint32_t ecx; + uint32_t eax; + + uint32_t ebp; + uint32_t eip; + uint32_t cs; + uint32_t eflags; + uint32_t esp; + uint32_t ss; + + uint8_t extended_registers[512]; +}; + +//! \brief x86_64-specifc flags for MinidumpContextAMD64::context_flags. +enum MinidumpContextAMD64Flags : uint32_t { + //! \brief Identifies the context structure as x86_64. This is the same as + //! `CONTEXT_AMD64` on Windows for this architecture. + kMinidumpContextAMD64 = 0x00100000, + + //! \brief Indicates the validity of control registers (`CONTEXT_CONTROL`). + //! + //! The `cs`, `ss`, `eflags`, `rsp`, and `rip` fields are valid. + kMinidumpContextAMD64Control = kMinidumpContextAMD64 | 0x00000001, + + //! \brief Indicates the validity of non-control integer registers + //! (`CONTEXT_INTEGER`). + //! + //! The `rax`, `rcx`, `rdx`, `rbx`, `rbp`, `rsi`, `rdi`, and `r8` through + //! `r15` fields are valid. + kMinidumpContextAMD64Integer = kMinidumpContextAMD64 | 0x00000002, + + //! \brief Indicates the validity of non-control segment registers + //! (`CONTEXT_SEGMENTS`). + //! + //! The `ds`, `es`, `fs`, and `gs` fields are valid. + kMinidumpContextAMD64Segment = kMinidumpContextAMD64 | 0x00000004, + + //! \brief Indicates the validity of floating-point state + //! (`CONTEXT_FLOATING_POINT`). + //! + //! The `xmm0` through `xmm15` fields are valid. + kMinidumpContextAMD64FloatingPoint = kMinidumpContextAMD64 | 0x00000008, + + //! \brief Indicates the validity of debug registers + //! (`CONTEXT_DEBUG_REGISTERS`). + //! + //! The `dr0` through `dr3`, `dr6`, and `dr7` fields are valid. + kMinidumpContextAMD64Debug = kMinidumpContextAMD64 | 0x00000010, + + //! \brief Indicates the validity of `xsave` data (`CONTEXT_XSTATE`). + //! + //! The context contains `xsave` data. This is used with an extended context + //! structure not currently defined here. + kMinidumpContextX86Xstate = kMinidumpContextAMD64 | 0x00000040, + + //! \brief Indicates the validity of control, integer, and segment registers. + kMinidumpContextAMD64Full = kMinidumpContextAMD64Control | + kMinidumpContextAMD64Integer | + kMinidumpContextAMD64Segment, + + //! \brief Indicates the validity of all registers except `xsave` data. + kMinidumpContextAMD64All = kMinidumpContextAMD64Full | + kMinidumpContextAMD64FloatingPoint | + kMinidumpContextAMD64Debug, +}; + +//! \brief An x86_64 (AMD64) CPU context (register state) carried in a minidump +//! file. +//! +//! This is analogous to the `CONTEXT` structure on Windows when targeting +//! x86_64. This structure is used instead of `CONTEXT` to make it available +//! when targeting other architectures. +struct __attribute__((aligned(16))) MinidumpContextAMD64 { + //! \brief Register parameter home address. + //! + //! On Windows, this field may contain the “home” address (on-stack, in the + //! shadow area) of a parameter passed by register. This field is present for + //! convenience but is not necessarily populated, even if a corresponding + //! parameter was passed by register. + //! + //! \{ + uint64_t p1_home; + uint64_t p2_home; + uint64_t p3_home; + uint64_t p4_home; + uint64_t p5_home; + uint64_t p6_home; + //! \} + + //! \brief A bitfield composed of values of #MinidumpContextFlags and + //! #MinidumpContextAMD64Flags. + //! + //! This field identifies the context structure as an x86_64 CPU context, and + //! indicates which other fields in the structure are valid. + uint32_t context_flags; + + uint32_t mx_csr; + + uint16_t cs; + uint16_t ds; + uint16_t es; + uint16_t fs; + uint16_t gs; + uint16_t ss; + + uint32_t eflags; + + uint64_t dr0; + uint64_t dr1; + uint64_t dr2; + uint64_t dr3; + uint64_t dr6; + uint64_t dr7; + + uint64_t rax; + uint64_t rcx; + uint64_t rdx; + uint64_t rbx; + uint64_t rsp; + uint64_t rbp; + uint64_t rsi; + uint64_t rdi; + uint64_t r8; + uint64_t r9; + uint64_t r10; + uint64_t r11; + uint64_t r12; + uint64_t r13; + uint64_t r14; + uint64_t r15; + + uint64_t rip; + + union { + struct { + uint16_t control_word; + uint16_t status_word; + uint8_t tag_word; + uint8_t reserved_1; + uint16_t error_opcode; + uint32_t error_offset; + uint16_t error_selector; + uint16_t reserved_2; + uint32_t data_offset; + uint16_t data_selector; + uint16_t reserved_3; + uint32_t mx_csr; + uint32_t mx_csr_mask; + uint128_struct float_registers[8]; + uint128_struct xmm_registers[16]; + uint8_t reserved_4[96]; + } float_save; + struct { + uint128_struct header[2]; + uint128_struct legacy[8]; + uint128_struct xmm0; + uint128_struct xmm1; + uint128_struct xmm2; + uint128_struct xmm3; + uint128_struct xmm4; + uint128_struct xmm5; + uint128_struct xmm6; + uint128_struct xmm7; + uint128_struct xmm8; + uint128_struct xmm9; + uint128_struct xmm10; + uint128_struct xmm11; + uint128_struct xmm12; + uint128_struct xmm13; + uint128_struct xmm14; + uint128_struct xmm15; + }; + }; + + uint128_struct vector_register[26]; + uint64_t vector_control; + + //! \brief Model-specific debug extension register. + //! + //! See Intel Software Developer’s Manual, Volume 3B: System Programming, Part + //! 2 (253669-051), 17.4 “Last Branch, Interrupt, and Exception Recording + //! Overview”, and AMD Architecture Programmer’s Manual, Volume 2: + //! System Programming (24593-3.24), 13.1.6 “Control-Transfer Breakpoint + //! Features”. + //! + //! \{ + uint64_t debug_control; + uint64_t last_branch_to_rip; + uint64_t last_branch_from_rip; + uint64_t last_exception_to_rip; + uint64_t last_exception_from_rip; + //! \} +}; + +} // namespace crashpad + +#endif // CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_H_ diff --git a/minidump/minidump_context_writer.cc b/minidump/minidump_context_writer.cc new file mode 100644 index 00000000..3bbd4a4f --- /dev/null +++ b/minidump/minidump_context_writer.cc @@ -0,0 +1,77 @@ +// Copyright 2014 The Crashpad Authors. All rights reserved. +// +// 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 "base/logging.h" + +namespace crashpad { + +MinidumpContextWriter::~MinidumpContextWriter() { +} + +size_t MinidumpContextWriter::SizeOfObject() { + DCHECK_GE(state(), kStateFrozen); + + return ContextSize(); +} + +MinidumpContextX86Writer::MinidumpContextX86Writer() + : MinidumpContextWriter(), context_() { + context_.context_flags = kMinidumpContextX86; +} + +MinidumpContextX86Writer::~MinidumpContextX86Writer() { +} + +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_); +} + +MinidumpContextAMD64Writer::MinidumpContextAMD64Writer() + : MinidumpContextWriter(), context_() { + context_.context_flags = kMinidumpContextAMD64; +} + +MinidumpContextAMD64Writer::~MinidumpContextAMD64Writer() { +} + +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); + + return file_writer->Write(&context_, sizeof(context_)); +} + +size_t MinidumpContextAMD64Writer::ContextSize() const { + DCHECK_GE(state(), kStateFrozen); + + return sizeof(context_); +} + +} // namespace crashpad diff --git a/minidump/minidump_context_writer.h b/minidump/minidump_context_writer.h new file mode 100644 index 00000000..91e7367b --- /dev/null +++ b/minidump/minidump_context_writer.h @@ -0,0 +1,115 @@ +// Copyright 2014 The Crashpad Authors. All rights reserved. +// +// 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. + +#ifndef CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_WRITER_H_ +#define CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_WRITER_H_ + +#include + +#include "base/basictypes.h" +#include "minidump/minidump_context.h" +#include "minidump/minidump_writable.h" +#include "util/file/file_writer.h" + +namespace crashpad { + +//! \brief The base class for writers of CPU context structures in minidump +//! files. +class MinidumpContextWriter : public internal::MinidumpWritable { + public: + virtual ~MinidumpContextWriter(); + + protected: + MinidumpContextWriter() : MinidumpWritable() {} + + //! \brief Returns the size of the context structure that this object will + //! write. + //! + //! \note This method will only be called in #kStateFrozen or a subsequent + //! state. + virtual size_t ContextSize() const = 0; + + // MinidumpWritable: + virtual size_t SizeOfObject() override final; + + private: + DISALLOW_COPY_AND_ASSIGN(MinidumpContextWriter); +}; + +//! \brief The writer for a MinidumpContextX86 structure in a minidump file. +class MinidumpContextX86Writer final : public MinidumpContextWriter { + public: + MinidumpContextX86Writer(); + virtual ~MinidumpContextX86Writer(); + + //! \brief Returns a pointer to the context structure that this object will + //! write. + //! + //! \attention This returns a non-`const` pointer to this object’s private + //! data so that a caller can populate the context structure directly. + //! This is done because providing setter interfaces to each field in the + //! context structure would be unwieldy and cumbersome. Care must be taken + //! to populate the context structure correctly. The context structure + //! must only be modified while this object is in the #kStateMutable + //! state. + MinidumpContextX86* context() { return &context_; } + + protected: + // MinidumpWritable: + virtual bool WriteObject(FileWriterInterface* file_writer) override; + + // MinidumpContextWriter: + virtual size_t ContextSize() const override; + + private: + MinidumpContextX86 context_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpContextX86Writer); +}; + +//! \brief The writer for a MinidumpContextAMD64 structure in a minidump file. +class MinidumpContextAMD64Writer final : public MinidumpContextWriter { + public: + MinidumpContextAMD64Writer(); + virtual ~MinidumpContextAMD64Writer(); + + //! \brief Returns a pointer to the context structure that this object will + //! write. + //! + //! \attention This returns a non-`const` pointer to this object’s private + //! data so that a caller can populate the context structure directly. + //! This is done because providing setter interfaces to each field in the + //! context structure would be unwieldy and cumbersome. Care must be taken + //! to populate the context structure correctly. The context structure + //! must only be modified while this object is in the #kStateMutable + //! state. + MinidumpContextAMD64* context() { return &context_; } + + protected: + // MinidumpWritable: + virtual size_t Alignment() override; + virtual bool WriteObject(FileWriterInterface* file_writer) override; + + // MinidumpContextWriter: + virtual size_t ContextSize() const override; + + private: + MinidumpContextAMD64 context_; + + DISALLOW_COPY_AND_ASSIGN(MinidumpContextAMD64Writer); +}; + +} // namespace crashpad + +#endif // CRASHPAD_MINIDUMP_MINIDUMP_CONTEXT_WRITER_H_