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 }