microdump_stackwalk.cc
1 // Copyright 2014 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 // microdump_stackwalk.cc: Process a microdump with MicrodumpProcessor, printing 30 // the results, including stack traces. 31 32 #ifdef HAVE_CONFIG_H 33 #include <config.h> // Must come first 34 #endif 35 36 #include <stdio.h> 37 #include <string.h> 38 #include <unistd.h> 39 40 #include <fstream> 41 #include <string> 42 #include <vector> 43 44 #include "common/path_helper.h" 45 #include "common/scoped_ptr.h" 46 #include "common/using_std_string.h" 47 #include "google_breakpad/processor/basic_source_line_resolver.h" 48 #include "google_breakpad/processor/microdump.h" 49 #include "google_breakpad/processor/microdump_processor.h" 50 #include "google_breakpad/processor/process_state.h" 51 #include "google_breakpad/processor/stack_frame_symbolizer.h" 52 #include "processor/logging.h" 53 #include "processor/simple_symbol_supplier.h" 54 #include "processor/stackwalk_common.h" 55 56 57 namespace { 58 59 struct Options { 60 bool machine_readable; 61 bool output_stack_contents; 62 63 string microdump_file; 64 std::vector<string> symbol_paths; 65 }; 66 67 using google_breakpad::BasicSourceLineResolver; 68 using google_breakpad::Microdump; 69 using google_breakpad::MicrodumpProcessor; 70 using google_breakpad::ProcessResult; 71 using google_breakpad::ProcessState; 72 using google_breakpad::scoped_ptr; 73 using google_breakpad::SimpleSymbolSupplier; 74 using google_breakpad::StackFrameSymbolizer; 75 76 // Processes |options.microdump_file| using 77 // MicrodumpProcessor. |options.symbol_path|, if non-empty, is the 78 // base directory of a symbol storage area, laid out in the format 79 // required by SimpleSymbolSupplier. If such a storage area is 80 // specified, it is made available for use by the MicrodumpProcessor. 81 // 82 // Returns the value of MicrodumpProcessor::Process. If processing succeeds, 83 // prints identifying OS and CPU information from the microdump, crash 84 // information and call stacks for the crashing thread. 85 // All information is printed to stdout. 86 int PrintMicrodumpProcess(const Options& options) { 87 std::ifstream file_stream(options.microdump_file); 88 std::vector<char> bytes; 89 file_stream.seekg(0, std::ios_base::end); 90 bytes.resize(file_stream.tellg()); 91 if (bytes.empty()) { 92 BPLOG(ERROR) << "Microdump is empty."; 93 return 1; 94 } 95 file_stream.seekg(0, std::ios_base::beg); 96 file_stream.read(&bytes[0], bytes.size()); 97 string microdump_content(&bytes[0], bytes.size()); 98 99 scoped_ptr<SimpleSymbolSupplier> symbol_supplier; 100 if (!options.symbol_paths.empty()) { 101 symbol_supplier.reset(new SimpleSymbolSupplier(options.symbol_paths)); 102 } 103 104 BasicSourceLineResolver resolver; 105 StackFrameSymbolizer frame_symbolizer(symbol_supplier.get(), &resolver); 106 ProcessState process_state; 107 MicrodumpProcessor microdump_processor(&frame_symbolizer); 108 Microdump microdump(microdump_content); 109 ProcessResult res = microdump_processor.Process(µdump, 110 &process_state); 111 112 if (res == google_breakpad::PROCESS_OK) { 113 if (options.machine_readable) { 114 PrintProcessStateMachineReadable(process_state); 115 } else { 116 // Microdump has only one thread, |output_requesting_thread_only|'s value 117 // has no effect. 118 PrintProcessState(process_state, options.output_stack_contents, 119 /*output_requesting_thread_only=*/false, &resolver); 120 } 121 return 0; 122 } 123 124 BPLOG(ERROR) << "MicrodumpProcessor::Process failed (code = " << res << ")"; 125 return 1; 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] <microdump-file> [symbol-path ...]\n" 133 "\n" 134 "Output a stack trace for the provided microdump\n" 135 "\n" 136 "Options:\n" 137 "\n" 138 " -m Output in machine-readable format\n" 139 " -s Output stack contents\n", 140 google_breakpad::BaseName(argv[0]).c_str()); 141 } 142 143 static void SetupOptions(int argc, const char *argv[], Options* options) { 144 int ch; 145 146 options->machine_readable = false; 147 options->output_stack_contents = false; 148 149 while ((ch = getopt(argc, (char * const*)argv, "hms")) != -1) { 150 switch (ch) { 151 case 'h': 152 Usage(argc, argv, false); 153 exit(0); 154 break; 155 156 case 'm': 157 options->machine_readable = true; 158 break; 159 case 's': 160 options->output_stack_contents = true; 161 break; 162 163 case '?': 164 Usage(argc, argv, true); 165 exit(1); 166 break; 167 } 168 } 169 170 if ((argc - optind) == 0) { 171 fprintf(stderr, "%s: Missing microdump file\n", argv[0]); 172 Usage(argc, argv, true); 173 exit(1); 174 } 175 176 options->microdump_file = argv[optind]; 177 178 for (int argi = optind + 1; argi < argc; ++argi) 179 options->symbol_paths.push_back(argv[argi]); 180 } 181 182 int main(int argc, const char* argv[]) { 183 Options options; 184 SetupOptions(argc, argv, &options); 185 186 return PrintMicrodumpProcess(options); 187 }