diff --git a/src/processor/minidump_stackwalk.cc b/src/processor/minidump_stackwalk.cc index 5ff61b3c..08c30ed3 100644 --- a/src/processor/minidump_stackwalk.cc +++ b/src/processor/minidump_stackwalk.cc @@ -61,6 +61,7 @@ struct Options { bool machine_readable; bool output_stack_contents; bool output_requesting_thread_only; + bool brief; string minidump_file; std::vector symbol_paths; @@ -114,6 +115,8 @@ bool PrintMinidumpProcess(const Options& options) { if (options.machine_readable) { PrintProcessStateMachineReadable(process_state); + } else if (options.brief) { + PrintRequestingThreadBrief(process_state); } else { PrintProcessState(process_state, options.output_stack_contents, options.output_requesting_thread_only, &resolver); @@ -135,6 +138,7 @@ static void Usage(int argc, const char *argv[], bool error) { " -m Output in machine-readable format\n" " -s Output stack contents\n" " -c Output thread that causes crash or dump only\n", + " -b Brief of the thread that causes crash or dump\n", google_breakpad::BaseName(argv[0]).c_str()); } @@ -144,14 +148,18 @@ static void SetupOptions(int argc, const char *argv[], Options* options) { options->machine_readable = false; options->output_stack_contents = false; options->output_requesting_thread_only = false; + options->brief = false; - while ((ch = getopt(argc, (char * const*)argv, "chms")) != -1) { + while ((ch = getopt(argc, (char* const*)argv, "bchms")) != -1) { switch (ch) { case 'h': Usage(argc, argv, false); exit(0); break; + case 'b': + options->brief = true; + break; case 'c': options->output_requesting_thread_only = true; break; diff --git a/src/processor/stackwalk_common.cc b/src/processor/stackwalk_common.cc index 3a842959..889931ea 100644 --- a/src/processor/stackwalk_common.cc +++ b/src/processor/stackwalk_common.cc @@ -277,6 +277,33 @@ static void PrintStackContents(const string& indent, printf("\n"); } +static void PrintFrameHeader(const StackFrame* frame, int frame_index) { + printf("%2d ", frame_index); + + uint64_t instruction_address = frame->ReturnAddress(); + + if (frame->module) { + printf("%s", PathnameStripper::File(frame->module->code_file()).c_str()); + if (!frame->function_name.empty()) { + printf("!%s", frame->function_name.c_str()); + if (!frame->source_file_name.empty()) { + string source_file = PathnameStripper::File(frame->source_file_name); + printf(" [%s : %d + 0x%" PRIx64 "]", source_file.c_str(), + frame->source_line, + instruction_address - frame->source_line_base); + } else { + printf(" + 0x%" PRIx64, instruction_address - frame->function_base); + } + } else { + printf(" + 0x%" PRIx64, + instruction_address - frame->module->base_address()); + } + } else { + printf("0x%" PRIx64, instruction_address); + } + printf("\n "); +} + // PrintStack prints the call stack in |stack| to stdout, in a reasonably // useful form. Module, function, and source file names are displayed if // they are available. The code offset to the base code address of the @@ -298,31 +325,7 @@ static void PrintStack(const CallStack* stack, } for (int frame_index = 0; frame_index < frame_count; ++frame_index) { const StackFrame* frame = stack->frames()->at(frame_index); - printf("%2d ", frame_index); - - uint64_t instruction_address = frame->ReturnAddress(); - - if (frame->module) { - printf("%s", PathnameStripper::File(frame->module->code_file()).c_str()); - if (!frame->function_name.empty()) { - printf("!%s", frame->function_name.c_str()); - if (!frame->source_file_name.empty()) { - string source_file = PathnameStripper::File(frame->source_file_name); - printf(" [%s : %d + 0x%" PRIx64 "]", - source_file.c_str(), - frame->source_line, - instruction_address - frame->source_line_base); - } else { - printf(" + 0x%" PRIx64, instruction_address - frame->function_base); - } - } else { - printf(" + 0x%" PRIx64, - instruction_address - frame->module->base_address()); - } - } else { - printf("0x%" PRIx64, instruction_address); - } - printf("\n "); + PrintFrameHeader(frame, frame_index); // Inlined frames don't have registers info. if (frame->trust != StackFrameAMD64::FRAME_TRUST_INLINE) { @@ -1281,4 +1284,20 @@ void PrintProcessStateMachineReadable(const ProcessState& process_state) { } } +void PrintRequestingThreadBrief(const ProcessState& process_state) { + int requesting_thread = process_state.requesting_thread(); + if (requesting_thread == -1) { + printf(" \n"); + return; + } + + printf("Thread %d (%s)\n", requesting_thread, + process_state.crashed() ? "crashed" : "requested dump, did not crash"); + const CallStack* stack = process_state.threads()->at(requesting_thread); + int frame_count = stack->frames()->size(); + for (int frame_index = 0; frame_index < frame_count; ++frame_index) { + PrintFrameHeader(stack->frames()->at(frame_index), frame_index); + } +} + } // namespace google_breakpad diff --git a/src/processor/stackwalk_common.h b/src/processor/stackwalk_common.h index bb12b98f..3782f987 100644 --- a/src/processor/stackwalk_common.h +++ b/src/processor/stackwalk_common.h @@ -43,6 +43,7 @@ void PrintProcessState(const ProcessState& process_state, bool output_stack_contents, bool output_requesting_thread_only, SourceLineResolverInterface* resolver); +void PrintRequestingThreadBrief(const ProcessState& process_state); } // namespace google_breakpad