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