/ src / processor / minidump_dump.cc
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  }