Add brief flag to minidump_stackwalk

The added flag will print only one line per frame for the requesting
thread (This is mostly the crashing thread).

Refactor the code for printing the frame so it can be reused.

Bug: 1374075
Change-Id: I8a1c8b1a09740fcaa23c3cc642468622ee64ea73
Reviewed-on: https://chromium-review.googlesource.com/c/breakpad/breakpad/+/4339771
Reviewed-by: Joshua Peraza <jperaza@chromium.org>
This commit is contained in:
Ziad Youssef 2023-03-15 15:34:30 +00:00 committed by Joshua Peraza
parent 3848d7e3b5
commit 309534f959
3 changed files with 54 additions and 26 deletions

View file

@ -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<string> 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;

View file

@ -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(" <no crashing or requesting dump thread identified>\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

View file

@ -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