Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion client/crashpad_info.cc
Original file line number Diff line number Diff line change
Expand Up @@ -133,7 +133,7 @@ CrashpadInfo::CrashpadInfo()
crashpad_handler_behavior_(TriState::kUnset),
system_crash_reporter_forwarding_(TriState::kUnset),
gather_indirectly_referenced_memory_(TriState::kUnset),
padding_1_(0),
limit_stack_capture_to_sp_(TriState::kUnset),
extra_memory_ranges_(nullptr),
simple_annotations_(nullptr),
user_data_minidump_stream_head_(nullptr),
Expand Down
21 changes: 20 additions & 1 deletion client/crashpad_info.h
Original file line number Diff line number Diff line change
Expand Up @@ -244,6 +244,25 @@ struct CrashpadInfo {
indirectly_referenced_memory_cap_ = limit;
}

//! \brief Limits stack capture to stack pointer.
//!
//! When handling an exception, the Crashpad handler will scan all modules in
//! a process. The first one that has a CrashpadInfo structure populated with
//! a value other than TriState::kUnset for this field will dictate whether
//! stack capture is limited.
//!
//! This causes Crashpad to use the current stack pointer as the upper bound
//! of the stack capture range, once validated to be within TEB
//! StackLimit/StackBase values. This reduces the capture range compared to
//! using the full TEB-derived stack region. This is useful when running under
//! Wine/Proton where TEB values may be incorrect.
//!
//! \param[in] limit_stack_capture_to_sp Whether to limit stack capture to
//! the stack pointer.
void set_limit_stack_capture_to_sp(TriState limit_stack_capture_to_sp) {
limit_stack_capture_to_sp_ = limit_stack_capture_to_sp;
}

//! \brief Adds a custom stream to the minidump.
//!
//! The memory block referenced by \a data and \a size will added to the
Expand Down Expand Up @@ -329,7 +348,7 @@ struct CrashpadInfo {
TriState crashpad_handler_behavior_;
TriState system_crash_reporter_forwarding_;
TriState gather_indirectly_referenced_memory_;
uint8_t padding_1_;
TriState limit_stack_capture_to_sp_;
SimpleAddressRangeBag* extra_memory_ranges_; // weak
SimpleStringDictionary* simple_annotations_; // weak
internal::UserDataMinidumpStreamListEntry* user_data_minidump_stream_head_;
Expand Down
3 changes: 2 additions & 1 deletion snapshot/crashpad_info_client_options.cc
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,8 @@ CrashpadInfoClientOptions::CrashpadInfoClientOptions()
: crashpad_handler_behavior(TriState::kUnset),
system_crash_reporter_forwarding(TriState::kUnset),
gather_indirectly_referenced_memory(TriState::kUnset),
indirectly_referenced_memory_cap(0) {
indirectly_referenced_memory_cap(0),
limit_stack_capture_to_sp(TriState::kUnset) {
}

} // namespace crashpad
3 changes: 3 additions & 0 deletions snapshot/crashpad_info_client_options.h
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,9 @@ struct CrashpadInfoClientOptions {

//! \sa CrashpadInfo::set_gather_indirectly_referenced_memory()
uint32_t indirectly_referenced_memory_cap;

//! \sa CrashpadInfo::set_limit_stack_capture_to_sp()
TriState limit_stack_capture_to_sp;
};

} // namespace crashpad
Expand Down
5 changes: 4 additions & 1 deletion snapshot/crashpad_types/crashpad_info_reader.cc
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ class CrashpadInfoReader::InfoContainerSpecific : public InfoContainer {
UnsetIfNotValidTriState(&info.crashpad_handler_behavior);
UnsetIfNotValidTriState(&info.system_crash_reporter_forwarding);
UnsetIfNotValidTriState(&info.gather_indirectly_referenced_memory);
UnsetIfNotValidTriState(&info.limit_stack_capture_to_sp);

return true;
}
Expand All @@ -109,7 +110,7 @@ class CrashpadInfoReader::InfoContainerSpecific : public InfoContainer {
TriState crashpad_handler_behavior;
TriState system_crash_reporter_forwarding;
TriState gather_indirectly_referenced_memory;
uint8_t padding_1;
TriState limit_stack_capture_to_sp;
typename Traits::Address extra_memory_ranges;
typename Traits::Address simple_annotations;
typename Traits::Address user_data_minidump_stream_head;
Expand Down Expand Up @@ -181,6 +182,8 @@ DEFINE_GETTER(uint32_t,
IndirectlyReferencedMemoryCap,
indirectly_referenced_memory_cap)

DEFINE_GETTER(TriState, LimitStackCaptureToSp, limit_stack_capture_to_sp)

DEFINE_GETTER(VMAddress, ExtraMemoryRanges, extra_memory_ranges)

DEFINE_GETTER(VMAddress, SimpleAnnotations, simple_annotations)
Expand Down
1 change: 1 addition & 0 deletions snapshot/crashpad_types/crashpad_info_reader.h
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ class CrashpadInfoReader {
TriState SystemCrashReporterForwarding();
TriState GatherIndirectlyReferencedMemory();
uint32_t IndirectlyReferencedMemoryCap();
TriState LimitStackCaptureToSp();
VMAddress ExtraMemoryRanges();
VMAddress SimpleAnnotations();
VMAddress AnnotationsList();
Expand Down
3 changes: 3 additions & 0 deletions snapshot/win/module_snapshot_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -259,6 +259,7 @@ void ModuleSnapshotWin::GetCrashpadOptionsInternal(
options->system_crash_reporter_forwarding = TriState::kUnset;
options->gather_indirectly_referenced_memory = TriState::kUnset;
options->indirectly_referenced_memory_cap = 0;
options->limit_stack_capture_to_sp = TriState::kUnset;
return;
}

Expand All @@ -270,6 +271,8 @@ void ModuleSnapshotWin::GetCrashpadOptionsInternal(
crashpad_info_->GatherIndirectlyReferencedMemory();
options->indirectly_referenced_memory_cap =
crashpad_info_->IndirectlyReferencedMemoryCap();
options->limit_stack_capture_to_sp =
crashpad_info_->LimitStackCaptureToSp();
}

const VS_FIXEDFILEINFO* ModuleSnapshotWin::VSFixedFileInfo() const {
Expand Down
14 changes: 12 additions & 2 deletions snapshot/win/process_snapshot_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -245,12 +245,18 @@ const ProcessMemory* ProcessSnapshotWin::Memory() const {
void ProcessSnapshotWin::InitializeThreads(uint32_t* budget_remaining_pointer) {
const std::vector<ProcessReaderWin::Thread>& process_reader_threads =
process_reader_.Threads();

// Check if stack capture limit is enabled via CrashpadInfo
bool limit_stack_capture_to_sp =
options_.limit_stack_capture_to_sp == TriState::kEnabled;

for (const ProcessReaderWin::Thread& process_reader_thread :
process_reader_threads) {
auto thread = std::make_unique<internal::ThreadSnapshotWin>();
if (thread->Initialize(&process_reader_,
process_reader_thread,
budget_remaining_pointer)) {
budget_remaining_pointer,
limit_stack_capture_to_sp)) {
threads_.push_back(std::move(thread));
}
}
Expand Down Expand Up @@ -359,12 +365,16 @@ void ProcessSnapshotWin::GetCrashpadOptionsInternal(
local_options.indirectly_referenced_memory_cap =
module_options.indirectly_referenced_memory_cap;
}
if (local_options.limit_stack_capture_to_sp == TriState::kUnset) {
local_options.limit_stack_capture_to_sp = module_options.limit_stack_capture_to_sp;
}

// 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 &&
local_options.gather_indirectly_referenced_memory != TriState::kUnset) {
local_options.gather_indirectly_referenced_memory != TriState::kUnset &&
local_options.limit_stack_capture_to_sp != TriState::kUnset) {
break;
}
}
Expand Down
67 changes: 61 additions & 6 deletions snapshot/win/thread_snapshot_win.cc
Original file line number Diff line number Diff line change
Expand Up @@ -46,6 +46,51 @@ XSAVE_CET_U_FORMAT* LocateXStateCetU(CONTEXT* context) {
locate_xstate_feature(context, XSTATE_CET_U, &cet_u_size));
}
#endif // defined(ARCH_CPU_X86_64)

// Helper function to adjust stack capture range based on current stack pointer
bool AdjustStackCaptureRange(ProcessReaderWin* process_reader,
const ProcessReaderWin::Thread& thread,
WinVMAddress* stack_capture_address,
WinVMSize* stack_capture_size) {
WinVMAddress sp = 0;
WinVMAddress stack_base = thread.stack_region_address + thread.stack_region_size;

// Get the stack pointer from the context
#if defined(ARCH_CPU_X86)
sp = thread.context.context<CONTEXT>()->Esp;
#elif defined(ARCH_CPU_X86_64)
if (process_reader->Is64Bit()) {
sp = thread.context.context<CONTEXT>()->Rsp;
} else {
sp = thread.context.context<WOW64_CONTEXT>()->Esp;
}
#elif defined(ARCH_CPU_ARM64)
sp = thread.context.context<CONTEXT>()->Sp;
#endif

// Verify SP is within the valid stack region
if (sp >= thread.stack_region_address && sp < stack_base) {
// Account for potential red zone
// Windows x64 follows Microsoft x64 calling convention and has no red zone
// ARM64 has a 16-byte red zone
const WinVMSize red_zone_size =
#if defined(ARCH_CPU_ARM64)
16;
#else
0;
#endif

// Adjust stack capture to start from SP (minus red zone) to stack base
WinVMAddress adjusted_start = sp > red_zone_size ? sp - red_zone_size : sp;
if (adjusted_start >= thread.stack_region_address && adjusted_start < stack_base) {
*stack_capture_address = adjusted_start;
*stack_capture_size = stack_base - adjusted_start;
return true;
}
}
return false;
}

} // namespace

ThreadSnapshotWin::ThreadSnapshotWin()
Expand All @@ -61,16 +106,26 @@ ThreadSnapshotWin::~ThreadSnapshotWin() {}
bool ThreadSnapshotWin::Initialize(
ProcessReaderWin* process_reader,
const ProcessReaderWin::Thread& process_reader_thread,
uint32_t* gather_indirectly_referenced_memory_bytes_remaining) {
uint32_t* gather_indirectly_referenced_memory_bytes_remaining,
bool limit_stack_capture_to_sp) {
INITIALIZATION_STATE_SET_INITIALIZING(initialized_);

thread_ = process_reader_thread;

WinVMAddress stack_capture_address = thread_.stack_region_address;
WinVMSize stack_capture_size = thread_.stack_region_size;

// If limit_stack_capture_to_sp is enabled, calculate stack range based on current SP
if (limit_stack_capture_to_sp) {
AdjustStackCaptureRange(
process_reader, thread_, &stack_capture_address, &stack_capture_size);
}

if (process_reader->GetProcessInfo().LoggingRangeIsFullyReadable(
CheckedRange<WinVMAddress, WinVMSize>(thread_.stack_region_address,
thread_.stack_region_size))) {
stack_.Initialize(process_reader->Memory(),
thread_.stack_region_address,
thread_.stack_region_size);
CheckedRange<WinVMAddress, WinVMSize>(stack_capture_address,
stack_capture_size))) {
stack_.Initialize(
process_reader->Memory(), stack_capture_address, stack_capture_size);
} else {
stack_.Initialize(process_reader->Memory(), 0, 0);
}
Expand Down
5 changes: 4 additions & 1 deletion snapshot/win/thread_snapshot_win.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,13 +55,16 @@ class ThreadSnapshotWin final : public ThreadSnapshot {
//! 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.
//! \param[in] limit_stack_capture_to_sp If `true`, limit the stack capture
//! to the current stack pointer instead of using full TEB-derived range.
//!
//! \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,
uint32_t* gather_indirectly_referenced_memory_bytes_remaining);
uint32_t* gather_indirectly_referenced_memory_bytes_remaining,
bool limit_stack_capture_to_sp = false);

// ThreadSnapshot:

Expand Down