minidump_dump.cc
1 // Copyright 2006 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_dump.cc: Print the contents of a minidump file in somewhat 30 // readable text. 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 "common/path_helper.h" 43 #include "common/scoped_ptr.h" 44 #include "google_breakpad/processor/minidump.h" 45 #include "processor/logging.h" 46 47 namespace { 48 49 using google_breakpad::Minidump; 50 using google_breakpad::MinidumpThreadList; 51 using google_breakpad::MinidumpThreadNameList; 52 using google_breakpad::MinidumpModuleList; 53 using google_breakpad::MinidumpMemoryInfoList; 54 using google_breakpad::MinidumpMemoryList; 55 using google_breakpad::MinidumpException; 56 using google_breakpad::MinidumpAssertion; 57 using google_breakpad::MinidumpSystemInfo; 58 using google_breakpad::MinidumpMiscInfo; 59 using google_breakpad::MinidumpBreakpadInfo; 60 using google_breakpad::MinidumpCrashpadInfo; 61 62 struct Options { 63 Options() 64 : minidumpPath(), hexdump(false), hexdump_width(16) {} 65 66 string minidumpPath; 67 bool hexdump; 68 unsigned int hexdump_width; 69 }; 70 71 static void DumpRawStream(Minidump *minidump, 72 uint32_t stream_type, 73 const char *stream_name, 74 int *errors) { 75 uint32_t length = 0; 76 if (!minidump->SeekToStreamType(stream_type, &length)) { 77 return; 78 } 79 80 printf("Stream %s:\n", stream_name); 81 82 if (length == 0) { 83 printf("\n"); 84 return; 85 } 86 std::vector<char> contents(length); 87 if (!minidump->ReadBytes(&contents[0], length)) { 88 ++*errors; 89 BPLOG(ERROR) << "minidump.ReadBytes failed"; 90 return; 91 } 92 size_t current_offset = 0; 93 while (current_offset < length) { 94 size_t remaining = length - current_offset; 95 // Printf requires an int and direct casting from size_t results 96 // in compatibility warnings. 97 uint32_t int_remaining = remaining; 98 printf("%.*s", int_remaining, &contents[current_offset]); 99 char *next_null = reinterpret_cast<char*>( 100 memchr(&contents[current_offset], 0, remaining)); 101 if (next_null == NULL) 102 break; 103 printf("\\0\n"); 104 size_t null_offset = next_null - &contents[0]; 105 current_offset = null_offset + 1; 106 } 107 printf("\n\n"); 108 } 109 110 static bool PrintMinidumpDump(const Options& options) { 111 Minidump minidump(options.minidumpPath, 112 options.hexdump); 113 if (!minidump.Read()) { 114 BPLOG(ERROR) << "minidump.Read() failed"; 115 return false; 116 } 117 minidump.Print(); 118 119 int errors = 0; 120 121 MinidumpThreadList *thread_list = minidump.GetThreadList(); 122 if (!thread_list) { 123 ++errors; 124 BPLOG(ERROR) << "minidump.GetThreadList() failed"; 125 } else { 126 thread_list->Print(); 127 } 128 129 MinidumpThreadNameList *thread_name_list = minidump.GetThreadNameList(); 130 if (thread_name_list) { 131 thread_name_list->Print(); 132 } 133 134 // It's useful to be able to see the full list of modules here even if it 135 // would cause minidump_stackwalk to fail. 136 MinidumpModuleList::set_max_modules(UINT32_MAX); 137 MinidumpModuleList *module_list = minidump.GetModuleList(); 138 if (!module_list) { 139 ++errors; 140 BPLOG(ERROR) << "minidump.GetModuleList() failed"; 141 } else { 142 module_list->Print(); 143 } 144 145 MinidumpMemoryList *memory_list = minidump.GetMemoryList(); 146 if (!memory_list) { 147 ++errors; 148 BPLOG(ERROR) << "minidump.GetMemoryList() failed"; 149 } else { 150 memory_list->Print(); 151 } 152 153 MinidumpException *exception = minidump.GetException(); 154 if (!exception) { 155 BPLOG(INFO) << "minidump.GetException() failed"; 156 } else { 157 exception->Print(); 158 } 159 160 MinidumpAssertion *assertion = minidump.GetAssertion(); 161 if (!assertion) { 162 BPLOG(INFO) << "minidump.GetAssertion() failed"; 163 } else { 164 assertion->Print(); 165 } 166 167 MinidumpSystemInfo *system_info = minidump.GetSystemInfo(); 168 if (!system_info) { 169 ++errors; 170 BPLOG(ERROR) << "minidump.GetSystemInfo() failed"; 171 } else { 172 system_info->Print(); 173 } 174 175 MinidumpMiscInfo *misc_info = minidump.GetMiscInfo(); 176 if (!misc_info) { 177 ++errors; 178 BPLOG(ERROR) << "minidump.GetMiscInfo() failed"; 179 } else { 180 misc_info->Print(); 181 } 182 183 MinidumpBreakpadInfo *breakpad_info = minidump.GetBreakpadInfo(); 184 if (!breakpad_info) { 185 // Breakpad info is optional, so don't treat this as an error. 186 BPLOG(INFO) << "minidump.GetBreakpadInfo() failed"; 187 } else { 188 breakpad_info->Print(); 189 } 190 191 MinidumpMemoryInfoList *memory_info_list = minidump.GetMemoryInfoList(); 192 if (!memory_info_list) { 193 ++errors; 194 BPLOG(ERROR) << "minidump.GetMemoryInfoList() failed"; 195 } else { 196 memory_info_list->Print(); 197 } 198 199 MinidumpCrashpadInfo *crashpad_info = minidump.GetCrashpadInfo(); 200 if (crashpad_info) { 201 // Crashpad info is optional, so don't treat absence as an error. 202 crashpad_info->Print(); 203 } 204 205 DumpRawStream(&minidump, 206 MD_LINUX_CMD_LINE, 207 "MD_LINUX_CMD_LINE", 208 &errors); 209 DumpRawStream(&minidump, 210 MD_LINUX_ENVIRON, 211 "MD_LINUX_ENVIRON", 212 &errors); 213 DumpRawStream(&minidump, 214 MD_LINUX_LSB_RELEASE, 215 "MD_LINUX_LSB_RELEASE", 216 &errors); 217 DumpRawStream(&minidump, 218 MD_LINUX_PROC_STATUS, 219 "MD_LINUX_PROC_STATUS", 220 &errors); 221 DumpRawStream(&minidump, 222 MD_LINUX_CPU_INFO, 223 "MD_LINUX_CPU_INFO", 224 &errors); 225 DumpRawStream(&minidump, 226 MD_LINUX_MAPS, 227 "MD_LINUX_MAPS", 228 &errors); 229 230 return errors == 0; 231 } 232 233 //============================================================================= 234 static void 235 Usage(int argc, char *argv[], bool error) { 236 FILE *fp = error ? stderr : stdout; 237 238 fprintf(fp, 239 "Usage: %s [options...] <minidump>\n" 240 "Dump data in a minidump.\n" 241 "\n" 242 "Options:\n" 243 " <minidump> should be a minidump.\n" 244 " -x:\t Display memory in a hexdump like format\n" 245 " -h:\t Usage\n", 246 google_breakpad::BaseName(argv[0]).c_str()); 247 } 248 249 //============================================================================= 250 static void 251 SetupOptions(int argc, char *argv[], Options *options) { 252 int ch; 253 254 while ((ch = getopt(argc, (char * const*)argv, "xh")) != -1) { 255 switch (ch) { 256 case 'x': 257 options->hexdump = true; 258 break; 259 case 'h': 260 Usage(argc, argv, false); 261 exit(0); 262 263 default: 264 Usage(argc, argv, true); 265 exit(1); 266 break; 267 } 268 } 269 270 if ((argc - optind) != 1) { 271 fprintf(stderr, "%s: Missing minidump file\n", argv[0]); 272 exit(1); 273 } 274 275 options->minidumpPath = argv[optind]; 276 } 277 278 } // namespace 279 280 int main(int argc, char *argv[]) { 281 Options options; 282 BPLOG_INIT(&argc, &argv); 283 SetupOptions(argc, argv, &options); 284 return PrintMinidumpDump(options) ? 0 : 1; 285 }