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