minidump-2-core: Use exception context for crashed thread

Use the exception record's context for the crashed thread instead of
the thread's own context. For the crashed thread the thread's own
context is the state inside the exception handler. Using it would not
result in the expected stack trace from the time of the crash.

This change aligns the behavior of minidump-2-core with the behavior of
minidump_stackwalk.

Bug: google-breakpad:885
Change-Id: I5cd3e9d39807308491b64fcd335f5f85b1dcd084
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/4473128
Reviewed-by: Joshua Peraza <jperaza@google.com>
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
Ben Wagner 2023-04-24 23:41:28 -04:00 committed by Joshua Peraza
parent 68f5a4d11a
commit de040fa25d

View file

@ -282,7 +282,7 @@ typedef struct prpsinfo { /* Information about process */
// We parse the minidump file and keep the parsed information in this structure
struct CrashedProcess {
CrashedProcess()
: crashing_tid(-1),
: exception{-1},
auxv(NULL),
auxv_length(0) {
memset(&prps, 0, sizeof(prps));
@ -306,7 +306,6 @@ struct CrashedProcess {
};
std::map<uint64_t, Mapping> mappings;
pid_t crashing_tid;
int fatal_signal;
struct Thread {
@ -330,6 +329,7 @@ struct CrashedProcess {
size_t stack_length;
};
std::vector<Thread> threads;
Thread exception;
const uint8_t* auxv;
size_t auxv_length;
@ -999,10 +999,25 @@ ParseDSODebugInfo(const Options& options, CrashedProcess* crashinfo,
static void
ParseExceptionStream(const Options& options, CrashedProcess* crashinfo,
const MinidumpMemoryRange& range) {
const MinidumpMemoryRange& range,
const MinidumpMemoryRange& full_file) {
const MDRawExceptionStream* exp = range.GetData<MDRawExceptionStream>(0);
crashinfo->crashing_tid = exp->thread_id;
if (!exp) {
return;
}
if (options.verbose) {
fprintf(stderr,
"MD_EXCEPTION_STREAM:\n"
"Found exception thread %" PRIu32 " \n"
"\n\n",
exp->thread_id);
}
crashinfo->fatal_signal = (int) exp->exception_record.exception_code;
crashinfo->exception = {};
crashinfo->exception.tid = exp->thread_id;
// crashinfo->threads[].tid == crashinfo->exception.tid provides the stack.
ParseThreadRegisters(&crashinfo->exception,
full_file.Subrange(exp->thread_context));
}
static bool
@ -1365,7 +1380,7 @@ main(int argc, const char* argv[]) {
break;
case MD_EXCEPTION_STREAM:
ParseExceptionStream(options, &crashinfo,
dump.Subrange(dirent->location));
dump.Subrange(dirent->location), dump);
break;
case MD_MODULE_LIST_STREAM:
ParseModuleStream(options, &crashinfo, dump.Subrange(dirent->location),
@ -1481,16 +1496,21 @@ main(int argc, const char* argv[]) {
return 1;
}
for (unsigned i = 0; i < crashinfo.threads.size(); ++i) {
if (crashinfo.threads[i].tid == crashinfo.crashing_tid) {
WriteThread(options, crashinfo.threads[i], crashinfo.fatal_signal);
for (const auto& current_thread : crashinfo.threads) {
if (current_thread.tid == crashinfo.exception.tid) {
// Use the exception record's context for the crashed thread instead of
// the thread's own context. For the crashed thread the thread's own
// context is the state inside the exception handler. Using it would not
// result in the expected stack trace from the time of the crash.
// The stack memory has already been provided by current_thread.
WriteThread(options, crashinfo.exception, crashinfo.fatal_signal);
break;
}
}
for (unsigned i = 0; i < crashinfo.threads.size(); ++i) {
if (crashinfo.threads[i].tid != crashinfo.crashing_tid)
WriteThread(options, crashinfo.threads[i], 0);
for (const auto& current_thread : crashinfo.threads) {
if (current_thread.tid != crashinfo.exception.tid)
WriteThread(options, current_thread, 0);
}
if (note_align) {