mirror of
https://github.com/chromium/crashpad.git
synced 2024-12-26 23:01:05 +08:00
win: Capture memory pointed to by the stack
Change-Id: Ide75475aa9c42edf36c3a709bfc7dfbfed68b0d3 Reviewed-on: https://chromium-review.googlesource.com/322261 Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
parent
83247fda60
commit
feb3aa3923
@ -28,6 +28,7 @@
|
||||
#include "base/macros.h"
|
||||
#include "build/build_config.h"
|
||||
#include "client/crashpad_client.h"
|
||||
#include "client/crashpad_info.h"
|
||||
#include "util/win/critical_section_with_debug_info.h"
|
||||
#include "util/win/get_function.h"
|
||||
|
||||
@ -164,6 +165,18 @@ int CrashyMain(int argc, wchar_t* argv[]) {
|
||||
return EXIT_FAILURE;
|
||||
}
|
||||
|
||||
// Make sure data pointed to by the stack is captured.
|
||||
const int kDataSize = 512;
|
||||
int* pointed_to_data = new int[kDataSize];
|
||||
for (int i = 0; i < kDataSize; ++i)
|
||||
pointed_to_data[i] = i | ((i % 2 == 0) ? 0x80000000 : 0);
|
||||
int* offset_pointer = &pointed_to_data[128];
|
||||
// Encourage the compiler to keep this variable around.
|
||||
printf("%p, %p\n", offset_pointer, &offset_pointer);
|
||||
|
||||
crashpad::CrashpadInfo::GetCrashpadInfo()
|
||||
->set_gather_indirectly_referenced_memory(TriState::kEnabled);
|
||||
|
||||
AllocateMemoryOfVariousProtections();
|
||||
|
||||
if (InitializeCriticalSectionWithDebugInfoIfPossible(
|
||||
|
128
snapshot/capture_memory.cc
Normal file
128
snapshot/capture_memory.cc
Normal file
@ -0,0 +1,128 @@
|
||||
// Copyright 2016 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/capture_memory.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "base/memory/scoped_ptr.h"
|
||||
#include "snapshot/memory_snapshot.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
|
||||
void MaybeCaptureMemoryAround(CaptureMemory::Delegate* delegate,
|
||||
uint64_t address) {
|
||||
const uint64_t non_address_offset = 0x10000;
|
||||
if (address < non_address_offset)
|
||||
return;
|
||||
|
||||
const uint64_t max_address = delegate->Is64Bit() ?
|
||||
std::numeric_limits<uint64_t>::max() :
|
||||
std::numeric_limits<uint32_t>::max();
|
||||
if (address > max_address - non_address_offset)
|
||||
return;
|
||||
|
||||
const uint64_t kRegisterByteOffset = 256;
|
||||
const uint64_t target = address - kRegisterByteOffset;
|
||||
const uint64_t size = 1024;
|
||||
static_assert(kRegisterByteOffset <= size / 2,
|
||||
"negative offset too large");
|
||||
auto ranges =
|
||||
delegate->GetReadableRanges(CheckedRange<uint64_t>(target, size));
|
||||
for (const auto& range : ranges) {
|
||||
delegate->AddNewMemorySnapshot(range);
|
||||
}
|
||||
}
|
||||
|
||||
template <class T>
|
||||
void CaptureAtPointersInRange(uint8_t* buffer,
|
||||
uint64_t buffer_size,
|
||||
CaptureMemory::Delegate* delegate) {
|
||||
for (uint64_t address_offset = 0; address_offset < buffer_size;
|
||||
address_offset += sizeof(T)) {
|
||||
uint64_t target_address = *reinterpret_cast<T*>(&buffer[address_offset]);
|
||||
MaybeCaptureMemoryAround(delegate, target_address);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
// static
|
||||
void CaptureMemory::PointedToByContext(const CPUContext& context,
|
||||
Delegate* delegate) {
|
||||
#if defined(ARCH_CPU_X86_FAMILY)
|
||||
if (context.architecture == kCPUArchitectureX86_64) {
|
||||
MaybeCaptureMemoryAround(delegate, context.x86_64->rax);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86_64->rbx);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86_64->rcx);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86_64->rdx);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86_64->rdi);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86_64->rsi);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86_64->rbp);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86_64->r8);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86_64->r9);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86_64->r10);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86_64->r11);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86_64->r12);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86_64->r13);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86_64->r14);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86_64->r15);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86_64->rip);
|
||||
} else {
|
||||
MaybeCaptureMemoryAround(delegate, context.x86->eax);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86->ebx);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86->ecx);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86->edx);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86->edi);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86->esi);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86->ebp);
|
||||
MaybeCaptureMemoryAround(delegate, context.x86->eip);
|
||||
}
|
||||
#else
|
||||
#error non-x86
|
||||
#endif
|
||||
}
|
||||
|
||||
// static
|
||||
void CaptureMemory::PointedToByMemoryRange(const MemorySnapshot& memory,
|
||||
Delegate* delegate) {
|
||||
if (memory.Size() == 0)
|
||||
return;
|
||||
|
||||
const size_t alignment =
|
||||
delegate->Is64Bit() ? sizeof(uint64_t) : sizeof(uint32_t);
|
||||
if (memory.Address() % alignment != 0 || memory.Size() % alignment != 0) {
|
||||
LOG(ERROR) << "unaligned range";
|
||||
return;
|
||||
}
|
||||
|
||||
scoped_ptr<uint8_t[]> buffer(new uint8_t[memory.Size()]);
|
||||
if (!delegate->ReadMemory(memory.Address(), memory.Size(), buffer.get())) {
|
||||
LOG(ERROR) << "ReadMemory";
|
||||
return;
|
||||
}
|
||||
|
||||
if (delegate->Is64Bit())
|
||||
CaptureAtPointersInRange<uint64_t>(buffer.get(), memory.Size(), delegate);
|
||||
else
|
||||
CaptureAtPointersInRange<uint32_t>(buffer.get(), memory.Size(), delegate);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
98
snapshot/capture_memory.h
Normal file
98
snapshot/capture_memory.h
Normal file
@ -0,0 +1,98 @@
|
||||
// Copyright 2016 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_CAPTURE_MEMORY_H_
|
||||
#define CRASHPAD_SNAPSHOT_CAPTURE_MEMORY_H_
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <vector>
|
||||
|
||||
#include "snapshot/cpu_context.h"
|
||||
#include "util/numeric/checked_range.h"
|
||||
|
||||
namespace crashpad {
|
||||
|
||||
class MemorySnapshot;
|
||||
|
||||
namespace internal {
|
||||
|
||||
class CaptureMemory {
|
||||
public:
|
||||
//! \brief An interface to a platform-specific process reader.
|
||||
class Delegate {
|
||||
public:
|
||||
virtual ~Delegate() {}
|
||||
|
||||
//! \return `true` if the target process is a 64-bit process.
|
||||
virtual bool Is64Bit() const = 0;
|
||||
|
||||
//! \brief Attempts to read \a num_bytes bytes from the target process
|
||||
//! starting at address \a at into \a into.
|
||||
//!
|
||||
//! \return `true` if the entire region could be read, or `false` with an
|
||||
//! error logged.
|
||||
virtual bool ReadMemory(uint64_t at,
|
||||
uint64_t num_bytes,
|
||||
void* into) const = 0;
|
||||
|
||||
//! \brief Given a range to be read from the target process, returns a
|
||||
//! vector
|
||||
//! of ranges, representing the readable portions of the original range.
|
||||
//!
|
||||
//! \param[in] range The range being identified.
|
||||
//!
|
||||
//! \return A vector of ranges corresponding to the portion of \a range that
|
||||
//! is readable.
|
||||
virtual std::vector<CheckedRange<uint64_t>> GetReadableRanges(
|
||||
const CheckedRange<uint64_t, uint64_t>& range) const = 0;
|
||||
|
||||
//! \brief Adds the given range representing a memory snapshot in the target
|
||||
//! process to the result.
|
||||
virtual void AddNewMemorySnapshot(
|
||||
const CheckedRange<uint64_t, uint64_t>& range) = 0;
|
||||
};
|
||||
|
||||
//! \brief For all registers that appear to be pointer-like in \a context,
|
||||
//! captures a small amount of memory near their pointed to location.
|
||||
//!
|
||||
//! "Pointer-like" in this context means not too close to zero (signed or
|
||||
//! unsigned) so that there's a reasonable chance that the value is a pointer.
|
||||
//!
|
||||
//! \param[in] context The context to inspect.
|
||||
//! \param[in] process_reader A MemoryCaptureProcessReader to read from the
|
||||
//! target process, and that handles adding new ranges.
|
||||
static void PointedToByContext(const CPUContext& context, Delegate* delegate);
|
||||
|
||||
//! \brief For all pointer-like values in a memory range of the target
|
||||
//! process,
|
||||
//! captures a small amount of memory near the pointed to location.
|
||||
//!
|
||||
//! \param[in] memory An existing MemorySnapshot of the range to search. The
|
||||
//! base address and size must be pointer-aligned and an integral number
|
||||
//! of
|
||||
//! pointers long.
|
||||
//! \param[in] process_reader A MemoryCaptureProcessReader to read from the
|
||||
//! target process, and that handles adding new ranges.
|
||||
static void PointedToByMemoryRange(const MemorySnapshot& memory,
|
||||
Delegate* delegate);
|
||||
|
||||
private:
|
||||
DISALLOW_IMPLICIT_CONSTRUCTORS(CaptureMemory);
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_SNAPSHOT_CAPTURE_MEMORY_H_
|
@ -70,14 +70,13 @@ class ScopedUnsetCrashpadInfoOptions {
|
||||
DISALLOW_COPY_AND_ASSIGN(ScopedUnsetCrashpadInfoOptions);
|
||||
};
|
||||
|
||||
TEST(CrashpadInfoClientOptions, OneModule) {
|
||||
// Make sure that the initial state has all values unset.
|
||||
CrashpadInfoClientOptions SelfProcessSnapshotAndGetCrashpadOptions() {
|
||||
#if defined(OS_MACOSX)
|
||||
ProcessSnapshotMac process_snapshot;
|
||||
ASSERT_TRUE(process_snapshot.Initialize(mach_task_self()));
|
||||
EXPECT_TRUE(process_snapshot.Initialize(mach_task_self()));
|
||||
#elif defined(OS_WIN)
|
||||
ProcessSnapshotWin process_snapshot;
|
||||
ASSERT_TRUE(process_snapshot.Initialize(
|
||||
EXPECT_TRUE(process_snapshot.Initialize(
|
||||
GetCurrentProcess(), ProcessSuspensionState::kRunning, 0));
|
||||
#else
|
||||
#error Port.
|
||||
@ -85,6 +84,12 @@ TEST(CrashpadInfoClientOptions, OneModule) {
|
||||
|
||||
CrashpadInfoClientOptions options;
|
||||
process_snapshot.GetCrashpadOptions(&options);
|
||||
return options;
|
||||
}
|
||||
|
||||
TEST(CrashpadInfoClientOptions, OneModule) {
|
||||
// Make sure that the initial state has all values unset.
|
||||
auto options = SelfProcessSnapshotAndGetCrashpadOptions();
|
||||
|
||||
EXPECT_EQ(TriState::kUnset, options.crashpad_handler_behavior);
|
||||
EXPECT_EQ(TriState::kUnset, options.system_crash_reporter_forwarding);
|
||||
@ -98,7 +103,7 @@ TEST(CrashpadInfoClientOptions, OneModule) {
|
||||
|
||||
crashpad_info->set_crashpad_handler_behavior(TriState::kEnabled);
|
||||
|
||||
process_snapshot.GetCrashpadOptions(&options);
|
||||
options = SelfProcessSnapshotAndGetCrashpadOptions();
|
||||
EXPECT_EQ(TriState::kEnabled, options.crashpad_handler_behavior);
|
||||
EXPECT_EQ(TriState::kUnset, options.system_crash_reporter_forwarding);
|
||||
EXPECT_EQ(TriState::kUnset, options.gather_indirectly_referenced_memory);
|
||||
@ -109,7 +114,7 @@ TEST(CrashpadInfoClientOptions, OneModule) {
|
||||
|
||||
crashpad_info->set_system_crash_reporter_forwarding(TriState::kDisabled);
|
||||
|
||||
process_snapshot.GetCrashpadOptions(&options);
|
||||
options = SelfProcessSnapshotAndGetCrashpadOptions();
|
||||
EXPECT_EQ(TriState::kUnset, options.crashpad_handler_behavior);
|
||||
EXPECT_EQ(TriState::kDisabled, options.system_crash_reporter_forwarding);
|
||||
EXPECT_EQ(TriState::kUnset, options.gather_indirectly_referenced_memory);
|
||||
@ -120,7 +125,7 @@ TEST(CrashpadInfoClientOptions, OneModule) {
|
||||
|
||||
crashpad_info->set_gather_indirectly_referenced_memory(TriState::kEnabled);
|
||||
|
||||
process_snapshot.GetCrashpadOptions(&options);
|
||||
options = SelfProcessSnapshotAndGetCrashpadOptions();
|
||||
EXPECT_EQ(TriState::kUnset, options.crashpad_handler_behavior);
|
||||
EXPECT_EQ(TriState::kUnset, options.system_crash_reporter_forwarding);
|
||||
EXPECT_EQ(TriState::kEnabled, options.gather_indirectly_referenced_memory);
|
||||
@ -199,21 +204,9 @@ TEST(CrashpadInfoClientOptions, TwoModules) {
|
||||
dl_handle.LookUpSymbol<CrashpadInfo* (*)()>("TestModule_GetCrashpadInfo");
|
||||
ASSERT_TRUE(TestModule_GetCrashpadInfo);
|
||||
|
||||
auto options = SelfProcessSnapshotAndGetCrashpadOptions();
|
||||
|
||||
// Make sure that the initial state has all values unset.
|
||||
#if defined(OS_MACOSX)
|
||||
ProcessSnapshotMac process_snapshot;
|
||||
ASSERT_TRUE(process_snapshot.Initialize(mach_task_self()));
|
||||
#elif defined(OS_WIN)
|
||||
ProcessSnapshotWin process_snapshot;
|
||||
ASSERT_TRUE(process_snapshot.Initialize(
|
||||
GetCurrentProcess(), ProcessSuspensionState::kRunning, 0));
|
||||
#else
|
||||
#error Port.
|
||||
#endif // OS_MACOSX
|
||||
|
||||
CrashpadInfoClientOptions options;
|
||||
process_snapshot.GetCrashpadOptions(&options);
|
||||
|
||||
EXPECT_EQ(TriState::kUnset, options.crashpad_handler_behavior);
|
||||
EXPECT_EQ(TriState::kUnset, options.system_crash_reporter_forwarding);
|
||||
EXPECT_EQ(TriState::kUnset, options.gather_indirectly_referenced_memory);
|
||||
@ -232,7 +225,7 @@ TEST(CrashpadInfoClientOptions, TwoModules) {
|
||||
// When only one module sets a value, it applies to the entire process.
|
||||
remote_crashpad_info->set_crashpad_handler_behavior(TriState::kEnabled);
|
||||
|
||||
process_snapshot.GetCrashpadOptions(&options);
|
||||
options = SelfProcessSnapshotAndGetCrashpadOptions();
|
||||
EXPECT_EQ(TriState::kEnabled, options.crashpad_handler_behavior);
|
||||
EXPECT_EQ(TriState::kUnset, options.system_crash_reporter_forwarding);
|
||||
EXPECT_EQ(TriState::kUnset, options.gather_indirectly_referenced_memory);
|
||||
@ -242,7 +235,7 @@ TEST(CrashpadInfoClientOptions, TwoModules) {
|
||||
// module, because the local module loaded the remote module.
|
||||
local_crashpad_info->set_crashpad_handler_behavior(TriState::kDisabled);
|
||||
|
||||
process_snapshot.GetCrashpadOptions(&options);
|
||||
options = SelfProcessSnapshotAndGetCrashpadOptions();
|
||||
EXPECT_EQ(TriState::kDisabled, options.crashpad_handler_behavior);
|
||||
EXPECT_EQ(TriState::kUnset, options.system_crash_reporter_forwarding);
|
||||
EXPECT_EQ(TriState::kUnset, options.gather_indirectly_referenced_memory);
|
||||
@ -256,7 +249,7 @@ TEST(CrashpadInfoClientOptions, TwoModules) {
|
||||
remote_crashpad_info->set_system_crash_reporter_forwarding(
|
||||
TriState::kDisabled);
|
||||
|
||||
process_snapshot.GetCrashpadOptions(&options);
|
||||
options = SelfProcessSnapshotAndGetCrashpadOptions();
|
||||
EXPECT_EQ(TriState::kUnset, options.crashpad_handler_behavior);
|
||||
EXPECT_EQ(TriState::kDisabled, options.system_crash_reporter_forwarding);
|
||||
EXPECT_EQ(TriState::kUnset, options.gather_indirectly_referenced_memory);
|
||||
@ -267,7 +260,7 @@ TEST(CrashpadInfoClientOptions, TwoModules) {
|
||||
local_crashpad_info->set_system_crash_reporter_forwarding(
|
||||
TriState::kEnabled);
|
||||
|
||||
process_snapshot.GetCrashpadOptions(&options);
|
||||
options = SelfProcessSnapshotAndGetCrashpadOptions();
|
||||
EXPECT_EQ(TriState::kUnset, options.crashpad_handler_behavior);
|
||||
EXPECT_EQ(TriState::kEnabled, options.system_crash_reporter_forwarding);
|
||||
EXPECT_EQ(TriState::kUnset, options.gather_indirectly_referenced_memory);
|
||||
|
@ -30,6 +30,8 @@
|
||||
'..',
|
||||
],
|
||||
'sources': [
|
||||
'capture_memory.cc',
|
||||
'capture_memory.h',
|
||||
'cpu_architecture.h',
|
||||
'cpu_context.cc',
|
||||
'cpu_context.h',
|
||||
@ -89,12 +91,12 @@
|
||||
'process_snapshot.h',
|
||||
'system_snapshot.h',
|
||||
'thread_snapshot.h',
|
||||
'win/capture_context_memory.cc',
|
||||
'win/capture_context_memory.h',
|
||||
'win/cpu_context_win.cc',
|
||||
'win/cpu_context_win.h',
|
||||
'win/exception_snapshot_win.cc',
|
||||
'win/exception_snapshot_win.h',
|
||||
'win/capture_memory_delegate_win.cc',
|
||||
'win/capture_memory_delegate_win.h',
|
||||
'win/memory_map_region_snapshot_win.cc',
|
||||
'win/memory_map_region_snapshot_win.h',
|
||||
'win/memory_snapshot_win.cc',
|
||||
|
@ -1,103 +0,0 @@
|
||||
// Copyright 2016 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/win/capture_context_memory.h"
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
#include <limits>
|
||||
|
||||
#include "snapshot/win/memory_snapshot_win.h"
|
||||
#include "snapshot/win/process_reader_win.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
|
||||
namespace {
|
||||
|
||||
void MaybeCaptureMemoryAround(ProcessReaderWin* process_reader,
|
||||
WinVMAddress address,
|
||||
PointerVector<MemorySnapshotWin>* into) {
|
||||
const WinVMAddress non_address_offset = 0x10000;
|
||||
if (address < non_address_offset)
|
||||
return;
|
||||
if (process_reader->Is64Bit()) {
|
||||
if (address >= std::numeric_limits<uint64_t>::max() - non_address_offset)
|
||||
return;
|
||||
} else {
|
||||
if (address >= std::numeric_limits<uint32_t>::max() - non_address_offset)
|
||||
return;
|
||||
}
|
||||
|
||||
const WinVMSize kRegisterByteOffset = 32;
|
||||
const WinVMAddress target = address - kRegisterByteOffset;
|
||||
const WinVMSize size = 128;
|
||||
auto ranges = process_reader->GetProcessInfo().GetReadableRanges(
|
||||
CheckedRange<WinVMAddress, WinVMSize>(target, size));
|
||||
for (const auto& range : ranges) {
|
||||
internal::MemorySnapshotWin* snapshot = new internal::MemorySnapshotWin();
|
||||
snapshot->Initialize(process_reader, range.base(), range.size());
|
||||
into->push_back(snapshot);
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
void CaptureMemoryPointedToByContext(const CPUContext& context,
|
||||
ProcessReaderWin* process_reader,
|
||||
const ProcessReaderWin::Thread& thread,
|
||||
PointerVector<MemorySnapshotWin>* into) {
|
||||
#if defined(ARCH_CPU_X86_64)
|
||||
if (context.architecture == kCPUArchitectureX86_64) {
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86_64->rax, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86_64->rbx, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86_64->rcx, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86_64->rdx, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86_64->rdi, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86_64->rsi, into);
|
||||
if (context.x86_64->rbp < thread.stack_region_address ||
|
||||
context.x86_64->rbp >=
|
||||
thread.stack_region_address + thread.stack_region_size) {
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86_64->rbp, into);
|
||||
}
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86_64->r8, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86_64->r9, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86_64->r10, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86_64->r11, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86_64->r12, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86_64->r13, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86_64->r14, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86_64->r15, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86_64->rip, into);
|
||||
} else {
|
||||
#endif
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86->eax, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86->ebx, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86->ecx, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86->edx, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86->edi, into);
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86->esi, into);
|
||||
if (context.x86->ebp < thread.stack_region_address ||
|
||||
context.x86->ebp >=
|
||||
thread.stack_region_address + thread.stack_region_size) {
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86->ebp, into);
|
||||
}
|
||||
MaybeCaptureMemoryAround(process_reader, context.x86->eip, into);
|
||||
#if defined(ARCH_CPU_X86_64)
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
@ -1,43 +0,0 @@
|
||||
// Copyright 2016 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_WIN_CAPTURE_CONTEXT_MEMORY_H_
|
||||
#define CRASHPAD_SNAPSHOT_WIN_CAPTURE_CONTEXT_MEMORY_H_
|
||||
|
||||
#include "snapshot/cpu_context.h"
|
||||
#include "snapshot/win/process_reader_win.h"
|
||||
#include "util/stdlib/pointer_container.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
|
||||
class MemorySnapshotWin;
|
||||
|
||||
//! \brief For all registers that appear to be pointer-like in \a context,
|
||||
//! captures a small amount of memory near their pointed to location.
|
||||
//!
|
||||
//! \param[in] context The context to inspect.
|
||||
//! \param[in] process_reader A ProcessReaderWin to read from the target
|
||||
//! process.
|
||||
//! \param[in] thread The thread to which the context belongs.
|
||||
//! \param[out] into A vector of pointers to append new ranges to.
|
||||
void CaptureMemoryPointedToByContext(const CPUContext& context,
|
||||
ProcessReaderWin* process_reader,
|
||||
const ProcessReaderWin::Thread& thread,
|
||||
PointerVector<MemorySnapshotWin>* into);
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_SNAPSHOT_WIN_CAPTURE_CONTEXT_MEMORY_H_
|
56
snapshot/win/capture_memory_delegate_win.cc
Normal file
56
snapshot/win/capture_memory_delegate_win.cc
Normal file
@ -0,0 +1,56 @@
|
||||
// Copyright 2016 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/win/capture_memory_delegate_win.h"
|
||||
|
||||
#include "snapshot/win/memory_snapshot_win.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
|
||||
CaptureMemoryDelegateWin::CaptureMemoryDelegateWin(
|
||||
ProcessReaderWin* process_reader,
|
||||
const ProcessReaderWin::Thread& thread,
|
||||
PointerVector<MemorySnapshotWin>* snapshots)
|
||||
: stack_(thread.stack_region_address, thread.stack_region_size),
|
||||
process_reader_(process_reader),
|
||||
snapshots_(snapshots) {}
|
||||
|
||||
bool CaptureMemoryDelegateWin::Is64Bit() const {
|
||||
return process_reader_->Is64Bit();
|
||||
}
|
||||
|
||||
bool CaptureMemoryDelegateWin::ReadMemory(uint64_t at,
|
||||
uint64_t num_bytes,
|
||||
void* into) const {
|
||||
return process_reader_->ReadMemory(at, num_bytes, into);
|
||||
}
|
||||
|
||||
std::vector<CheckedRange<uint64_t>> CaptureMemoryDelegateWin::GetReadableRanges(
|
||||
const CheckedRange<uint64_t, uint64_t>& range) const {
|
||||
return process_reader_->GetProcessInfo().GetReadableRanges(range);
|
||||
}
|
||||
|
||||
void CaptureMemoryDelegateWin::AddNewMemorySnapshot(
|
||||
const CheckedRange<uint64_t, uint64_t>& range) {
|
||||
// Don't bother storing this memory if it points back into the stack.
|
||||
if (stack_.ContainsRange(range))
|
||||
return;
|
||||
internal::MemorySnapshotWin* snapshot = new internal::MemorySnapshotWin();
|
||||
snapshot->Initialize(process_reader_, range.base(), range.size());
|
||||
snapshots_->push_back(snapshot);
|
||||
}
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
58
snapshot/win/capture_memory_delegate_win.h
Normal file
58
snapshot/win/capture_memory_delegate_win.h
Normal file
@ -0,0 +1,58 @@
|
||||
// Copyright 2016 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_WIN_CAPTURE_MEMORY_DELEGATE_WIN_H_
|
||||
#define CRASHPAD_SNAPSHOT_WIN_CAPTURE_MEMORY_DELEGATE_WIN_H_
|
||||
|
||||
#include "snapshot/capture_memory.h"
|
||||
|
||||
#include "snapshot/win/process_reader_win.h"
|
||||
#include "util/stdlib/pointer_container.h"
|
||||
|
||||
namespace crashpad {
|
||||
namespace internal {
|
||||
|
||||
class MemorySnapshotWin;
|
||||
|
||||
class CaptureMemoryDelegateWin : public CaptureMemory::Delegate {
|
||||
public:
|
||||
//! \brief A MemoryCaptureDelegate for Windows.
|
||||
//!
|
||||
//! \param[in] process_reader A ProcessReaderWin for the target process.
|
||||
//! \param[in] thread The thread being inspected. Memory ranges overlapping
|
||||
//! this thread's stack will be ignored on the assumption that they're
|
||||
//! already captured elsewhere.
|
||||
//! \param[in] snapshots A vector of MemorySnapshotWin to which the captured
|
||||
//! memory will be added.
|
||||
CaptureMemoryDelegateWin(ProcessReaderWin* process_reader,
|
||||
const ProcessReaderWin::Thread& thread,
|
||||
PointerVector<MemorySnapshotWin>* snapshots);
|
||||
|
||||
// MemoryCaptureDelegate:
|
||||
bool Is64Bit() const override;
|
||||
bool ReadMemory(uint64_t at, uint64_t num_bytes, void* into) const override;
|
||||
std::vector<CheckedRange<uint64_t>> GetReadableRanges(
|
||||
const CheckedRange<uint64_t, uint64_t>& range) const override;
|
||||
void AddNewMemorySnapshot(const CheckedRange<uint64_t, uint64_t>& range);
|
||||
|
||||
private:
|
||||
CheckedRange<uint64_t, uint64_t> stack_;
|
||||
ProcessReaderWin* process_reader_;
|
||||
PointerVector<MemorySnapshotWin>* snapshots_;
|
||||
};
|
||||
|
||||
} // namespace internal
|
||||
} // namespace crashpad
|
||||
|
||||
#endif // CRASHPAD_SNAPSHOT_WIN_CAPTURE_MEMORY_DELEGATE_WIN_H_
|
@ -247,10 +247,22 @@ def RunTests(cdb_path,
|
||||
r'FreeOwnStackAndBreak.*\nquit:',
|
||||
'at correct location, no additional stack entries')
|
||||
|
||||
# Switch to the other thread after jumping to the exception, and examine
|
||||
# memory.
|
||||
out = CdbRun(cdb_path, dump_path, '.ecxr; ~1s; db /c14 edi')
|
||||
out.Check(r'63 62 61 60 5f 5e 5d 5c-5b 5a 59 58 57 56 55 54 53 52 51 50',
|
||||
'data pointed to by registers captured')
|
||||
|
||||
# Move up one stack frame after jumping to the exception, and examine memory.
|
||||
out = CdbRun(cdb_path, dump_path,
|
||||
'.ecxr; .f+; dd /c100 poi(offset_pointer)-20')
|
||||
out.Check(r'80000078 00000079 8000007a 0000007b 8000007c 0000007d 8000007e '
|
||||
r'0000007f 80000080 00000081 80000082 00000083 80000084 00000085 '
|
||||
r'80000086 00000087 80000088 00000089 8000008a 0000008b 8000008c '
|
||||
r'0000008d 8000008e 0000008f 80000090 00000091 80000092 00000093 '
|
||||
r'80000094 00000095 80000096 00000097',
|
||||
'data pointed to by stack captured')
|
||||
|
||||
if z7_dump_path:
|
||||
out = CdbRun(cdb_path, z7_dump_path, '.ecxr;lm')
|
||||
out.Check('This dump file has an exception of interest stored in it',
|
||||
|
@ -14,9 +14,10 @@
|
||||
|
||||
#include "snapshot/win/exception_snapshot_win.h"
|
||||
|
||||
#include "snapshot/capture_memory.h"
|
||||
#include "snapshot/memory_snapshot.h"
|
||||
#include "snapshot/win/capture_context_memory.h"
|
||||
#include "snapshot/win/cpu_context_win.h"
|
||||
#include "snapshot/win/capture_memory_delegate_win.h"
|
||||
#include "snapshot/win/memory_snapshot_win.h"
|
||||
#include "snapshot/win/process_reader_win.h"
|
||||
#include "util/win/nt_internals.h"
|
||||
@ -89,8 +90,9 @@ bool ExceptionSnapshotWin::Initialize(ProcessReaderWin* process_reader,
|
||||
InitializeX86Context(context_record, context_.x86);
|
||||
}
|
||||
|
||||
CaptureMemoryPointedToByContext(
|
||||
context_, process_reader, *thread, &extra_memory_);
|
||||
CaptureMemoryDelegateWin capture_memory_delegate(
|
||||
process_reader, *thread, &extra_memory_);
|
||||
CaptureMemory::PointedToByContext(context_, &capture_memory_delegate);
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
|
@ -38,6 +38,7 @@ ProcessSnapshotWin::ProcessSnapshotWin()
|
||||
client_id_(),
|
||||
annotations_simple_map_(),
|
||||
snapshot_time_(),
|
||||
options_(),
|
||||
initialized_() {
|
||||
}
|
||||
|
||||
@ -65,9 +66,13 @@ bool ProcessSnapshotWin::Initialize(
|
||||
debug_critical_section_address);
|
||||
}
|
||||
|
||||
InitializeThreads();
|
||||
InitializeModules();
|
||||
|
||||
GetCrashpadOptionsInternal(&options_);
|
||||
|
||||
InitializeThreads(options_.gather_indirectly_referenced_memory ==
|
||||
TriState::kEnabled);
|
||||
|
||||
for (const MEMORY_BASIC_INFORMATION64& mbi :
|
||||
process_reader_.GetProcessInfo().MemoryInfo()) {
|
||||
memory_map_.push_back(new internal::MemoryMapRegionSnapshotWin(mbi));
|
||||
@ -104,35 +109,7 @@ bool ProcessSnapshotWin::InitializeException(
|
||||
void ProcessSnapshotWin::GetCrashpadOptions(
|
||||
CrashpadInfoClientOptions* options) {
|
||||
INITIALIZATION_STATE_DCHECK_VALID(initialized_);
|
||||
|
||||
CrashpadInfoClientOptions local_options;
|
||||
|
||||
for (internal::ModuleSnapshotWin* module : modules_) {
|
||||
CrashpadInfoClientOptions module_options;
|
||||
module->GetCrashpadOptions(&module_options);
|
||||
|
||||
if (local_options.crashpad_handler_behavior == TriState::kUnset) {
|
||||
local_options.crashpad_handler_behavior =
|
||||
module_options.crashpad_handler_behavior;
|
||||
}
|
||||
if (local_options.system_crash_reporter_forwarding == TriState::kUnset) {
|
||||
local_options.system_crash_reporter_forwarding =
|
||||
module_options.system_crash_reporter_forwarding;
|
||||
}
|
||||
if (local_options.gather_indirectly_referenced_memory == TriState::kUnset) {
|
||||
local_options.gather_indirectly_referenced_memory =
|
||||
module_options.gather_indirectly_referenced_memory;
|
||||
}
|
||||
|
||||
// If non-default values have been found for all options, the loop can end
|
||||
// early.
|
||||
if (local_options.crashpad_handler_behavior != TriState::kUnset &&
|
||||
local_options.system_crash_reporter_forwarding != TriState::kUnset) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*options = local_options;
|
||||
*options = options_;
|
||||
}
|
||||
|
||||
pid_t ProcessSnapshotWin::ProcessID() const {
|
||||
@ -238,13 +215,16 @@ std::vector<const MemorySnapshot*> ProcessSnapshotWin::ExtraMemory() const {
|
||||
return extra_memory;
|
||||
}
|
||||
|
||||
void ProcessSnapshotWin::InitializeThreads() {
|
||||
void ProcessSnapshotWin::InitializeThreads(
|
||||
bool gather_indirectly_referenced_memory) {
|
||||
const std::vector<ProcessReaderWin::Thread>& process_reader_threads =
|
||||
process_reader_.Threads();
|
||||
for (const ProcessReaderWin::Thread& process_reader_thread :
|
||||
process_reader_threads) {
|
||||
auto thread = make_scoped_ptr(new internal::ThreadSnapshotWin());
|
||||
if (thread->Initialize(&process_reader_, process_reader_thread)) {
|
||||
if (thread->Initialize(&process_reader_,
|
||||
process_reader_thread,
|
||||
gather_indirectly_referenced_memory)) {
|
||||
threads_.push_back(thread.release());
|
||||
}
|
||||
}
|
||||
@ -262,6 +242,38 @@ void ProcessSnapshotWin::InitializeModules() {
|
||||
}
|
||||
}
|
||||
|
||||
void ProcessSnapshotWin::GetCrashpadOptionsInternal(
|
||||
CrashpadInfoClientOptions* options) {
|
||||
CrashpadInfoClientOptions local_options;
|
||||
|
||||
for (internal::ModuleSnapshotWin* module : modules_) {
|
||||
CrashpadInfoClientOptions module_options;
|
||||
module->GetCrashpadOptions(&module_options);
|
||||
|
||||
if (local_options.crashpad_handler_behavior == TriState::kUnset) {
|
||||
local_options.crashpad_handler_behavior =
|
||||
module_options.crashpad_handler_behavior;
|
||||
}
|
||||
if (local_options.system_crash_reporter_forwarding == TriState::kUnset) {
|
||||
local_options.system_crash_reporter_forwarding =
|
||||
module_options.system_crash_reporter_forwarding;
|
||||
}
|
||||
if (local_options.gather_indirectly_referenced_memory == TriState::kUnset) {
|
||||
local_options.gather_indirectly_referenced_memory =
|
||||
module_options.gather_indirectly_referenced_memory;
|
||||
}
|
||||
|
||||
// If non-default values have been found for all options, the loop can end
|
||||
// early.
|
||||
if (local_options.crashpad_handler_behavior != TriState::kUnset &&
|
||||
local_options.system_crash_reporter_forwarding != TriState::kUnset) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
*options = local_options;
|
||||
}
|
||||
|
||||
template <class Traits>
|
||||
void ProcessSnapshotWin::InitializePebData(
|
||||
WinVMAddress debug_critical_section_address) {
|
||||
|
@ -141,11 +141,14 @@ class ProcessSnapshotWin final : public ProcessSnapshot {
|
||||
|
||||
private:
|
||||
// Initializes threads_ on behalf of Initialize().
|
||||
void InitializeThreads();
|
||||
void InitializeThreads(bool gather_indirectly_referenced_memory);
|
||||
|
||||
// Initializes modules_ on behalf of Initialize().
|
||||
void InitializeModules();
|
||||
|
||||
// Initializes options_ on behalf of Initialize().
|
||||
void GetCrashpadOptionsInternal(CrashpadInfoClientOptions* options);
|
||||
|
||||
// Initializes various memory blocks reachable from the PEB on behalf of
|
||||
// Initialize().
|
||||
template <class Traits>
|
||||
@ -186,6 +189,7 @@ class ProcessSnapshotWin final : public ProcessSnapshot {
|
||||
UUID client_id_;
|
||||
std::map<std::string, std::string> annotations_simple_map_;
|
||||
timeval snapshot_time_;
|
||||
CrashpadInfoClientOptions options_;
|
||||
InitializationStateDcheck initialized_;
|
||||
|
||||
DISALLOW_COPY_AND_ASSIGN(ProcessSnapshotWin);
|
||||
|
@ -17,8 +17,9 @@
|
||||
#include <vector>
|
||||
|
||||
#include "base/logging.h"
|
||||
#include "snapshot/win/capture_context_memory.h"
|
||||
#include "snapshot/capture_memory.h"
|
||||
#include "snapshot/win/cpu_context_win.h"
|
||||
#include "snapshot/win/capture_memory_delegate_win.h"
|
||||
#include "snapshot/win/process_reader_win.h"
|
||||
|
||||
namespace crashpad {
|
||||
@ -38,7 +39,8 @@ ThreadSnapshotWin::~ThreadSnapshotWin() {
|
||||
|
||||
bool ThreadSnapshotWin::Initialize(
|
||||
ProcessReaderWin* process_reader,
|
||||
const ProcessReaderWin::Thread& process_reader_thread) {
|
||||
const ProcessReaderWin::Thread& process_reader_thread,
|
||||
bool gather_indirectly_referenced_memory) {
|
||||
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
|
||||
|
||||
thread_ = process_reader_thread;
|
||||
@ -76,8 +78,11 @@ bool ThreadSnapshotWin::Initialize(
|
||||
InitializeX86Context(process_reader_thread.context.native, context_.x86);
|
||||
#endif // ARCH_CPU_X86_64
|
||||
|
||||
CaptureMemoryPointedToByContext(
|
||||
context_, process_reader, thread_, &pointed_to_memory_);
|
||||
CaptureMemoryDelegateWin capture_memory_delegate(
|
||||
process_reader, thread_, &pointed_to_memory_);
|
||||
CaptureMemory::PointedToByContext(context_, &capture_memory_delegate);
|
||||
if (gather_indirectly_referenced_memory)
|
||||
CaptureMemory::PointedToByMemoryRange(stack_, &capture_memory_delegate);
|
||||
|
||||
INITIALIZATION_STATE_SET_VALID(initialized_);
|
||||
return true;
|
||||
|
@ -48,11 +48,14 @@ class ThreadSnapshotWin final : public ThreadSnapshot {
|
||||
//! the thread.
|
||||
//! \param[in] process_reader_thread The thread within the ProcessReaderWin
|
||||
//! for which the snapshot should be created.
|
||||
//! \param[in] gather_indirectly_referenced_memory If `true`, adds extra
|
||||
//! memory regions to the snapshot pointed to by the thread's stack.
|
||||
//!
|
||||
//! \return `true` if the snapshot could be created, `false` otherwise with
|
||||
//! an appropriate message logged.
|
||||
bool Initialize(ProcessReaderWin* process_reader,
|
||||
const ProcessReaderWin::Thread& process_reader_thread);
|
||||
const ProcessReaderWin::Thread& process_reader_thread,
|
||||
bool gather_indirectly_referenced_memory);
|
||||
|
||||
// ThreadSnapshot:
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user