1 // Copyright (c) 2006, Google Inc.
2 // All rights reserved.
3 //
4 // Redistribution and use in source and binary forms, with or without
5 // modification, are permitted provided that the following conditions are
6 // met:
7 //
8 // * Redistributions of source code must retain the above copyright
9 // notice, this list of conditions and the following disclaimer.
10 // * Redistributions in binary form must reproduce the above
11 // copyright notice, this list of conditions and the following disclaimer
12 // in the documentation and/or other materials provided with the
13 // distribution.
14 // * Neither the name of Google Inc. nor the names of its
15 // contributors may be used to endorse or promote products derived from
16 // this software without specific prior written permission.
17 //
18 // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29
30 // minidump_dump.cc: Print the contents of a minidump file in somewhat
31 // readable text.
32 //
33 // Author: Mark Mentovai
34
35 #include <stdio.h>
36 #include <string.h>
37 #include <unistd.h>
38
39 #include "common/scoped_ptr.h"
40 #include "google_breakpad/processor/minidump.h"
41 #include "processor/logging.h"
42
43 namespace {
44
45 using google_breakpad::Minidump;
46 using google_breakpad::MinidumpThreadList;
47 using google_breakpad::MinidumpModuleList;
48 using google_breakpad::MinidumpMemoryInfoList;
49 using google_breakpad::MinidumpMemoryList;
50 using google_breakpad::MinidumpException;
51 using google_breakpad::MinidumpAssertion;
52 using google_breakpad::MinidumpSystemInfo;
53 using google_breakpad::MinidumpMiscInfo;
54 using google_breakpad::MinidumpBreakpadInfo;
55 using google_breakpad::MinidumpCrashpadInfo;
56
57 struct Options {
Options__anon29ef6f1d0111::Options58 Options()
59 : minidumpPath(), hexdump(false), hexdump_width(16) {}
60
61 string minidumpPath;
62 bool hexdump;
63 unsigned int hexdump_width;
64 };
65
DumpRawStream(Minidump * minidump,uint32_t stream_type,const char * stream_name,int * errors)66 static void DumpRawStream(Minidump *minidump,
67 uint32_t stream_type,
68 const char *stream_name,
69 int *errors) {
70 uint32_t length = 0;
71 if (!minidump->SeekToStreamType(stream_type, &length)) {
72 return;
73 }
74
75 printf("Stream %s:\n", stream_name);
76
77 if (length == 0) {
78 printf("\n");
79 return;
80 }
81 std::vector<char> contents(length);
82 if (!minidump->ReadBytes(&contents[0], length)) {
83 ++*errors;
84 BPLOG(ERROR) << "minidump.ReadBytes failed";
85 return;
86 }
87 size_t current_offset = 0;
88 while (current_offset < length) {
89 size_t remaining = length - current_offset;
90 // Printf requires an int and direct casting from size_t results
91 // in compatibility warnings.
92 uint32_t int_remaining = remaining;
93 printf("%.*s", int_remaining, &contents[current_offset]);
94 char *next_null = reinterpret_cast<char *>(
95 memchr(&contents[current_offset], 0, remaining));
96 if (next_null == NULL)
97 break;
98 printf("\\0\n");
99 size_t null_offset = next_null - &contents[0];
100 current_offset = null_offset + 1;
101 }
102 printf("\n\n");
103 }
104
PrintMinidumpDump(const Options & options)105 static bool PrintMinidumpDump(const Options& options) {
106 Minidump minidump(options.minidumpPath,
107 options.hexdump);
108 if (!minidump.Read()) {
109 BPLOG(ERROR) << "minidump.Read() failed";
110 return false;
111 }
112 minidump.Print();
113
114 int errors = 0;
115
116 MinidumpThreadList *thread_list = minidump.GetThreadList();
117 if (!thread_list) {
118 ++errors;
119 BPLOG(ERROR) << "minidump.GetThreadList() failed";
120 } else {
121 thread_list->Print();
122 }
123
124 // It's useful to be able to see the full list of modules here even if it
125 // would cause minidump_stackwalk to fail.
126 MinidumpModuleList::set_max_modules(UINT32_MAX);
127 MinidumpModuleList *module_list = minidump.GetModuleList();
128 if (!module_list) {
129 ++errors;
130 BPLOG(ERROR) << "minidump.GetModuleList() failed";
131 } else {
132 module_list->Print();
133 }
134
135 MinidumpMemoryList *memory_list = minidump.GetMemoryList();
136 if (!memory_list) {
137 ++errors;
138 BPLOG(ERROR) << "minidump.GetMemoryList() failed";
139 } else {
140 memory_list->Print();
141 }
142
143 MinidumpException *exception = minidump.GetException();
144 if (!exception) {
145 BPLOG(INFO) << "minidump.GetException() failed";
146 } else {
147 exception->Print();
148 }
149
150 MinidumpAssertion *assertion = minidump.GetAssertion();
151 if (!assertion) {
152 BPLOG(INFO) << "minidump.GetAssertion() failed";
153 } else {
154 assertion->Print();
155 }
156
157 MinidumpSystemInfo *system_info = minidump.GetSystemInfo();
158 if (!system_info) {
159 ++errors;
160 BPLOG(ERROR) << "minidump.GetSystemInfo() failed";
161 } else {
162 system_info->Print();
163 }
164
165 MinidumpMiscInfo *misc_info = minidump.GetMiscInfo();
166 if (!misc_info) {
167 ++errors;
168 BPLOG(ERROR) << "minidump.GetMiscInfo() failed";
169 } else {
170 misc_info->Print();
171 }
172
173 MinidumpBreakpadInfo *breakpad_info = minidump.GetBreakpadInfo();
174 if (!breakpad_info) {
175 // Breakpad info is optional, so don't treat this as an error.
176 BPLOG(INFO) << "minidump.GetBreakpadInfo() failed";
177 } else {
178 breakpad_info->Print();
179 }
180
181 MinidumpMemoryInfoList *memory_info_list = minidump.GetMemoryInfoList();
182 if (!memory_info_list) {
183 ++errors;
184 BPLOG(ERROR) << "minidump.GetMemoryInfoList() failed";
185 } else {
186 memory_info_list->Print();
187 }
188
189 MinidumpCrashpadInfo *crashpad_info = minidump.GetCrashpadInfo();
190 if (crashpad_info) {
191 // Crashpad info is optional, so don't treat absence as an error.
192 crashpad_info->Print();
193 }
194
195 DumpRawStream(&minidump,
196 MD_LINUX_CMD_LINE,
197 "MD_LINUX_CMD_LINE",
198 &errors);
199 DumpRawStream(&minidump,
200 MD_LINUX_ENVIRON,
201 "MD_LINUX_ENVIRON",
202 &errors);
203 DumpRawStream(&minidump,
204 MD_LINUX_LSB_RELEASE,
205 "MD_LINUX_LSB_RELEASE",
206 &errors);
207 DumpRawStream(&minidump,
208 MD_LINUX_PROC_STATUS,
209 "MD_LINUX_PROC_STATUS",
210 &errors);
211 DumpRawStream(&minidump,
212 MD_LINUX_CPU_INFO,
213 "MD_LINUX_CPU_INFO",
214 &errors);
215 DumpRawStream(&minidump,
216 MD_LINUX_MAPS,
217 "MD_LINUX_MAPS",
218 &errors);
219
220 return errors == 0;
221 }
222
223 //=============================================================================
224 static void
Usage(int argc,char * argv[],bool error)225 Usage(int argc, char *argv[], bool error) {
226 FILE *fp = error ? stderr : stdout;
227
228 fprintf(fp,
229 "Usage: %s [options...] <minidump>\n"
230 "Dump data in a minidump.\n"
231 "\n"
232 "Options:\n"
233 " <minidump> should be a minidump.\n"
234 " -x:\t Display memory in a hexdump like format\n"
235 " -h:\t Usage\n",
236 argv[0]);
237 }
238
239 //=============================================================================
240 static void
SetupOptions(int argc,char * argv[],Options * options)241 SetupOptions(int argc, char *argv[], Options *options) {
242 int ch;
243
244 while ((ch = getopt(argc, (char * const *)argv, "xh")) != -1) {
245 switch (ch) {
246 case 'x':
247 options->hexdump = true;
248 break;
249 case 'h':
250 Usage(argc, argv, false);
251 exit(0);
252
253 default:
254 Usage(argc, argv, true);
255 exit(1);
256 break;
257 }
258 }
259
260 if ((argc - optind) != 1) {
261 fprintf(stderr, "%s: Missing minidump file\n", argv[0]);
262 exit(1);
263 }
264
265 options->minidumpPath = argv[optind];
266 }
267
268 } // namespace
269
main(int argc,char * argv[])270 int main(int argc, char *argv[]) {
271 Options options;
272 BPLOG_INIT(&argc, &argv);
273 SetupOptions(argc, argv, &options);
274 return PrintMinidumpDump(options) ? 0 : 1;
275 }
276