crashpad/snapshot/win/process_reader_win.h

174 lines
5.7 KiB
C
Raw Normal View History

// Copyright 2015 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.
#ifndef CRASHPAD_SNAPSHOT_WIN_PROCESS_READER_WIN_H_
#define CRASHPAD_SNAPSHOT_WIN_PROCESS_READER_WIN_H_
#include <windows.h>
#include <sys/time.h>
#include <string>
#include <vector>
#include "build/build_config.h"
#include "util/misc/initialization_state_dcheck.h"
#include "util/process/process_memory_win.h"
#include "util/win/address_types.h"
#include "util/win/process_info.h"
namespace crashpad {
//! \brief State of process being read by ProcessReaderWin.
enum class ProcessSuspensionState : bool {
//! \brief The process has not been suspended.
kRunning,
//! \brief The process is suspended.
kSuspended,
};
//! \brief Accesses information about another process, identified by a `HANDLE`.
class ProcessReaderWin {
public:
//! \brief Helper to make the context copyable and resizable.
class ThreadContext {
public:
ThreadContext();
~ThreadContext() {}
template <typename T>
T* context() const {
DCHECK(initialized_);
return reinterpret_cast<T*>(
const_cast<unsigned char*>(data_.data() + offset_));
}
#if defined(ARCH_CPU_64_BITS)
bool InitializeWow64(HANDLE thread_handle);
#endif // ARCH_CPU_64_BITS
#if defined(ARCH_CPU_X86_64)
Captures shadow stack registers for x64 Windows contexts Windows extended contexts must be allocated by InitializeContext2 and may not be aligned. This means we cannot simply store a struct in our thread snapshot object, but must instead store enough memory and alias our struct onto this backing memory. Note that shadow stack pointers are not yet recorded for the initial exception - this cannot be determined using LocateXStateFeature in the capturing process and will be added in a future CL by plumbing through client messages when a crashed process requests a dump. See crash/32bd2c53a252705c for an example dump with this baked into chrome, that has passed through breakpad without breaking it. Local testing shows this creates valid dumps when built into Chrome, but that the referenced memory limits may need to be increased to allow for ssp referenced memory to be included. See "MANAGING STATE USING THE XSAVE FEATURE SET" Chapter 13 in the Intel SDM[0]. 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"[1]. [0] 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. [1] https://www.amd.com/system/files/TechDocs/24593.pdf Bug: 1250098 Change-Id: I4b13bcb023e9d5fba257044abfd7e251d66a9329 Reviewed-on: https://chromium-review.googlesource.com/c/crashpad/crashpad/+/3300992 Reviewed-by: Joshua Peraza <jperaza@chromium.org> Commit-Queue: Alex Gough <ajgo@chromium.org>
2022-05-16 15:38:37 -07:00
// Initializes internal structures for extended compacted contexts.
bool InitializeXState(HANDLE thread_handle, ULONG64 XStateCompactionMask);
#endif // ARCH_CPU_X86_64
void InitializeFromCurrentThread();
bool InitializeNative(HANDLE thread_handle);
private:
// This is usually 0 but Windows might cause it to be positive when
// fetching the extended context. This needs to be adjusted after
// calls to InitializeContext2().
size_t offset_;
bool initialized_;
std::vector<unsigned char> data_;
};
//! \brief Contains information about a thread that belongs to a process.
struct Thread {
Thread();
~Thread() {}
ThreadContext context;
std::string name;
uint64_t id;
WinVMAddress teb_address;
WinVMSize teb_size;
WinVMAddress stack_region_address;
WinVMSize stack_region_size;
uint32_t suspend_count;
uint32_t priority_class;
uint32_t priority;
};
ProcessReaderWin();
ProcessReaderWin(const ProcessReaderWin&) = delete;
ProcessReaderWin& operator=(const ProcessReaderWin&) = delete;
~ProcessReaderWin();
//! \brief Initializes this object. This method must be called before any
//! other.
//!
//! \param[in] process Process handle, must have `PROCESS_QUERY_INFORMATION`,
//! `PROCESS_VM_READ`, and `PROCESS_DUP_HANDLE` access.
//! \param[in] suspension_state Whether \a process has already been suspended
//! by the caller. Typically, this will be
//! ProcessSuspensionState::kSuspended, except for testing uses and where
//! the reader is reading itself.
//!
//! \return `true` on success, indicating that this object will respond
//! validly to further method calls. `false` on failure. On failure, no
//! further method calls should be made.
//!
//! \sa ScopedProcessSuspend
bool Initialize(HANDLE process, ProcessSuspensionState suspension_state);
//! \return `true` if the target task is a 64-bit process.
bool Is64Bit() const { return process_info_.Is64Bit(); }
//! \brief Return a memory reader for the target process.
const ProcessMemoryWin* Memory() const { return &process_memory_; }
win: Add more memory regions to gathering of PEB Previously: 0:000> !peb PEB at 7f374000 InheritedAddressSpace: No ReadImageFileExecOptions: No BeingDebugged: No ImageBaseAddress: 01380000 Ldr 77ec8b40 *** unable to read Ldr table at 77ec8b40 SubSystemData: 00000000 ProcessHeap: 00740000 ProcessParameters: 007414e0 CurrentDirectory: '< Name not readable >' WindowTitle: '< Name not readable >' ImageFile: '< Name not readable >' CommandLine: '< Name not readable >' DllPath: '< Name not readable >' Environment: 00000000 Unable to read Environment string. Now: 0:000> !peb PEB at 7f494000 InheritedAddressSpace: No ReadImageFileExecOptions: No BeingDebugged: No ImageBaseAddress: 00ef0000 Ldr 77ec8b40 Ldr.Initialized: Yes Ldr.InInitializationOrderModuleList: 01042b68 . 01043c68 Ldr.InLoadOrderModuleList: 01042c38 . 01043c58 Ldr.InMemoryOrderModuleList: 01042c40 . 01043c60 Base TimeStamp Module ef0000 5609bd17 Sep 28 15:20:07 2015 d:\src\crashpad\crashpad\out\debug\crashy_program.exe 77dc0000 55c599e1 Aug 07 22:55:45 2015 C:\Windows\SYSTEM32\ntdll.dll 758e0000 559f3b21 Jul 09 20:25:21 2015 C:\Windows\SYSTEM32\KERNEL32.DLL 76850000 559f3b2a Jul 09 20:25:30 2015 C:\Windows\SYSTEM32\KERNELBASE.dll SubSystemData: 00000000 ProcessHeap: 01040000 ProcessParameters: 01041520 CurrentDirectory: 'd:\src\crashpad\crashpad\' WindowTitle: 'out\debug\crashy_program.exe \\.\pipe\stuff' ImageFile: 'd:\src\crashpad\crashpad\out\debug\crashy_program.exe' CommandLine: 'out\debug\crashy_program.exe \\.\pipe\stuff' DllPath: '< Name not readable >' Environment: 010405c8 =D:=d:\src\crashpad\crashpad =ExitCode=C0000005 ALLUSERSPROFILE=C:\ProgramData APPDATA=C:\Users\scott\AppData\Roaming CommonProgramFiles=C:\Program Files (x86)\Common Files CommonProgramFiles(x86)=C:\Program Files (x86)\Common Files ... R=mark@chromium.org BUG=crashpad:46 Review URL: https://codereview.chromium.org/1360863006 .
2015-10-01 15:24:12 -07:00
//! \brief Determines the target process' start time.
//!
//! \param[out] start_time The time that the process started.
//!
//! \return `true` on success, `false` on failure, with a warning logged.
bool StartTime(timeval* start_time) const;
//! \brief Determines the target process' execution time.
//!
//! \param[out] user_time The amount of time the process has executed code in
//! user mode.
//! \param[out] system_time The amount of time the process has executed code
//! in kernel mode.
//!
//! \return `true` on success, `false` on failure, with a warning logged.
bool CPUTimes(timeval* user_time, timeval* system_time) const;
//! \return The threads that are in the process. The first element (at index
//! `0`) corresponds to the main thread.
const std::vector<Thread>& Threads();
//! \return The modules loaded in the process. The first element (at index
//! `0`) corresponds to the main executable.
const std::vector<ProcessInfo::Module>& Modules();
win: Save contents of PEB to minidump to start making !peb work This makes the basics of !peb work in windbg, however, pointed-to things are not yet retrieved. For full functionality, a variety of pointers in the PEB also needs to be walked and captured. e.g. Previously: 0:000> .ecxr eax=00000007 ebx=7e383000 ecx=c3f9a943 edx=00000000 esi=006d62d0 edi=003c9280 eip=00384828 esp=005bf634 ebp=005bf638 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246 crashy_program!crashpad::`anonymous namespace'::SomeCrashyFunction+0x28: 00384828 c7002a000000 mov dword ptr [eax],2Ah ds:002b:00000007=???????? 0:000> !peb PEB at 7e383000 error 1 InitTypeRead( nt!_PEB at 7e383000)... Now: 0:000> .ecxr eax=00000007 ebx=7f958000 ecx=02102f4d edx=00000000 esi=00e162d0 edi=01389280 eip=01344828 esp=00c2fb64 ebp=00c2fb68 iopl=0 nv up ei pl zr na pe nc cs=0023 ss=002b ds=002b es=002b fs=0053 gs=002b efl=00010246 crashy_program!crashpad::`anonymous namespace'::SomeCrashyFunction+0x28: 01344828 c7002a000000 mov dword ptr [eax],2Ah ds:002b:00000007=???????? 0:000> !peb PEB at 7f958000 InheritedAddressSpace: No ReadImageFileExecOptions: No BeingDebugged: No ImageBaseAddress: 01340000 Ldr 77ec8b40 *** unable to read Ldr table at 77ec8b40 SubSystemData: 00000000 ProcessHeap: 00e10000 ProcessParameters: 00e114e0 CurrentDirectory: '< Name not readable >' WindowTitle: '< Name not readable >' ImageFile: '< Name not readable >' CommandLine: '< Name not readable >' DllPath: '< Name not readable >' Environment: 00000000 Unable to read Environment string. R=mark@chromium.org BUG=crashpad:46 Review URL: https://codereview.chromium.org/1364053002 .
2015-09-25 10:31:02 -07:00
//! \return A ProcessInfo object for the process being read.
const ProcessInfo& GetProcessInfo() const;
//! \brief Decrements the thread suspend counts for all thread ids other than
//! \a except_thread_id.
//!
//! Used to adjust the thread suspend count to correspond to the actual values
//! for the process before Crashpad got involved.
void DecrementThreadSuspendCounts(uint64_t except_thread_id);
private:
template <class Traits>
void ReadThreadData(bool is_64_reading_32);
HANDLE process_;
ProcessInfo process_info_;
ProcessMemoryWin process_memory_;
std::vector<Thread> threads_;
std::vector<ProcessInfo::Module> modules_;
ProcessSuspensionState suspension_state_;
bool initialized_threads_;
InitializationStateDcheck initialized_;
};
} // namespace crashpad
#endif // CRASHPAD_SNAPSHOT_WIN_PROCESS_READER_WIN_H_