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