xref: /aosp_15_r20/external/google-breakpad/src/processor/minidump_dump.cc (revision 9712c20fc9bbfbac4935993a2ca0b3958c5adad2)
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 {
Options__anon42a3008c0111::Options63   Options()
64       : minidumpPath(), hexdump(false), hexdump_width(16) {}
65 
66   string minidumpPath;
67   bool hexdump;
68   unsigned int hexdump_width;
69 };
70 
DumpRawStream(Minidump * minidump,uint32_t stream_type,const char * stream_name,int * errors)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 
PrintMinidumpDump(const Options & options)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
Usage(int argc,char * argv[],bool error)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
SetupOptions(int argc,char * argv[],Options * options)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 
main(int argc,char * argv[])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 }
286