Skip to content

Commit

Permalink
Allows setting maximum number of threads to process.
Browse files Browse the repository at this point in the history
By default, there is no limit and all threads will be processed. If set to a positive integer (via set_max_thread_count), the minidump processor will stop once that limit is reached. The limit will be ignored if the crashing/requesting thread is above the specified limit.

The original thread count is stored in the ProcessState and can be
acessed via the original_thread_count() method.

Change-Id: I6f0f173e5ad163aa7b2be76780b4a86e4932fc17
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/5641257
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
  • Loading branch information
Ivan Penkov committed Jun 18, 2024
1 parent c8318f0 commit e0a3a76
Show file tree
Hide file tree
Showing 4 changed files with 43 additions and 11 deletions.
9 changes: 9 additions & 0 deletions src/google_breakpad/processor/minidump_processor.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,11 @@ class MinidumpProcessor {
enable_objdump_for_exploitability_ = enabled;
}

// Sets the maximum number of threads to process.
void set_max_thread_count(int max_thread_count) {
max_thread_count_ = max_thread_count;
}

private:
StackFrameSymbolizer* frame_symbolizer_;
// Indicate whether resolver_helper_ is owned by this instance.
Expand All @@ -157,6 +162,10 @@ class MinidumpProcessor {
// purposes of disassembly. This results in significantly more overhead than
// the enable_objdump_ flag.
bool enable_objdump_for_exploitability_;

// The maximum number of threads to process. This can be exceeded if the
// requesting thread comes after the limit. Setting this to -1 means no limit.
int max_thread_count_;
};

} // namespace google_breakpad
Expand Down
6 changes: 6 additions & 0 deletions src/google_breakpad/processor/process_state.h
Original file line number Diff line number Diff line change
Expand Up @@ -105,6 +105,7 @@ class ProcessState {
uint64_t crash_address() const { return crash_address_; }
string assertion() const { return assertion_; }
int requesting_thread() const { return requesting_thread_; }
int original_thread_count() const { return original_thread_count_; }
const ExceptionRecord* exception_record() const { return &exception_record_; }
const vector<CallStack*>* threads() const { return &threads_; }
const vector<MemoryRegion*>* thread_memory_regions() const {
Expand Down Expand Up @@ -168,6 +169,11 @@ class ProcessState {
// indicating that the dump thread is not available.
int requesting_thread_;

// Original thread count. The Processor has limit on how many threads to
// process, so not all threads are processed. This tells you how many threads
// were originally in the minudump.
int original_thread_count_;

// Exception record details: code, flags, address, parameters.
ExceptionRecord exception_record_;

Expand Down
38 changes: 27 additions & 11 deletions src/processor/minidump_processor.cc
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,8 @@
#include <assert.h>

#include <algorithm>
#include <cstdint>
#include <cstdio>
#include <limits>
#include <map>
#include <string>
Expand Down Expand Up @@ -64,7 +66,8 @@ MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier,
own_frame_symbolizer_(true),
enable_exploitability_(false),
enable_objdump_(false),
enable_objdump_for_exploitability_(false) {
enable_objdump_for_exploitability_(false),
max_thread_count_(-1) {
}

MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier,
Expand All @@ -74,7 +77,8 @@ MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier,
own_frame_symbolizer_(true),
enable_exploitability_(enable_exploitability),
enable_objdump_(false),
enable_objdump_for_exploitability_(false) {
enable_objdump_for_exploitability_(false),
max_thread_count_(-1) {
}

MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer* frame_symbolizer,
Expand All @@ -83,7 +87,8 @@ MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer* frame_symbolizer,
own_frame_symbolizer_(false),
enable_exploitability_(enable_exploitability),
enable_objdump_(false),
enable_objdump_for_exploitability_(false) {
enable_objdump_for_exploitability_(false),
max_thread_count_(-1) {
assert(frame_symbolizer_);
}

Expand Down Expand Up @@ -208,29 +213,32 @@ ProcessResult MinidumpProcessor::Process(
bool interrupted = false;
bool found_requesting_thread = false;
unsigned int thread_count = threads->thread_count();
process_state->original_thread_count_ = thread_count;

// Reset frame_symbolizer_ at the beginning of stackwalk for each minidump.
frame_symbolizer_->Reset();


MinidumpThreadNameList* thread_names = dump->GetThreadNameList();
std::map<uint32_t, string> thread_id_to_name;
if (thread_names) {
const unsigned int thread_name_count = thread_names->thread_name_count();
for (unsigned int thread_name_index = 0;
thread_name_index < thread_name_count;
++thread_name_index) {
MinidumpThreadName* thread_name = thread_names->GetThreadNameAtIndex(thread_name_index);
thread_name_index < thread_name_count; ++thread_name_index) {
MinidumpThreadName* thread_name =
thread_names->GetThreadNameAtIndex(thread_name_index);
if (!thread_name) {
BPLOG(ERROR) << "Could not get thread name for thread at index " << thread_name_index;
BPLOG(ERROR) << "Could not get thread name for thread at index "
<< thread_name_index;
return PROCESS_ERROR_GETTING_THREAD_NAME;
}
uint32_t thread_id;
if (!thread_name->GetThreadID(&thread_id)) {
BPLOG(ERROR) << "Could not get thread ID for thread at index " << thread_name_index;
BPLOG(ERROR) << "Could not get thread ID for thread at index "
<< thread_name_index;
return PROCESS_ERROR_GETTING_THREAD_NAME;
}
thread_id_to_name.insert(std::make_pair(thread_id, thread_name->GetThreadName()));
thread_id_to_name.insert(
std::make_pair(thread_id, thread_name->GetThreadName()));
}
}

Expand Down Expand Up @@ -270,6 +278,7 @@ ProcessResult MinidumpProcessor::Process(
// dump of itself (when both its context and its stack are in flux),
// processing that stack wouldn't provide much useful data.
if (has_dump_thread && thread_id == dump_thread_id) {
process_state->original_thread_count_--;
continue;
}

Expand All @@ -290,6 +299,13 @@ ProcessResult MinidumpProcessor::Process(
// be the index of the current thread when it's pushed into the
// vector.
process_state->requesting_thread_ = process_state->threads_.size();
if (max_thread_count_ >= 0) {
thread_count =
std::min(thread_count,
std::max(static_cast<unsigned int>(
process_state->requesting_thread_ + 1),
static_cast<unsigned int>(max_thread_count_)));
}

found_requesting_thread = true;

Expand Down Expand Up @@ -1341,7 +1357,7 @@ string MinidumpProcessor::GetCrashReason(Minidump* dump, uint64_t* address,
// an attempt to read data, 1 if it was an attempt to write data,
// and 8 if this was a data execution violation.
// exception_information[2] contains the underlying NTSTATUS code,
// which is the explanation for why this error occured.
// which is the explanation for why this error occurred.
// This information is useful in addition to the code address, which
// will be present in the crash thread's instruction field anyway.
if (raw_exception->exception_record.number_parameters >= 1) {
Expand Down
1 change: 1 addition & 0 deletions src/processor/process_state.cc
Original file line number Diff line number Diff line change
Expand Up @@ -54,6 +54,7 @@ void ProcessState::Clear() {
crash_address_ = 0;
assertion_.clear();
requesting_thread_ = -1;
original_thread_count_ = 0;
for (vector<CallStack*>::const_iterator iterator = threads_.begin();
iterator != threads_.end();
++iterator) {
Expand Down

0 comments on commit e0a3a76

Please sign in to comment.