From 7b2e7efcc247583cd8044118c48480c5aa59c756 Mon Sep 17 00:00:00 2001 From: Mark Mentovai Date: Thu, 2 Oct 2014 17:09:37 -0400 Subject: [PATCH] Add the Snapshot interface. These are all of the abstract base classes used in the Snapshot series, discussed in the thread at https://groups.google.com/a/chromium.org/d/topic/crashpad-dev/4pACgjhIz-I. R=rsesek@chromium.org Review URL: https://codereview.chromium.org/597673004 --- crashpad.gyp | 1 + snapshot/cpu_architecture.h | 39 +++++ snapshot/cpu_context.cc | 33 +++++ snapshot/cpu_context.h | 173 ++++++++++++++++++++++ snapshot/exception_snapshot.h | 96 ++++++++++++ snapshot/memory_snapshot.h | 78 ++++++++++ snapshot/module_snapshot.h | 149 +++++++++++++++++++ snapshot/process_snapshot.h | 116 +++++++++++++++ snapshot/snapshot.gyp | 41 ++++++ snapshot/system_snapshot.h | 265 ++++++++++++++++++++++++++++++++++ snapshot/thread_snapshot.h | 69 +++++++++ 11 files changed, 1060 insertions(+) create mode 100644 snapshot/cpu_architecture.h create mode 100644 snapshot/cpu_context.cc create mode 100644 snapshot/cpu_context.h create mode 100644 snapshot/exception_snapshot.h create mode 100644 snapshot/memory_snapshot.h create mode 100644 snapshot/module_snapshot.h create mode 100644 snapshot/process_snapshot.h create mode 100644 snapshot/snapshot.gyp create mode 100644 snapshot/system_snapshot.h create mode 100644 snapshot/thread_snapshot.h diff --git a/crashpad.gyp b/crashpad.gyp index 608483e9..cc935459 100644 --- a/crashpad.gyp +++ b/crashpad.gyp @@ -22,6 +22,7 @@ 'client/client.gyp:*', 'compat/compat.gyp:*', 'minidump/minidump.gyp:*', + 'snapshot/snapshot.gyp:*', 'tools/tools.gyp:*', 'util/util.gyp:*', ], diff --git a/snapshot/cpu_architecture.h b/snapshot/cpu_architecture.h new file mode 100644 index 00000000..208e98f2 --- /dev/null +++ b/snapshot/cpu_architecture.h @@ -0,0 +1,39 @@ +// 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_SNAPSHOT_SNAPSHOT_CPU_ARCHITECTURE_H_ +#define CRASHPAD_SNAPSHOT_SNAPSHOT_CPU_ARCHITECTURE_H_ + +namespace crashpad { + +//! \brief A system’s CPU architecture. +//! +//! This can be used to represent the CPU architecture of an entire system +//! as in SystemSnapshot::CPUArchitecture(). It can also be used to represent +//! the architecture of a CPUContext structure in its CPUContext::architecture +//! field without reference to external data. +enum CPUArchitecture { + //! \brief The CPU architecture is unknown. + kCPUArchitectureUnknown = 0, + + //! \brief 32-bit x86. + kCPUArchitectureX86, + + //! \brief x86_64. + kCPUArchitectureX86_64, +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_SNAPSHOT_CPU_ARCHITECTURE_H_ diff --git a/snapshot/cpu_context.cc b/snapshot/cpu_context.cc new file mode 100644 index 00000000..eada29e4 --- /dev/null +++ b/snapshot/cpu_context.cc @@ -0,0 +1,33 @@ +// 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 "snapshot/cpu_context.h" + +#include "base/logging.h" + +namespace crashpad { + +uint64_t CPUContext::InstructionPointer() const { + switch (architecture) { + case kCPUArchitectureX86: + return x86->eip; + case kCPUArchitectureX86_64: + return x86_64->rip; + default: + NOTREACHED(); + return -1; + } +} + +} // namespace crashpad diff --git a/snapshot/cpu_context.h b/snapshot/cpu_context.h new file mode 100644 index 00000000..ec318fdc --- /dev/null +++ b/snapshot/cpu_context.h @@ -0,0 +1,173 @@ +// 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_SNAPSHOT_SNAPSHOT_CPU_CONTEXT_H_ +#define CRASHPAD_SNAPSHOT_SNAPSHOT_CPU_CONTEXT_H_ + +#include + +#include "snapshot/cpu_architecture.h" + +namespace crashpad { + +//! \brief A context structure carrying 32-bit x86 CPU state. +struct CPUContextX86 { + typedef uint8_t X87Register[10]; + + union X87OrMMXRegister { + struct { + X87Register st; + uint8_t st_reserved[6]; + }; + struct { + uint8_t mm_value[8]; + uint8_t mm_reserved[8]; + }; + }; + + typedef uint8_t XMMRegister[16]; + + struct Fxsave { + uint16_t fcw; // FPU control word + uint16_t fsw; // FPU status word + uint8_t ftw; // abridged FPU tag word + uint8_t reserved_1; + uint16_t fop; // FPU opcode + uint32_t fpu_ip; // FPU instruction pointer offset + uint16_t fpu_cs; // FPU instruction pointer segment selector + uint16_t reserved_2; + uint32_t fpu_dp; // FPU data pointer offset + uint16_t fpu_ds; // FPU data pointer segment selector + uint16_t reserved_3; + uint32_t mxcsr; // multimedia extensions status and control register + uint32_t mxcsr_mask; // valid bits in mxcsr + X87OrMMXRegister st_mm[8]; + XMMRegister xmm[8]; + uint8_t reserved_4[176]; + uint8_t available[48]; + }; + + // Integer registers. + uint32_t eax; + uint32_t ebx; + uint32_t ecx; + uint32_t edx; + uint32_t edi; // destination index + uint32_t esi; // source index + uint32_t ebp; // base pointer + uint32_t esp; // stack pointer + uint32_t eip; // instruction pointer + uint32_t eflags; + uint16_t cs; // code segment selector + uint16_t ds; // data segment selector + uint16_t es; // extra segment selector + uint16_t fs; + uint16_t gs; + uint16_t ss; // stack segment selector + + // Floating-point and vector registers. + Fxsave fxsave; + + // Debug registers. + uint32_t dr0; + uint32_t dr1; + uint32_t dr2; + uint32_t dr3; + uint32_t dr4; // obsolete, normally an alias for dr6 + uint32_t dr5; // obsolete, normally an alias for dr7 + uint32_t dr6; + uint32_t dr7; +}; + +//! \brief A context structure carrying x86_64 CPU state. +struct CPUContextX86_64 { + typedef CPUContextX86::X87Register X87Register; + typedef CPUContextX86::X87OrMMXRegister X87OrMMXRegister; + typedef CPUContextX86::XMMRegister XMMRegister; + + struct Fxsave64 { + uint16_t fcw; // FPU control word + uint16_t fsw; // FPU status word + uint8_t ftw; // abridged FPU tag word + uint8_t reserved_1; + uint16_t fop; // FPU opcode + uint64_t fpu_ip; // FPU instruction pointer + uint64_t fpu_dp; // FPU data pointer + uint32_t mxcsr; // multimedia extensions status and control register + uint32_t mxcsr_mask; // valid bits in mxcsr + X87OrMMXRegister st_mm[8]; + XMMRegister xmm[16]; + uint8_t reserved_2[48]; + uint8_t available[48]; + }; + + // Integer registers. + uint64_t rax; + uint64_t rbx; + uint64_t rcx; + uint64_t rdx; + uint64_t rdi; // destination index + uint64_t rsi; // source index + uint64_t rbp; // base pointer + uint64_t rsp; // stack pointer + 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; // instruction pointer + uint64_t rflags; + uint16_t cs; // code segment selector + uint16_t fs; + uint16_t gs; + + // Floating-point and vector registers. + Fxsave64 fxsave64; + + // Debug registers. + uint64_t dr0; + uint64_t dr1; + uint64_t dr2; + uint64_t dr3; + uint64_t dr4; // obsolete, normally an alias for dr6 + uint64_t dr5; // obsolete, normally an alias for dr7 + uint64_t dr6; + uint64_t dr7; +}; + +//! \brief A context structure capable of carrying the context of any supported +//! CPU architecture. +struct CPUContext { + //! \brief Returns the instruction pointer value from the context structure. + //! + //! This is a CPU architecture-independent method that is capable of + //! recovering the instruction pointer from any supported CPU architecture’s + //! context structure. + uint64_t InstructionPointer() const; + + //! \brief The CPU architecture of a context structure. This field controls + //! the expression of the union. + CPUArchitecture architecture; + union { + CPUContextX86* x86; + CPUContextX86_64* x86_64; + }; +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_SNAPSHOT_CPU_CONTEXT_H_ diff --git a/snapshot/exception_snapshot.h b/snapshot/exception_snapshot.h new file mode 100644 index 00000000..5788468a --- /dev/null +++ b/snapshot/exception_snapshot.h @@ -0,0 +1,96 @@ +// 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_SNAPSHOT_EXCEPTION_SNAPSHOT_H_ +#define CRASHPAD_SNAPSHOT_EXCEPTION_SNAPSHOT_H_ + +#include + +#include + +namespace crashpad { + +struct CPUContext; + +//! \brief An abstract interface to a snapshot representing an exception that a +//! snapshot process sustained and triggered the snapshot being taken. +class ExceptionSnapshot { + public: + //! \brief Returns a CPUContext object corresponding to the exception thread’s + //! CPU context at the time of the exception. + //! + //! The caller does not take ownership of this object, it is scoped to the + //! lifetime of the ThreadSnapshot object that it was obtained from. + virtual const CPUContext* Context() const = 0; + + //! \brief Returns the thread identifier of the thread that triggered the + //! exception. + //! + //! This value can be compared to ThreadSnapshot::ThreadID() to associate an + //! ExceptionSnapshot object with the ThreadSnapshot that contains a snapshot + //! of the thread that triggered the exception. + virtual uint64_t ThreadID() const = 0; + + //! \brief Returns the top-level exception code identifying the exception. + //! + //! This is an operating system-specific value. + //! + //! For Mac OS X, this will be an \ref EXC_x "EXC_*" exception type, such as + //! `EXC_BAD_ACCESS`. `EXC_CRASH` will not appear here for exceptions + //! processed as `EXC_CRASH` when generated from another preceding exception: + //! the original exception code will appear instead. The exception type as it + //! was received will appear at index 0 of Codes(). + virtual uint32_t Exception() const = 0; + + //! \brief Returns the second-level exception code identifying the exception. + //! + //! This is an operating system-specific value. + //! + //! For Mac OS X, this will be the value of the exception code at index 0 as + //! received by a Mach exception handler. For `EXC_CRASH` exceptions generated + //! from another preceding exception, the original exception code will appear + //! here, not the code as received by the Mach exception handler. The code as + //! it was received will appear at index 1 of Codes(). + virtual uint32_t ExceptionInfo() const = 0; + + //! \brief Returns the address that triggered the exception. + //! + //! This may be the address that caused a fault on data access, or it may be + //! the instruction pointer that contained an offending instruction. For + //! exceptions where this value cannot be determined, it will be `0`. + //! + //! For Mac OS X, this will be the value of the exception code at index 1 as + //! received by a Mach exception handler. + virtual uint64_t ExceptionAddress() const = 0; + + //! \brief Returns a series of operating system-specific exception codes. + //! + //! The precise interpretation of these codes is specific to the snapshot + //! operating system. These codes may provide a duplicate of information + //! available elsewhere, they may extend information available elsewhere, or + //! they may not be present at all. In this case, an empty vector will be + //! returned. + //! + //! For Mac OS X, this will be a vector containing the original exception type + //! and the values of `code[0]` and `code[1]` as received by a Mach exception + //! handler. + virtual const std::vector& Codes() const = 0; + + protected: + ~ExceptionSnapshot() {} +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_EXCEPTION_SNAPSHOT_H_ diff --git a/snapshot/memory_snapshot.h b/snapshot/memory_snapshot.h new file mode 100644 index 00000000..e7d83166 --- /dev/null +++ b/snapshot/memory_snapshot.h @@ -0,0 +1,78 @@ +// 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_SNAPSHOT_MEMORY_SNAPSHOT_H_ +#define CRASHPAD_SNAPSHOT_MEMORY_SNAPSHOT_H_ + +#include +#include + +namespace crashpad { + +//! \brief An abstract interface to a snapshot representing a region of memory +//! present in a snapshot process. +class MemorySnapshot { + public: + //! \brief An interface that MemorySnapshot clients must implement in order to + //! receive memory snapshot data. + //! + //! This callback-based model frees MemorySnapshot implementations from having + //! to deal with memory region ownership problems. When a memory snapshot’s + //! data is read, it will be passed to a delegate method. + class Delegate { + public: + //! \brief Called by MemorySnapshot::Read() to provide data requested by a + //! call to that method. + //! + //! \param[in] data A pointer to the data that was read. The callee does not + //! take ownership of this data. This data is only valid for the + //! duration of the call to this method. + //! \param[in] size The size of the data that was read. + //! + //! \return `true` on success, `false` on failure. MemoryDelegate::Read() + //! will use this as its own return value. + virtual bool MemorySnapshotDelegateRead(void* data, size_t size) = 0; + + protected: + ~Delegate() {} + }; + + //! \brief The base address of the memory snapshot in the snapshot process’ + //! address space. + virtual uint64_t Address() const = 0; + + //! \brief The size of the memory snapshot. + virtual size_t Size() const = 0; + + //! \brief Calls Delegate::MemorySnapshotDelegateRead(), providing it with + //! the memory snapshot’s data. + //! + //! Implementations do not necessarily read the memory snapshot data prior to + //! this method being called. Memory snapshot data may be loaded lazily and + //! may be discarded after being passed to the delegate. This provides clean + //! memory management without burdening a snapshot implementation with the + //! requirement that it track all memory region data simultaneously. + //! + //! \return `false` on failure, otherwise, the return value of + //! Delegate::MemorySnapshotDelegateRead(), which should be `true` on + //! success and `false` on failure. + virtual bool Read(Delegate* delegate) const = 0; + + protected: + ~MemorySnapshot() {} +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_MEMORY_SNAPSHOT_H_ diff --git a/snapshot/module_snapshot.h b/snapshot/module_snapshot.h new file mode 100644 index 00000000..7ebef044 --- /dev/null +++ b/snapshot/module_snapshot.h @@ -0,0 +1,149 @@ +// 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_SNAPSHOT_MODULE_SNAPSHOT_H_ +#define CRASHPAD_SNAPSHOT_MODULE_SNAPSHOT_H_ + +#include +#include + +#include +#include +#include + +#include "util/misc/uuid.h" + +namespace crashpad { + +//! \brief An abstract interface to a snapshot representing a code module +//! (binary image) loaded into a snapshot process. +class ModuleSnapshot { + public: + //! \brief A module’s type. + enum ModuleType { + //! \brief The module’s type is unknown. + kModuleTypeUnknown = 0, + + //! \brief The module is a main executable. + kModuleTypeExecutable, + + //! \brief The module is a shared library. + //! + //! \sa kModuleTypeLoadableModule + kModuleTypeSharedLibrary, + + //! \brief The module is a loadable module. + //! + //! On some platforms, loadable modules are distinguished from shared + //! libraries. On these platforms, a shared library is a module that another + //! module links against directly, and a loadable module is not. Loadable + //! modules tend to be binary plug-ins. + kModuleTypeLoadableModule, + + //! \brief The module is a dynamic loader. + //! + //! This is the module responsible for loading other modules. This is + //! normally `dyld` for Mac OS X and `ld.so` for Linux and other systems + //! using ELF. + kModuleTypeDynamicLoader, + }; + + //! \brief Returns the module’s pathname. + virtual std::string Name() const = 0; + + //! \brief Returns the base address that the module is loaded at in the + //! snapshot process. + virtual uint64_t Address() const = 0; + + //! \brief Returns the size that the module occupies in the snapshot process’ + //! address space, starting at its base address. + //! + //! For Mac OS X snapshots, this method only reports the size of the `__TEXT` + //! segment, because segments may not be loaded contiguously. + virtual uint64_t Size() const = 0; + + //! \brief Returns the module’s timestamp, if known. + //! + //! The timestamp is typically the modification time of the file that provided + //! the module in `time_t` format, seconds since the POSIX epoch. If the + //! module’s timestamp is unknown, this method returns `0`. + virtual time_t Timestamp() const = 0; + + //! \brief Returns the module’s file version in the \a version_* parameters. + //! + //! If no file version can be determined, the \a version_* parameters are set + //! to `0`. + //! + //! For Mac OS X snapshots, this is taken from the module’s `LC_ID_DYLIB` load + //! command for shared libraries, and is `0` for other module types. + virtual void FileVersion(uint16_t* version_0, + uint16_t* version_1, + uint16_t* version_2, + uint16_t* version_3) const = 0; + + //! \brief Returns the module’s source version in the \a version_* parameters. + //! + //! If no source version can be determined, the \a version_* parameters are + //! set to `0`. + //! + //! For Mac OS X snapshots, this is taken from the module’s + //! `LC_SOURCE_VERSION` load command. + virtual void SourceVersion(uint16_t* version_0, + uint16_t* version_1, + uint16_t* version_2, + uint16_t* version_3) const = 0; + + //! \brief Returns the module’s type. + virtual ModuleType GetModuleType() const = 0; + + //! \brief Returns the module’s UUID in the \a uuid parameter. + //! + //! A snapshot module’s UUID is taken directly from the module itself. If the + //! module does not have a UUID, the \a uuid parameter will be zeroed out. + virtual void UUID(crashpad::UUID* uuid) const = 0; + + //! \brief Returns diagnostic messages recorded in the module. + //! + //! This method retrieves diagnostic messages recorded in a module. These + //! messages are intended for diagnostic use, including crash analysis. A + //! module may contain multiple diagnostic messages. + //! + //! For Mac OS X snapshots, the diagnostic messages are found by interpreting + //! the module’s `__DATA, __crash_info` section as + //! `crashreporter_annotations_t`. System libraries using the crash reporter + //! client interface may reference diagnostic messages in this structure. + //! Additional diagnostic messages may be found in other locations, which may + //! be module-specific. The dynamic linker (`dyld`) can provide a diagnostic + //! message at its `_error_string` symbol. + virtual std::vector DiagnosticMessages() const = 0; + + //! \brief Returns simple annotations recorded in the module. + //! + //! This method retrieves simple annotations recorded in a module. These + //! annotations are intended for diagnostic use, including crash analysis. + //! Simple annotations are structured as a sequence of key-value pairs. These + //! are referred to in Chrome as “crash keys.” + //! + //! For Mac OS X snapshots, simple annotations are found by interpreting + //! the `__DATA, __crashpad_info` section as `CrashpadInfo`. Clients can use + //! the Crashpad client interface to store annotations in this structure. + virtual std::map SimpleAnnotations() const = 0; + + protected: + ~ModuleSnapshot() {} +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_MODULE_SNAPSHOT_H_ diff --git a/snapshot/process_snapshot.h b/snapshot/process_snapshot.h new file mode 100644 index 00000000..76ea7fe6 --- /dev/null +++ b/snapshot/process_snapshot.h @@ -0,0 +1,116 @@ +// 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_SNAPSHOT_PROCESS_SNAPSHOT_H_ +#define CRASHPAD_SNAPSHOT_PROCESS_SNAPSHOT_H_ + +#include +#include + +#include + +namespace crashpad { + +class ExceptionSnapshot; +class ModuleSnapshot; +class SystemSnapshot; +class ThreadSnapshot; + +//! \brief An abstract interface to a snapshot representing the state of a +//! process. +//! +//! This is the top-level object in a family of Snapshot objects, because it +//! gives access to a SystemSnapshot, vectors of ModuleSnapshot and +//! ThreadSnapshot objects, and possibly an ExceptionSnapshot. In turn, +//! ThreadSnapshot and ExceptionSnapshot objects both give access to CPUContext +//! objects, and ThreadSnapshot objects also give access to MemorySnapshot +//! objects corresponding to thread stacks. +class ProcessSnapshot { + public: + //! \brief Returns the snapshot process’ process ID. + virtual pid_t ProcessID() const = 0; + + //! \brief Returns the snapshot process’ parent process’ process ID. + virtual pid_t ParentProcessID() const = 0; + + //! \brief Returns the time that the snapshot was taken in \a snapshot_time. + //! + //! \param[out] snapshot_time The time that the snapshot was taken. This is + //! distinct from the time that a ProcessSnapshot object was created or + //! initialized, although it may be that time for ProcessSnapshot objects + //! representing live or recently-crashed process state. + virtual void SnapshotTime(timeval* snapshot_time) const = 0; + + //! \brief Returns the time that the snapshot process was started in \a + //! start_time. + //! + //! Normally, process uptime in wall clock time can be computed as + //! SnapshotTime() − ProcessStartTime(), but this cannot be guaranteed in + //! cases where the real-time clock has been set during the snapshot process’ + //! lifetime. + //! + //! \param[out] start_time The time that the process was started. + virtual void ProcessStartTime(timeval* start_time) const = 0; + + //! \brief Returns the snapshot process’ CPU usage times in \a user_time and + //! \a system_time. + //! + //! \param[out] user_time The time that the process has spent executing in + //! user mode. + //! \param[out] system_time The time that the process has spent executing in + //! system (kernel) mode. + virtual void ProcessCPUTimes(timeval* user_time, + timeval* system_time) const = 0; + + //! \brief Returns a SystemSnapshot reflecting the characteristics of the + //! system that ran the snapshot process at the time of the snapshot. + //! + //! \return A SystemSnapshot object. The caller does not take ownership of + //! this object, it is scoped to the lifetime of the ProcessSnapshot + //! object that it was obtained from. + virtual const SystemSnapshot* System() const = 0; + + //! \brief Returns ModuleSnapshot objects reflecting the code modules (binary + //! images) loaded into the snapshot process at the time of the snapshot. + //! + //! \return A vector of ModuleSnapshot objects. The caller does not take + //! ownership of these objects, they are scoped to the lifetime of the + //! ProcessSnapshot object that they were obtained from. + virtual std::vector Modules() const = 0; + + //! \brief Returns ThreadSnapshot objects reflecting the threads (lightweight + //! processes) existing in the snapshot process at the time of the + //! snapshot. + //! + //! \return A vector of ThreadSnapshot objects. The caller does not take + //! ownership of these objects, they are scoped to the lifetime of the + //! ProcessSnapshot object that they were obtained from. + virtual std::vector Threads() const = 0; + + //! \brief Returns an ExceptionSnapshot reflecting the exception that the + //! snapshot process sustained to trigger the snapshot being taken. + //! + //! \return An ExceptionSnapshot object. The caller does not take ownership of + //! this object, it is scoped to the lifetime of the ProcessSnapshot + //! object that it was obtained from. If the snapshot is not a result of + //! an exception, returns `NULL`. + virtual const ExceptionSnapshot* Exception() const = 0; + + protected: + ~ProcessSnapshot() {} +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_PROCESS_SNAPSHOT_H_ diff --git a/snapshot/snapshot.gyp b/snapshot/snapshot.gyp new file mode 100644 index 00000000..216d93ed --- /dev/null +++ b/snapshot/snapshot.gyp @@ -0,0 +1,41 @@ +# 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. + +{ + 'targets': [ + { + 'target_name': 'snapshot', + 'type': 'static_library', + 'dependencies': [ + '../compat/compat.gyp:compat', + '../third_party/mini_chromium/mini_chromium/base/base.gyp:base', + '../util/util.gyp:util', + ], + 'include_dirs': [ + '..', + ], + 'sources': [ + 'cpu_architecture.h', + 'cpu_context.cc', + 'cpu_context.h', + 'exception_snapshot.h', + 'memory_snapshot.h', + 'module_snapshot.h', + 'process_snapshot.h', + 'system_snapshot.h', + 'thread_snapshot.h', + ], + }, + ], +} diff --git a/snapshot/system_snapshot.h b/snapshot/system_snapshot.h new file mode 100644 index 00000000..393bd271 --- /dev/null +++ b/snapshot/system_snapshot.h @@ -0,0 +1,265 @@ +// 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_SNAPSHOT_SYSTEM_SNAPSHOT_H_ +#define CRASHPAD_SNAPSHOT_SYSTEM_SNAPSHOT_H_ + +#include +#include + +#include + +#include "snapshot/cpu_architecture.h" + +namespace crashpad { + +//! \brief An abstract interface to a snapshot representing the state of a +//! system, comprising an operating system, CPU architecture, and various +//! other characteristics. +class SystemSnapshot { + public: + //! \brief A system’s operating system family. + enum OperatingSystem { + //! \brief The snapshot system’s operating system is unknown. + kOperatingSystemUnknown = 0, + + //! \brief Mac OS X. + kOperatingSystemMacOSX, + }; + + //! \brief A system’s daylight saving time status. + //! + //! The daylight saving time status is taken partially from the system’s + //! locale configuration. This determines whether daylight saving time is + //! ever observed on the system. If it is, the snapshot’s time + //! (ProcessSnapshot::SnapshotTime()) is used to determine whether the system + //! was observing daylight saving time at the time of the snapshot. + enum DaylightSavingTimeStatus { + //! \brief Daylight saving time is never observed on the snapshot system. + kDoesNotObserveDaylightSavingTime = 0, + + //! \brief Daylight saving time is observed on the snapshot system when in + //! effect, but standard time was in effect at the time of the snapshot. + kObservingStandardTime, + + //! \brief Daylight saving time is observed on the snapshot system when in + //! effect, and daylight saving time was in effect at the time of the + //! snapshot. + kObservingDaylightSavingTime, + }; + + //! \brief Returns the snapshot system’s CPU architecture. + //! + //! In some cases, a system may be able to run processes of multiple specific + //! architecture types. For example, systems based on 64-bit architectures + //! such as x86_64 are often able to run 32-bit code of another architecture + //! in the same family, such as 32-bit x86. On these systems, this method will + //! return the architecture of the process that the snapshot is associated + //! with, provided that the SystemSnapshot object was obtained from + //! ProcessSnapshot::System(). This renders one aspect of this method’s return + //! value a process attribute rather than a system attribute, but it’s defined + //! here rather than in ProcessSnapshot because the CPU architecture is a + //! better conceptual fit for the system abstraction alongside these other + //! related methods. + virtual CPUArchitecture GetCPUArchitecture() const = 0; + + //! \brief Returns the snapshot system’s CPU revision. + //! + //! For x86-family CPUs (including x86_64 and 32-bit x86), this is the CPU + //! family ID value from `cpuid 1` `eax`, adjusted to take the extended family + //! ID into account. + //! + //! \return A CPU architecture-specific value identifying the CPU revision. + virtual uint32_t CPURevision() const = 0; + + //! \brief Returns the total number of CPUs present in the snapshot system. + virtual uint8_t CPUCount() const = 0; + + //! \brief Returns the vendor of the snapshot system’s CPUs. + //! + //! For x86-family CPUs (including x86_64 and 32-bit x86), this is the CPU + //! vendor identification string as encoded in `cpuid 0` `ebx`, `edx`, and + //! `ecx`. + //! + //! \return A string identifying the vendor of the snapshot system’s CPUs. + virtual std::string CPUVendor() const = 0; + + //! \brief Returns frequency information about the snapshot system’s CPUs in + //! \current_hz and \a max_hz. + //! + //! \param[out] current_hz The snapshot system’s CPU clock frequency in Hz at + //! the time of the snapshot. + //! \param[out] max_hz The snapshot system’s maximum possible CPU clock + //! frequency. + virtual void CPUFrequency(uint64_t* current_hz, uint64_t* max_hz) const = 0; + + //! \brief Returns an x86-family snapshot system’s CPU signature. + //! + //! This is the family, model, and stepping ID values as encoded in `cpuid 1` + //! `eax`. + //! + //! This method must only be called when GetCPUArchitecture() indicates an + //! x86-family CPU architecture (#kCPUArchitectureX86 or + //! #kCPUArchitectureX86_64). + //! + //! \return An x86 family-specific value identifying the CPU signature. + virtual uint32_t CPUX86Signature() const = 0; + + //! \brief Returns an x86-family snapshot system’s CPU features. + //! + //! This is the feature information as encoded in `cpuid 1` `edx` and `ecx`. + //! `edx` is placed in the low half of the return value, and `ecx` is placed + //! in the high half. + //! + //! This method must only be called when GetCPUArchitecture() indicates an + //! x86-family CPU architecture (#kCPUArchitectureX86 or + //! #kCPUArchitectureX86_64). + //! + //! \return An x86 family-specific value identifying CPU features. + //! + //! \sa CPUX86ExtendedFeatures() + //! \sa CPUX86Leaf7Features() + virtual uint64_t CPUX86Features() const = 0; + + //! \brief Returns an x86-family snapshot system’s extended CPU features. + //! + //! This is the extended feature information as encoded in `cpuid 0x80000001` + //! `edx` and `ecx`. `edx` is placed in the low half of the return value, and + //! `ecx` is placed in the high half. + //! + //! This method must only be called when GetCPUArchitecture() indicates an + //! x86-family CPU architecture (#kCPUArchitectureX86 or + //! #kCPUArchitectureX86_64). + //! + //! \return An x86 family-specific value identifying extended CPU features. + //! + //! \sa CPUX86Features() + //! \sa CPUX86Leaf7Features() + virtual uint64_t CPUX86ExtendedFeatures() const = 0; + + //! \brief Returns an x86-family snapshot system’s “leaf 7” CPU features. + //! + //! This is the “leaf 7” feature information as encoded in `cpuid 7` `ebx`. If + //! `cpuid 7` is not supported by the snapshot CPU, this returns `0`. + //! + //! This method must only be called when GetCPUArchitecture() indicates an + //! x86-family CPU architecture (#kCPUArchitectureX86 or + //! #kCPUArchitectureX86_64). + //! + //! \return An x86 family-specific value identifying “leaf 7” CPU features. + //! + //! \sa CPUX86Features() + //! \sa CPUX86ExtendedFeatures() + virtual uint32_t CPUX86Leaf7Features() const = 0; + + //! \brief Returns an x86-family snapshot system’s CPU’s support for the SSE + //! DAZ (“denormals are zeros”) mode. + //! + //! This determines whether the CPU supports DAZ mode at all, not whether this + //! mode is enabled for any particular thread. DAZ mode support is detected by + //! examining the DAZ bit in the `mxcsr_mask` field of the floating-point + //! context saved by `fxsave`. + //! + //! This method must only be called when GetCPUArchitecture() indicates an + //! x86-family CPU architecture (#kCPUArchitectureX86 or + //! #kCPUArchitectureX86_64). + //! + //! \return `true` if the snapshot system’s CPUs support the SSE DAZ mode, + //! `false` if they do not. + virtual bool CPUX86SupportsDAZ() const = 0; + + //! \brief Returns the snapshot system’s operating system family. + virtual OperatingSystem GetOperatingSystem() const = 0; + + //! \brief Returns whether the snapshot system runs a server variant of its + //! operating system. + virtual bool OSServer() const = 0; + + //! \brief Returns the snapshot system’s operating system version information + //! in \a major, \a minor, \a bugfix, and \a build. + //! + //! \param[out] major The snapshot system’s operating system’s first (major) + //! version number component. This would be `10` for Mac OS X 10.9.5, and + //! `6` for Windows 7 (NT 6.1) SP1 version 6.1.7601. + //! \param[out] minor The snapshot system’s operating system’s second (minor) + //! version number component. This would be `9` for Mac OS X 10.9.5, and + //! `1` for Windows 7 (NT 6.1) SP1 version 6.1.7601. + //! \param[out] bugfix The snapshot system’s operating system’s third (bugfix) + //! version number component. This would be `5` for Mac OS X 10.9.5, and + //! `7601` for Windows 7 (NT 6.1) SP1 version 6.1.7601. + //! \param[out] build A string further identifying an operating system + //! version. For Mac OS X 10.9.5, this would be `"13F34"`. For Windows, + //! this would be `"Service Pack 1"` if that service pack was installed. + //! For Linux and other Unix-like systems, this would be the kernel + //! version from `uname -srvm`, possibly with additional information + //! appended. On Android, the `ro.build.fingerprint` system property would + //! be appended. + virtual void OSVersion(int* major, + int* minor, + int* bugfix, + std::string* build) const = 0; + + //! \brief Returns the snapshot system’s full operating system version + //! information in string format. + //! + //! For Mac OS X, the string contains values from the operating system and + //! kernel. A Mac OS X 10.9.5 snapshot system would be identified as `"Mac OS + //! X 10.9.5 (13F34); Darwin 13.4.0 Darwin Kernel Version 13.4.0: Sun Aug 17 + //! 19:50:11 PDT 2014; root:xnu-2422.115.4~1/RELEASE_X86_64 x86_64"`. + virtual std::string OSVersionFull() const = 0; + + //! \brief Returns a description of the snapshot system’s hardware in string + //! format. + //! + //! For Mac OS X, the string contains the Mac model and board ID. A mid-2014 + //! 15" MacBook Pro would be identified as `"MacBookPro11,3 + //! (Mac-2BD1B31983FE1663)"`. + virtual std::string MachineDescription() const = 0; + + //! \brief Returns the status of the NX (no-execute, or XD, execute-disable) + //! feature on the snapshot system. + //! + //! This refers to a feature that allows mapped readable pages to be marked + //! as non-executable. + //! + //! \return `true` if the snapshot system supports NX and it is enabled. + virtual bool NXEnabled() const = 0; + + //! \brief Returns time zone information from the snapshot system, based on + //! its locale configuration and real-time clock. + //! + //! \param[out] dst_status Whether the location observes daylight saving time, + //! and if so, whether it or standard time is currently being observed. + //! \param[out] standard_offset_seconds The number of seconds that the + //! location’s time zone is east (ahead) of UTC during standard time. + //! \param[out] daylight_offset_seconds The number of seconds that the + //! location’s time zone is east (ahead) of UTC during daylight saving. + //! time. + //! \param[out] standard_name The name of the time zone while standard time is + //! being observed. + //! \param[out] daylight_name The name of the time zone while daylight saving + //! time is being observed. + virtual void TimeZone(DaylightSavingTimeStatus* observes_daylight, + int* standard_offset_seconds, + int* daylight_offset_seconds, + std::string* standard_name, + std::string* daylight_name) const = 0; + + protected: + ~SystemSnapshot() {} +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_SYSTEM_SNAPSHOT_H_ diff --git a/snapshot/thread_snapshot.h b/snapshot/thread_snapshot.h new file mode 100644 index 00000000..5203c2a0 --- /dev/null +++ b/snapshot/thread_snapshot.h @@ -0,0 +1,69 @@ +// 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_SNAPSHOT_THREAD_SNAPSHOT_H_ +#define CRASHPAD_SNAPSHOT_THREAD_SNAPSHOT_H_ + +#include + +namespace crashpad { + +struct CPUContext; +class MemorySnapshot; + +//! \brief An abstract interface to a snapshot representing a thread +//! (lightweight process) present in a snapshot process. +class ThreadSnapshot { + public: + //! \brief Returns a CPUContext object corresponding to the thread’s CPU + //! context. + //! + //! The caller does not take ownership of this object, it is scoped to the + //! lifetime of the ThreadSnapshot object that it was obtained from. + virtual const CPUContext* Context() const = 0; + + //! \brief Returns a MemorySnapshot object corresponding to the memory region + //! that contains the thread’s stack. + //! + //! The caller does not take ownership of this object, it is scoped to the + //! lifetime of the ThreadSnapshot object that it was obtained from. + virtual const MemorySnapshot* Stack() const = 0; + + //! \brief Returns the thread’s identifier. + //! + //! Thread identifiers are at least unique within a process, and may be unique + //! system-wide. + virtual uint64_t ThreadID() const = 0; + + //! \brief Returns the thread’s suspend count. + //! + //! A suspend count of `0` denotes a schedulable (not suspended) thread. + virtual int SuspendCount() const = 0; + + //! \brief Returns the thread’s priority. + //! + //! Threads with higher priorities will have higher priority values. + virtual int Priority() const = 0; + + //! \brief Returns the base address of a region used to store thread-specific + //! data. + virtual uint64_t ThreadSpecificDataAddress() const = 0; + + protected: + ~ThreadSnapshot() {} +}; + +} // namespace crashpad + +#endif // CRASHPAD_SNAPSHOT_THREAD_SNAPSHOT_H_