xref: /aosp_15_r20/external/google-breakpad/src/processor/microdump_stackwalk.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
1*9712c20fSFrederick Mayle // Copyright 2014 Google LLC
2*9712c20fSFrederick Mayle //
3*9712c20fSFrederick Mayle // Redistribution and use in source and binary forms, with or without
4*9712c20fSFrederick Mayle // modification, are permitted provided that the following conditions are
5*9712c20fSFrederick Mayle // met:
6*9712c20fSFrederick Mayle //
7*9712c20fSFrederick Mayle //     * Redistributions of source code must retain the above copyright
8*9712c20fSFrederick Mayle // notice, this list of conditions and the following disclaimer.
9*9712c20fSFrederick Mayle //     * Redistributions in binary form must reproduce the above
10*9712c20fSFrederick Mayle // copyright notice, this list of conditions and the following disclaimer
11*9712c20fSFrederick Mayle // in the documentation and/or other materials provided with the
12*9712c20fSFrederick Mayle // distribution.
13*9712c20fSFrederick Mayle //     * Neither the name of Google LLC nor the names of its
14*9712c20fSFrederick Mayle // contributors may be used to endorse or promote products derived from
15*9712c20fSFrederick Mayle // this software without specific prior written permission.
16*9712c20fSFrederick Mayle //
17*9712c20fSFrederick Mayle // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18*9712c20fSFrederick Mayle // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19*9712c20fSFrederick Mayle // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20*9712c20fSFrederick Mayle // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21*9712c20fSFrederick Mayle // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22*9712c20fSFrederick Mayle // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23*9712c20fSFrederick Mayle // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24*9712c20fSFrederick Mayle // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25*9712c20fSFrederick Mayle // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26*9712c20fSFrederick Mayle // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27*9712c20fSFrederick Mayle // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28*9712c20fSFrederick Mayle 
29*9712c20fSFrederick Mayle // microdump_stackwalk.cc: Process a microdump with MicrodumpProcessor, printing
30*9712c20fSFrederick Mayle // the results, including stack traces.
31*9712c20fSFrederick Mayle 
32*9712c20fSFrederick Mayle #ifdef HAVE_CONFIG_H
33*9712c20fSFrederick Mayle #include <config.h>  // Must come first
34*9712c20fSFrederick Mayle #endif
35*9712c20fSFrederick Mayle 
36*9712c20fSFrederick Mayle #include <stdio.h>
37*9712c20fSFrederick Mayle #include <string.h>
38*9712c20fSFrederick Mayle #include <unistd.h>
39*9712c20fSFrederick Mayle 
40*9712c20fSFrederick Mayle #include <fstream>
41*9712c20fSFrederick Mayle #include <string>
42*9712c20fSFrederick Mayle #include <vector>
43*9712c20fSFrederick Mayle 
44*9712c20fSFrederick Mayle #include "common/path_helper.h"
45*9712c20fSFrederick Mayle #include "common/scoped_ptr.h"
46*9712c20fSFrederick Mayle #include "common/using_std_string.h"
47*9712c20fSFrederick Mayle #include "google_breakpad/processor/basic_source_line_resolver.h"
48*9712c20fSFrederick Mayle #include "google_breakpad/processor/microdump.h"
49*9712c20fSFrederick Mayle #include "google_breakpad/processor/microdump_processor.h"
50*9712c20fSFrederick Mayle #include "google_breakpad/processor/process_state.h"
51*9712c20fSFrederick Mayle #include "google_breakpad/processor/stack_frame_symbolizer.h"
52*9712c20fSFrederick Mayle #include "processor/logging.h"
53*9712c20fSFrederick Mayle #include "processor/simple_symbol_supplier.h"
54*9712c20fSFrederick Mayle #include "processor/stackwalk_common.h"
55*9712c20fSFrederick Mayle 
56*9712c20fSFrederick Mayle 
57*9712c20fSFrederick Mayle namespace {
58*9712c20fSFrederick Mayle 
59*9712c20fSFrederick Mayle struct Options {
60*9712c20fSFrederick Mayle   bool machine_readable;
61*9712c20fSFrederick Mayle   bool output_stack_contents;
62*9712c20fSFrederick Mayle 
63*9712c20fSFrederick Mayle   string microdump_file;
64*9712c20fSFrederick Mayle   std::vector<string> symbol_paths;
65*9712c20fSFrederick Mayle };
66*9712c20fSFrederick Mayle 
67*9712c20fSFrederick Mayle using google_breakpad::BasicSourceLineResolver;
68*9712c20fSFrederick Mayle using google_breakpad::Microdump;
69*9712c20fSFrederick Mayle using google_breakpad::MicrodumpProcessor;
70*9712c20fSFrederick Mayle using google_breakpad::ProcessResult;
71*9712c20fSFrederick Mayle using google_breakpad::ProcessState;
72*9712c20fSFrederick Mayle using google_breakpad::scoped_ptr;
73*9712c20fSFrederick Mayle using google_breakpad::SimpleSymbolSupplier;
74*9712c20fSFrederick Mayle using google_breakpad::StackFrameSymbolizer;
75*9712c20fSFrederick Mayle 
76*9712c20fSFrederick Mayle // Processes |options.microdump_file| using
77*9712c20fSFrederick Mayle // MicrodumpProcessor. |options.symbol_path|, if non-empty, is the
78*9712c20fSFrederick Mayle // base directory of a symbol storage area, laid out in the format
79*9712c20fSFrederick Mayle // required by SimpleSymbolSupplier.  If such a storage area is
80*9712c20fSFrederick Mayle // specified, it is made available for use by the MicrodumpProcessor.
81*9712c20fSFrederick Mayle //
82*9712c20fSFrederick Mayle // Returns the value of MicrodumpProcessor::Process. If processing succeeds,
83*9712c20fSFrederick Mayle // prints identifying OS and CPU information from the microdump, crash
84*9712c20fSFrederick Mayle // information and call stacks for the crashing thread.
85*9712c20fSFrederick Mayle // All information is printed to stdout.
PrintMicrodumpProcess(const Options & options)86*9712c20fSFrederick Mayle int PrintMicrodumpProcess(const Options& options) {
87*9712c20fSFrederick Mayle   std::ifstream file_stream(options.microdump_file);
88*9712c20fSFrederick Mayle   std::vector<char> bytes;
89*9712c20fSFrederick Mayle   file_stream.seekg(0, std::ios_base::end);
90*9712c20fSFrederick Mayle   bytes.resize(file_stream.tellg());
91*9712c20fSFrederick Mayle   if (bytes.empty()) {
92*9712c20fSFrederick Mayle     BPLOG(ERROR) << "Microdump is empty.";
93*9712c20fSFrederick Mayle     return 1;
94*9712c20fSFrederick Mayle   }
95*9712c20fSFrederick Mayle   file_stream.seekg(0, std::ios_base::beg);
96*9712c20fSFrederick Mayle   file_stream.read(&bytes[0], bytes.size());
97*9712c20fSFrederick Mayle   string microdump_content(&bytes[0], bytes.size());
98*9712c20fSFrederick Mayle 
99*9712c20fSFrederick Mayle   scoped_ptr<SimpleSymbolSupplier> symbol_supplier;
100*9712c20fSFrederick Mayle   if (!options.symbol_paths.empty()) {
101*9712c20fSFrederick Mayle     symbol_supplier.reset(new SimpleSymbolSupplier(options.symbol_paths));
102*9712c20fSFrederick Mayle   }
103*9712c20fSFrederick Mayle 
104*9712c20fSFrederick Mayle   BasicSourceLineResolver resolver;
105*9712c20fSFrederick Mayle   StackFrameSymbolizer frame_symbolizer(symbol_supplier.get(), &resolver);
106*9712c20fSFrederick Mayle   ProcessState process_state;
107*9712c20fSFrederick Mayle   MicrodumpProcessor microdump_processor(&frame_symbolizer);
108*9712c20fSFrederick Mayle   Microdump microdump(microdump_content);
109*9712c20fSFrederick Mayle   ProcessResult res = microdump_processor.Process(&microdump,
110*9712c20fSFrederick Mayle                                                   &process_state);
111*9712c20fSFrederick Mayle 
112*9712c20fSFrederick Mayle   if (res == google_breakpad::PROCESS_OK) {
113*9712c20fSFrederick Mayle     if (options.machine_readable) {
114*9712c20fSFrederick Mayle       PrintProcessStateMachineReadable(process_state);
115*9712c20fSFrederick Mayle     } else {
116*9712c20fSFrederick Mayle       // Microdump has only one thread, |output_requesting_thread_only|'s value
117*9712c20fSFrederick Mayle       // has no effect.
118*9712c20fSFrederick Mayle       PrintProcessState(process_state, options.output_stack_contents,
119*9712c20fSFrederick Mayle                         /*output_requesting_thread_only=*/false, &resolver);
120*9712c20fSFrederick Mayle     }
121*9712c20fSFrederick Mayle     return 0;
122*9712c20fSFrederick Mayle   }
123*9712c20fSFrederick Mayle 
124*9712c20fSFrederick Mayle   BPLOG(ERROR) << "MicrodumpProcessor::Process failed (code = " << res << ")";
125*9712c20fSFrederick Mayle   return 1;
126*9712c20fSFrederick Mayle }
127*9712c20fSFrederick Mayle 
128*9712c20fSFrederick Mayle }  // namespace
129*9712c20fSFrederick Mayle 
Usage(int argc,const char * argv[],bool error)130*9712c20fSFrederick Mayle static void Usage(int argc, const char *argv[], bool error) {
131*9712c20fSFrederick Mayle   fprintf(error ? stderr : stdout,
132*9712c20fSFrederick Mayle           "Usage: %s [options] <microdump-file> [symbol-path ...]\n"
133*9712c20fSFrederick Mayle           "\n"
134*9712c20fSFrederick Mayle           "Output a stack trace for the provided microdump\n"
135*9712c20fSFrederick Mayle           "\n"
136*9712c20fSFrederick Mayle           "Options:\n"
137*9712c20fSFrederick Mayle           "\n"
138*9712c20fSFrederick Mayle           "  -m         Output in machine-readable format\n"
139*9712c20fSFrederick Mayle           "  -s         Output stack contents\n",
140*9712c20fSFrederick Mayle           google_breakpad::BaseName(argv[0]).c_str());
141*9712c20fSFrederick Mayle }
142*9712c20fSFrederick Mayle 
SetupOptions(int argc,const char * argv[],Options * options)143*9712c20fSFrederick Mayle static void SetupOptions(int argc, const char *argv[], Options* options) {
144*9712c20fSFrederick Mayle   int ch;
145*9712c20fSFrederick Mayle 
146*9712c20fSFrederick Mayle   options->machine_readable = false;
147*9712c20fSFrederick Mayle   options->output_stack_contents = false;
148*9712c20fSFrederick Mayle 
149*9712c20fSFrederick Mayle   while ((ch = getopt(argc, (char * const*)argv, "hms")) != -1) {
150*9712c20fSFrederick Mayle     switch (ch) {
151*9712c20fSFrederick Mayle       case 'h':
152*9712c20fSFrederick Mayle         Usage(argc, argv, false);
153*9712c20fSFrederick Mayle         exit(0);
154*9712c20fSFrederick Mayle         break;
155*9712c20fSFrederick Mayle 
156*9712c20fSFrederick Mayle       case 'm':
157*9712c20fSFrederick Mayle         options->machine_readable = true;
158*9712c20fSFrederick Mayle         break;
159*9712c20fSFrederick Mayle       case 's':
160*9712c20fSFrederick Mayle         options->output_stack_contents = true;
161*9712c20fSFrederick Mayle         break;
162*9712c20fSFrederick Mayle 
163*9712c20fSFrederick Mayle       case '?':
164*9712c20fSFrederick Mayle         Usage(argc, argv, true);
165*9712c20fSFrederick Mayle         exit(1);
166*9712c20fSFrederick Mayle         break;
167*9712c20fSFrederick Mayle     }
168*9712c20fSFrederick Mayle   }
169*9712c20fSFrederick Mayle 
170*9712c20fSFrederick Mayle   if ((argc - optind) == 0) {
171*9712c20fSFrederick Mayle     fprintf(stderr, "%s: Missing microdump file\n", argv[0]);
172*9712c20fSFrederick Mayle     Usage(argc, argv, true);
173*9712c20fSFrederick Mayle     exit(1);
174*9712c20fSFrederick Mayle   }
175*9712c20fSFrederick Mayle 
176*9712c20fSFrederick Mayle   options->microdump_file = argv[optind];
177*9712c20fSFrederick Mayle 
178*9712c20fSFrederick Mayle   for (int argi = optind + 1; argi < argc; ++argi)
179*9712c20fSFrederick Mayle     options->symbol_paths.push_back(argv[argi]);
180*9712c20fSFrederick Mayle }
181*9712c20fSFrederick Mayle 
main(int argc,const char * argv[])182*9712c20fSFrederick Mayle int main(int argc, const char* argv[]) {
183*9712c20fSFrederick Mayle   Options options;
184*9712c20fSFrederick Mayle   SetupOptions(argc, argv, &options);
185*9712c20fSFrederick Mayle 
186*9712c20fSFrederick Mayle   return PrintMicrodumpProcess(options);
187*9712c20fSFrederick Mayle }
188