win: Cap indirect memory gathering

Add a user-configurable cap on the amount of memory that is gathered by
dereferencing thread stacks. (SyzyAsan stores a tremendously large
number of pointers on the stack, so the dumps were ending up in the ~25M
range.)

Also reduce the range around pointers somewhat.

Change-Id: I6bce57d86bd2f6a796e1580c530909e089ec00ed
Reviewed-on: https://chromium-review.googlesource.com/338463
Reviewed-by: Mark Mentovai <mark@chromium.org>
This commit is contained in:
Scott Graham 2016-04-21 22:19:31 -07:00
parent 96dba6713a
commit dbfcb5d032
17 changed files with 96 additions and 27 deletions

View File

@ -96,10 +96,12 @@ CrashpadInfo::CrashpadInfo()
: signature_(kSignature), : signature_(kSignature),
size_(sizeof(*this)), size_(sizeof(*this)),
version_(kCrashpadInfoVersion), version_(kCrashpadInfoVersion),
indirectly_referenced_memory_cap_(0),
padding_0_(0),
crashpad_handler_behavior_(TriState::kUnset), crashpad_handler_behavior_(TriState::kUnset),
system_crash_reporter_forwarding_(TriState::kUnset), system_crash_reporter_forwarding_(TriState::kUnset),
gather_indirectly_referenced_memory_(TriState::kUnset), gather_indirectly_referenced_memory_(TriState::kUnset),
padding_0_(0), padding_1_(0),
extra_memory_ranges_(nullptr), extra_memory_ranges_(nullptr),
simple_annotations_(nullptr), simple_annotations_(nullptr),
user_data_minidump_stream_head_(nullptr) user_data_minidump_stream_head_(nullptr)

View File

@ -148,9 +148,17 @@ struct CrashpadInfo {
//! This causes Crashpad to include pages of data referenced by locals or //! This causes Crashpad to include pages of data referenced by locals or
//! other stack memory. Turning this on can increase the size of the minidump //! other stack memory. Turning this on can increase the size of the minidump
//! significantly. //! significantly.
//!
//! \param[in] gather_indirectly_referenced_memory Whether extra memory should
//! be gathered.
//! \param[in] limit The amount of memory in bytes after which no more
//! indirectly gathered memory should be captured. This value is only used
//! when \a gather_indirectly_referenced_memory is TriState::kEnabled.
void set_gather_indirectly_referenced_memory( void set_gather_indirectly_referenced_memory(
TriState gather_indirectly_referenced_memory) { TriState gather_indirectly_referenced_memory,
uint32_t limit) {
gather_indirectly_referenced_memory_ = gather_indirectly_referenced_memory; gather_indirectly_referenced_memory_ = gather_indirectly_referenced_memory;
indirectly_referenced_memory_cap_ = limit;
} }
//! \brief Adds a custom stream to the minidump. //! \brief Adds a custom stream to the minidump.
@ -192,10 +200,12 @@ struct CrashpadInfo {
uint32_t signature_; // kSignature uint32_t signature_; // kSignature
uint32_t size_; // The size of the entire CrashpadInfo structure. uint32_t size_; // The size of the entire CrashpadInfo structure.
uint32_t version_; // kVersion uint32_t version_; // kVersion
uint32_t indirectly_referenced_memory_cap_;
uint32_t padding_0_;
TriState crashpad_handler_behavior_; TriState crashpad_handler_behavior_;
TriState system_crash_reporter_forwarding_; TriState system_crash_reporter_forwarding_;
TriState gather_indirectly_referenced_memory_; TriState gather_indirectly_referenced_memory_;
uint8_t padding_0_; uint8_t padding_1_;
SimpleAddressRangeBag* extra_memory_ranges_; // weak SimpleAddressRangeBag* extra_memory_ranges_; // weak
SimpleStringDictionary* simple_annotations_; // weak SimpleStringDictionary* simple_annotations_; // weak
internal::UserDataMinidumpStreamListEntry* user_data_minidump_stream_head_; internal::UserDataMinidumpStreamListEntry* user_data_minidump_stream_head_;

View File

@ -223,7 +223,8 @@ int CrashyMain(int argc, wchar_t* argv[]) {
printf("%p, %p\n", offset_pointer, &offset_pointer); printf("%p, %p\n", offset_pointer, &offset_pointer);
crashpad::CrashpadInfo::GetCrashpadInfo() crashpad::CrashpadInfo::GetCrashpadInfo()
->set_gather_indirectly_referenced_memory(TriState::kEnabled); ->set_gather_indirectly_referenced_memory(
TriState::kEnabled, std::numeric_limits<uint32_t>::max());
std::vector<uint8_t> data_stream1(128, 'x'); std::vector<uint8_t> data_stream1(128, 'x');
crashpad::CrashpadInfo::GetCrashpadInfo()->AddUserDataMinidumpStream( crashpad::CrashpadInfo::GetCrashpadInfo()->AddUserDataMinidumpStream(

View File

@ -38,9 +38,9 @@ void MaybeCaptureMemoryAround(CaptureMemory::Delegate* delegate,
if (address > max_address - non_address_offset) if (address > max_address - non_address_offset)
return; return;
const uint64_t kRegisterByteOffset = 256; const uint64_t kRegisterByteOffset = 128;
const uint64_t target = address - kRegisterByteOffset; const uint64_t target = address - kRegisterByteOffset;
const uint64_t size = 1024; const uint64_t size = 512;
static_assert(kRegisterByteOffset <= size / 2, static_assert(kRegisterByteOffset <= size / 2,
"negative offset too large"); "negative offset too large");
auto ranges = auto ranges =

View File

@ -62,6 +62,9 @@ struct CrashpadInfoClientOptions {
//! \sa CrashpadInfo::set_gather_indirectly_referenced_memory() //! \sa CrashpadInfo::set_gather_indirectly_referenced_memory()
TriState gather_indirectly_referenced_memory; TriState gather_indirectly_referenced_memory;
//! \sa CrashpadInfo::set_gather_indirectly_referenced_memory()
uint32_t indirectly_referenced_memory_cap;
}; };
} // namespace crashpad } // namespace crashpad

View File

@ -61,7 +61,8 @@ class ScopedUnsetCrashpadInfoOptions {
~ScopedUnsetCrashpadInfoOptions() { ~ScopedUnsetCrashpadInfoOptions() {
crashpad_info_->set_crashpad_handler_behavior(TriState::kUnset); crashpad_info_->set_crashpad_handler_behavior(TriState::kUnset);
crashpad_info_->set_system_crash_reporter_forwarding(TriState::kUnset); crashpad_info_->set_system_crash_reporter_forwarding(TriState::kUnset);
crashpad_info_->set_gather_indirectly_referenced_memory(TriState::kUnset); crashpad_info_->set_gather_indirectly_referenced_memory(TriState::kUnset,
0);
} }
private: private:
@ -94,6 +95,7 @@ TEST(CrashpadInfoClientOptions, OneModule) {
EXPECT_EQ(TriState::kUnset, options.crashpad_handler_behavior); EXPECT_EQ(TriState::kUnset, options.crashpad_handler_behavior);
EXPECT_EQ(TriState::kUnset, options.system_crash_reporter_forwarding); EXPECT_EQ(TriState::kUnset, options.system_crash_reporter_forwarding);
EXPECT_EQ(TriState::kUnset, options.gather_indirectly_referenced_memory); EXPECT_EQ(TriState::kUnset, options.gather_indirectly_referenced_memory);
EXPECT_EQ(0u, options.indirectly_referenced_memory_cap);
CrashpadInfo* crashpad_info = CrashpadInfo::GetCrashpadInfo(); CrashpadInfo* crashpad_info = CrashpadInfo::GetCrashpadInfo();
ASSERT_TRUE(crashpad_info); ASSERT_TRUE(crashpad_info);
@ -107,6 +109,7 @@ TEST(CrashpadInfoClientOptions, OneModule) {
EXPECT_EQ(TriState::kEnabled, options.crashpad_handler_behavior); EXPECT_EQ(TriState::kEnabled, options.crashpad_handler_behavior);
EXPECT_EQ(TriState::kUnset, options.system_crash_reporter_forwarding); EXPECT_EQ(TriState::kUnset, options.system_crash_reporter_forwarding);
EXPECT_EQ(TriState::kUnset, options.gather_indirectly_referenced_memory); EXPECT_EQ(TriState::kUnset, options.gather_indirectly_referenced_memory);
EXPECT_EQ(0u, options.indirectly_referenced_memory_cap);
} }
{ {
@ -118,17 +121,20 @@ TEST(CrashpadInfoClientOptions, OneModule) {
EXPECT_EQ(TriState::kUnset, options.crashpad_handler_behavior); EXPECT_EQ(TriState::kUnset, options.crashpad_handler_behavior);
EXPECT_EQ(TriState::kDisabled, options.system_crash_reporter_forwarding); EXPECT_EQ(TriState::kDisabled, options.system_crash_reporter_forwarding);
EXPECT_EQ(TriState::kUnset, options.gather_indirectly_referenced_memory); EXPECT_EQ(TriState::kUnset, options.gather_indirectly_referenced_memory);
EXPECT_EQ(0u, options.indirectly_referenced_memory_cap);
} }
{ {
ScopedUnsetCrashpadInfoOptions unset(crashpad_info); ScopedUnsetCrashpadInfoOptions unset(crashpad_info);
crashpad_info->set_gather_indirectly_referenced_memory(TriState::kEnabled); crashpad_info->set_gather_indirectly_referenced_memory(TriState::kEnabled,
1234);
options = SelfProcessSnapshotAndGetCrashpadOptions(); options = SelfProcessSnapshotAndGetCrashpadOptions();
EXPECT_EQ(TriState::kUnset, options.crashpad_handler_behavior); EXPECT_EQ(TriState::kUnset, options.crashpad_handler_behavior);
EXPECT_EQ(TriState::kUnset, options.system_crash_reporter_forwarding); EXPECT_EQ(TriState::kUnset, options.system_crash_reporter_forwarding);
EXPECT_EQ(TriState::kEnabled, options.gather_indirectly_referenced_memory); EXPECT_EQ(TriState::kEnabled, options.gather_indirectly_referenced_memory);
EXPECT_EQ(1234u, options.indirectly_referenced_memory_cap);
} }
} }

View File

@ -107,6 +107,8 @@ void ProcessSnapshotMac::GetCrashpadOptions(
if (local_options.gather_indirectly_referenced_memory == TriState::kUnset) { if (local_options.gather_indirectly_referenced_memory == TriState::kUnset) {
local_options.gather_indirectly_referenced_memory = local_options.gather_indirectly_referenced_memory =
module_options.gather_indirectly_referenced_memory; module_options.gather_indirectly_referenced_memory;
local_options.indirectly_referenced_memory_cap =
module_options.indirectly_referenced_memory_cap;
} }
// If non-default values have been found for all options, the loop can end // If non-default values have been found for all options, the loop can end

View File

@ -27,6 +27,8 @@ PROCESS_TYPE_STRUCT_BEGIN(CrashpadInfo)
PROCESS_TYPE_STRUCT_MEMBER(uint32_t, signature) PROCESS_TYPE_STRUCT_MEMBER(uint32_t, signature)
PROCESS_TYPE_STRUCT_MEMBER(uint32_t, size) PROCESS_TYPE_STRUCT_MEMBER(uint32_t, size)
PROCESS_TYPE_STRUCT_MEMBER(uint32_t, version) PROCESS_TYPE_STRUCT_MEMBER(uint32_t, version)
PROCESS_TYPE_STRUCT_MEMBER(uint32_t, indirectly_referenced_memory_cap)
PROCESS_TYPE_STRUCT_MEMBER(uint32_t, padding_0)
PROCESS_TYPE_STRUCT_MEMBER(uint8_t, crashpad_handler_behavior) // TriState PROCESS_TYPE_STRUCT_MEMBER(uint8_t, crashpad_handler_behavior) // TriState
// TriState // TriState
@ -35,7 +37,7 @@ PROCESS_TYPE_STRUCT_BEGIN(CrashpadInfo)
// TriState // TriState
PROCESS_TYPE_STRUCT_MEMBER(uint8_t, gather_indirectly_referenced_memory) PROCESS_TYPE_STRUCT_MEMBER(uint8_t, gather_indirectly_referenced_memory)
PROCESS_TYPE_STRUCT_MEMBER(uint8_t, padding_0) PROCESS_TYPE_STRUCT_MEMBER(uint8_t, padding_1)
// SimpleAddressRangeBag* // SimpleAddressRangeBag*
PROCESS_TYPE_STRUCT_MEMBER(Pointer, extra_memory_ranges) PROCESS_TYPE_STRUCT_MEMBER(Pointer, extra_memory_ranges)

View File

@ -14,6 +14,7 @@
#include "snapshot/win/capture_memory_delegate_win.h" #include "snapshot/win/capture_memory_delegate_win.h"
#include "base/numerics/safe_conversions.h"
#include "snapshot/win/memory_snapshot_win.h" #include "snapshot/win/memory_snapshot_win.h"
namespace crashpad { namespace crashpad {
@ -22,10 +23,12 @@ namespace internal {
CaptureMemoryDelegateWin::CaptureMemoryDelegateWin( CaptureMemoryDelegateWin::CaptureMemoryDelegateWin(
ProcessReaderWin* process_reader, ProcessReaderWin* process_reader,
const ProcessReaderWin::Thread& thread, const ProcessReaderWin::Thread& thread,
PointerVector<MemorySnapshotWin>* snapshots) PointerVector<MemorySnapshotWin>* snapshots,
uint32_t* budget_remaining)
: stack_(thread.stack_region_address, thread.stack_region_size), : stack_(thread.stack_region_address, thread.stack_region_size),
process_reader_(process_reader), process_reader_(process_reader),
snapshots_(snapshots) {} snapshots_(snapshots),
budget_remaining_(budget_remaining) {}
bool CaptureMemoryDelegateWin::Is64Bit() const { bool CaptureMemoryDelegateWin::Is64Bit() const {
return process_reader_->Is64Bit(); return process_reader_->Is64Bit();
@ -49,9 +52,20 @@ void CaptureMemoryDelegateWin::AddNewMemorySnapshot(
return; return;
if (range.size() == 0) if (range.size() == 0)
return; return;
if (budget_remaining_ && *budget_remaining_ == 0)
return;
internal::MemorySnapshotWin* snapshot = new internal::MemorySnapshotWin(); internal::MemorySnapshotWin* snapshot = new internal::MemorySnapshotWin();
snapshot->Initialize(process_reader_, range.base(), range.size()); snapshot->Initialize(process_reader_, range.base(), range.size());
snapshots_->push_back(snapshot); snapshots_->push_back(snapshot);
if (budget_remaining_) {
if (!base::IsValueInRangeForNumericType<int64_t>(range.size())) {
*budget_remaining_ = 0;
} else {
int64_t temp = *budget_remaining_;
temp -= range.size();
*budget_remaining_ = base::saturated_cast<uint32_t>(temp);
}
}
} }
} // namespace internal } // namespace internal

View File

@ -35,9 +35,13 @@ class CaptureMemoryDelegateWin : public CaptureMemory::Delegate {
//! already captured elsewhere. //! already captured elsewhere.
//! \param[in] snapshots A vector of MemorySnapshotWin to which the captured //! \param[in] snapshots A vector of MemorySnapshotWin to which the captured
//! memory will be added. //! memory will be added.
//! \param[in] budget_remaining If non-null, a pointer to the remaining number
//! of bytes to capture. If this is `0`, no further memory will be
//! captured.
CaptureMemoryDelegateWin(ProcessReaderWin* process_reader, CaptureMemoryDelegateWin(ProcessReaderWin* process_reader,
const ProcessReaderWin::Thread& thread, const ProcessReaderWin::Thread& thread,
PointerVector<MemorySnapshotWin>* snapshots); PointerVector<MemorySnapshotWin>* snapshots,
uint32_t* budget_remaining);
// MemoryCaptureDelegate: // MemoryCaptureDelegate:
bool Is64Bit() const override; bool Is64Bit() const override;
@ -50,6 +54,7 @@ class CaptureMemoryDelegateWin : public CaptureMemory::Delegate {
CheckedRange<uint64_t, uint64_t> stack_; CheckedRange<uint64_t, uint64_t> stack_;
ProcessReaderWin* process_reader_; ProcessReaderWin* process_reader_;
PointerVector<MemorySnapshotWin>* snapshots_; PointerVector<MemorySnapshotWin>* snapshots_;
uint32_t* budget_remaining_;
}; };
} // namespace internal } // namespace internal

View File

@ -91,7 +91,7 @@ bool ExceptionSnapshotWin::Initialize(ProcessReaderWin* process_reader,
} }
CaptureMemoryDelegateWin capture_memory_delegate( CaptureMemoryDelegateWin capture_memory_delegate(
process_reader, *thread, &extra_memory_); process_reader, *thread, &extra_memory_, nullptr);
CaptureMemory::PointedToByContext(context_, &capture_memory_delegate); CaptureMemory::PointedToByContext(context_, &capture_memory_delegate);
INITIALIZATION_STATE_SET_VALID(initialized_); INITIALIZATION_STATE_SET_VALID(initialized_);

View File

@ -223,6 +223,8 @@ void ModuleSnapshotWin::GetCrashpadOptionsInternal(
if (!pe_image_reader_->GetCrashpadInfo(&crashpad_info)) { if (!pe_image_reader_->GetCrashpadInfo(&crashpad_info)) {
options->crashpad_handler_behavior = TriState::kUnset; options->crashpad_handler_behavior = TriState::kUnset;
options->system_crash_reporter_forwarding = TriState::kUnset; options->system_crash_reporter_forwarding = TriState::kUnset;
options->gather_indirectly_referenced_memory = TriState::kUnset;
options->indirectly_referenced_memory_cap = 0;
return; return;
} }
@ -237,6 +239,9 @@ void ModuleSnapshotWin::GetCrashpadOptionsInternal(
options->gather_indirectly_referenced_memory = options->gather_indirectly_referenced_memory =
CrashpadInfoClientOptions::TriStateFromCrashpadInfo( CrashpadInfoClientOptions::TriStateFromCrashpadInfo(
crashpad_info.gather_indirectly_referenced_memory); crashpad_info.gather_indirectly_referenced_memory);
options->indirectly_referenced_memory_cap =
crashpad_info.indirectly_referenced_memory_cap;
} }
const VS_FIXEDFILEINFO* ModuleSnapshotWin::VSFixedFileInfo() const { const VS_FIXEDFILEINFO* ModuleSnapshotWin::VSFixedFileInfo() const {

View File

@ -39,10 +39,12 @@ struct CrashpadInfo {
uint32_t signature; uint32_t signature;
uint32_t size; uint32_t size;
uint32_t version; uint32_t version;
uint32_t indirectly_referenced_memory_cap;
uint32_t padding_0;
uint8_t crashpad_handler_behavior; // TriState. uint8_t crashpad_handler_behavior; // TriState.
uint8_t system_crash_reporter_forwarding; // TriState. uint8_t system_crash_reporter_forwarding; // TriState.
uint8_t gather_indirectly_referenced_memory; // TriState. uint8_t gather_indirectly_referenced_memory; // TriState.
uint8_t padding_0; uint8_t padding_1;
typename Traits::Pointer extra_address_ranges; typename Traits::Pointer extra_address_ranges;
typename Traits::Pointer simple_annotations; typename Traits::Pointer simple_annotations;
typename Traits::Pointer user_data_minidump_stream_head; typename Traits::Pointer user_data_minidump_stream_head;

View File

@ -72,8 +72,9 @@ bool ProcessSnapshotWin::Initialize(
GetCrashpadOptionsInternal(&options_); GetCrashpadOptionsInternal(&options_);
InitializeThreads(options_.gather_indirectly_referenced_memory == InitializeThreads(
TriState::kEnabled); options_.gather_indirectly_referenced_memory == TriState::kEnabled,
options_.indirectly_referenced_memory_cap);
for (const MEMORY_BASIC_INFORMATION64& mbi : for (const MEMORY_BASIC_INFORMATION64& mbi :
process_reader_.GetProcessInfo().MemoryInfo()) { process_reader_.GetProcessInfo().MemoryInfo()) {
@ -230,15 +231,20 @@ std::vector<const MemorySnapshot*> ProcessSnapshotWin::ExtraMemory() const {
} }
void ProcessSnapshotWin::InitializeThreads( void ProcessSnapshotWin::InitializeThreads(
bool gather_indirectly_referenced_memory) { bool gather_indirectly_referenced_memory,
uint32_t indirectly_referenced_memory_cap) {
const std::vector<ProcessReaderWin::Thread>& process_reader_threads = const std::vector<ProcessReaderWin::Thread>& process_reader_threads =
process_reader_.Threads(); process_reader_.Threads();
for (const ProcessReaderWin::Thread& process_reader_thread : for (const ProcessReaderWin::Thread& process_reader_thread :
process_reader_threads) { process_reader_threads) {
auto thread = make_scoped_ptr(new internal::ThreadSnapshotWin()); auto thread = make_scoped_ptr(new internal::ThreadSnapshotWin());
uint32_t* budget_remaining_pointer = nullptr;
uint32_t budget_remaining = indirectly_referenced_memory_cap;
if (gather_indirectly_referenced_memory)
budget_remaining_pointer = &budget_remaining;
if (thread->Initialize(&process_reader_, if (thread->Initialize(&process_reader_,
process_reader_thread, process_reader_thread,
gather_indirectly_referenced_memory)) { budget_remaining_pointer)) {
threads_.push_back(thread.release()); threads_.push_back(thread.release());
} }
} }
@ -322,6 +328,8 @@ void ProcessSnapshotWin::GetCrashpadOptionsInternal(
if (local_options.gather_indirectly_referenced_memory == TriState::kUnset) { if (local_options.gather_indirectly_referenced_memory == TriState::kUnset) {
local_options.gather_indirectly_referenced_memory = local_options.gather_indirectly_referenced_memory =
module_options.gather_indirectly_referenced_memory; module_options.gather_indirectly_referenced_memory;
local_options.indirectly_referenced_memory_cap =
module_options.indirectly_referenced_memory_cap;
} }
// If non-default values have been found for all options, the loop can end // If non-default values have been found for all options, the loop can end

View File

@ -16,6 +16,7 @@
#define CRASHPAD_SNAPSHOT_WIN_PROCESS_SNAPSHOT_WIN_H_ #define CRASHPAD_SNAPSHOT_WIN_PROCESS_SNAPSHOT_WIN_H_
#include <windows.h> #include <windows.h>
#include <stdint.h>
#include <sys/time.h> #include <sys/time.h>
#include <sys/types.h> #include <sys/types.h>
@ -143,7 +144,8 @@ class ProcessSnapshotWin final : public ProcessSnapshot {
private: private:
// Initializes threads_ on behalf of Initialize(). // Initializes threads_ on behalf of Initialize().
void InitializeThreads(bool gather_indirectly_referenced_memory); void InitializeThreads(bool gather_indirectly_referenced_memory,
uint32_t indirectly_referenced_memory_cap);
// Initializes modules_ on behalf of Initialize(). // Initializes modules_ on behalf of Initialize().
void InitializeModules(); void InitializeModules();

View File

@ -40,7 +40,7 @@ ThreadSnapshotWin::~ThreadSnapshotWin() {
bool ThreadSnapshotWin::Initialize( bool ThreadSnapshotWin::Initialize(
ProcessReaderWin* process_reader, ProcessReaderWin* process_reader,
const ProcessReaderWin::Thread& process_reader_thread, const ProcessReaderWin::Thread& process_reader_thread,
bool gather_indirectly_referenced_memory) { uint32_t* gather_indirectly_referenced_memory_bytes_remaining) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_); INITIALIZATION_STATE_SET_INITIALIZING(initialized_);
thread_ = process_reader_thread; thread_ = process_reader_thread;
@ -79,10 +79,14 @@ bool ThreadSnapshotWin::Initialize(
#endif // ARCH_CPU_X86_64 #endif // ARCH_CPU_X86_64
CaptureMemoryDelegateWin capture_memory_delegate( CaptureMemoryDelegateWin capture_memory_delegate(
process_reader, thread_, &pointed_to_memory_); process_reader,
thread_,
&pointed_to_memory_,
gather_indirectly_referenced_memory_bytes_remaining);
CaptureMemory::PointedToByContext(context_, &capture_memory_delegate); CaptureMemory::PointedToByContext(context_, &capture_memory_delegate);
if (gather_indirectly_referenced_memory) if (gather_indirectly_referenced_memory_bytes_remaining) {
CaptureMemory::PointedToByMemoryRange(stack_, &capture_memory_delegate); CaptureMemory::PointedToByMemoryRange(stack_, &capture_memory_delegate);
}
INITIALIZATION_STATE_SET_VALID(initialized_); INITIALIZATION_STATE_SET_VALID(initialized_);
return true; return true;

View File

@ -48,14 +48,17 @@ class ThreadSnapshotWin final : public ThreadSnapshot {
//! the thread. //! the thread.
//! \param[in] process_reader_thread The thread within the ProcessReaderWin //! \param[in] process_reader_thread The thread within the ProcessReaderWin
//! for which the snapshot should be created. //! for which the snapshot should be created.
//! \param[in] gather_indirectly_referenced_memory If `true`, adds extra //! \param[in] gather_indirectly_referenced_memory_bytes_remaining. If
//! memory regions to the snapshot pointed to by the thread's stack. //! non-null, add extra memory regions to the snapshot pointed to by the
//! thread's stack. The size of the regions added is subtracted from the
//! count, and when it's `0`, no more regions will be added.
//! //!
//! \return `true` if the snapshot could be created, `false` otherwise with //! \return `true` if the snapshot could be created, `false` otherwise with
//! an appropriate message logged. //! an appropriate message logged.
bool Initialize(ProcessReaderWin* process_reader, bool Initialize(
const ProcessReaderWin::Thread& process_reader_thread, ProcessReaderWin* process_reader,
bool gather_indirectly_referenced_memory); const ProcessReaderWin::Thread& process_reader_thread,
uint32_t* gather_indirectly_referenced_memory_bytes_remaining);
// ThreadSnapshot: // ThreadSnapshot: