toolkit/crashreporter/google-breakpad/src/processor/minidump_stackwalk.cc

Wed, 31 Dec 2014 06:09:35 +0100

author
Michael Schloh von Bennewitz <michael@schloh.com>
date
Wed, 31 Dec 2014 06:09:35 +0100
changeset 0
6474c204b198
permissions
-rw-r--r--

Cloned upstream origin tor-browser at tor-browser-31.3.0esr-4.5-1-build1
revision ID fc1c9ff7c1b2defdbc039f12214767608f46423f for hacking purpose.

     1 // Copyright (c) 2010 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.
    30 // minidump_stackwalk.cc: Process a minidump with MinidumpProcessor, printing
    31 // the results, including stack traces.
    32 //
    33 // Author: Mark Mentovai
    35 #include <stdio.h>
    36 #include <stdlib.h>
    37 #include <string.h>
    39 #include <string>
    40 #include <vector>
    42 #include "common/scoped_ptr.h"
    43 #include "common/using_std_string.h"
    44 #include "google_breakpad/processor/basic_source_line_resolver.h"
    45 #include "google_breakpad/processor/call_stack.h"
    46 #include "google_breakpad/processor/code_module.h"
    47 #include "google_breakpad/processor/code_modules.h"
    48 #include "google_breakpad/processor/minidump.h"
    49 #include "google_breakpad/processor/minidump_processor.h"
    50 #include "google_breakpad/processor/process_state.h"
    51 #include "google_breakpad/processor/stack_frame_cpu.h"
    52 #include "processor/logging.h"
    53 #include "processor/pathname_stripper.h"
    54 #include "processor/simple_symbol_supplier.h"
    56 namespace {
    58 using std::vector;
    59 using google_breakpad::BasicSourceLineResolver;
    60 using google_breakpad::CallStack;
    61 using google_breakpad::CodeModule;
    62 using google_breakpad::CodeModules;
    63 using google_breakpad::MinidumpModule;
    64 using google_breakpad::MinidumpProcessor;
    65 using google_breakpad::PathnameStripper;
    66 using google_breakpad::ProcessState;
    67 using google_breakpad::scoped_ptr;
    68 using google_breakpad::SimpleSymbolSupplier;
    69 using google_breakpad::StackFrame;
    70 using google_breakpad::StackFramePPC;
    71 using google_breakpad::StackFrameSPARC;
    72 using google_breakpad::StackFrameX86;
    73 using google_breakpad::StackFrameAMD64;
    74 using google_breakpad::StackFrameARM;
    76 // Separator character for machine readable output.
    77 static const char kOutputSeparator = '|';
    79 // PrintRegister prints a register's name and value to stdout.  It will
    80 // print four registers on a line.  For the first register in a set,
    81 // pass 0 for |start_col|.  For registers in a set, pass the most recent
    82 // return value of PrintRegister.
    83 // The caller is responsible for printing the final newline after a set
    84 // of registers is completely printed, regardless of the number of calls
    85 // to PrintRegister.
    86 static const int kMaxWidth = 80;  // optimize for an 80-column terminal
    87 static int PrintRegister(const char *name, uint32_t value, int start_col) {
    88   char buffer[64];
    89   snprintf(buffer, sizeof(buffer), " %5s = 0x%08x", name, value);
    91   if (start_col + static_cast<ssize_t>(strlen(buffer)) > kMaxWidth) {
    92     start_col = 0;
    93     printf("\n ");
    94   }
    95   fputs(buffer, stdout);
    97   return start_col + strlen(buffer);
    98 }
   100 // PrintRegister64 does the same thing, but for 64-bit registers.
   101 static int PrintRegister64(const char *name, uint64_t value, int start_col) {
   102   char buffer[64];
   103   snprintf(buffer, sizeof(buffer), " %5s = 0x%016" PRIx64 , name, value);
   105   if (start_col + static_cast<ssize_t>(strlen(buffer)) > kMaxWidth) {
   106     start_col = 0;
   107     printf("\n ");
   108   }
   109   fputs(buffer, stdout);
   111   return start_col + strlen(buffer);
   112 }
   114 // StripSeparator takes a string |original| and returns a copy
   115 // of the string with all occurences of |kOutputSeparator| removed.
   116 static string StripSeparator(const string &original) {
   117   string result = original;
   118   string::size_type position = 0;
   119   while ((position = result.find(kOutputSeparator, position)) != string::npos) {
   120     result.erase(position, 1);
   121   }
   122   position = 0;
   123   while ((position = result.find('\n', position)) != string::npos) {
   124     result.erase(position, 1);
   125   }
   126   return result;
   127 }
   129 // PrintStack prints the call stack in |stack| to stdout, in a reasonably
   130 // useful form.  Module, function, and source file names are displayed if
   131 // they are available.  The code offset to the base code address of the
   132 // source line, function, or module is printed, preferring them in that
   133 // order.  If no source line, function, or module information is available,
   134 // an absolute code offset is printed.
   135 //
   136 // If |cpu| is a recognized CPU name, relevant register state for each stack
   137 // frame printed is also output, if available.
   138 static void PrintStack(const CallStack *stack, const string &cpu) {
   139   int frame_count = stack->frames()->size();
   140   if (frame_count == 0) {
   141     printf(" <no frames>\n");
   142   }
   143   for (int frame_index = 0; frame_index < frame_count; ++frame_index) {
   144     const StackFrame *frame = stack->frames()->at(frame_index);
   145     printf("%2d  ", frame_index);
   147     uint64_t instruction_address = frame->ReturnAddress();
   149     if (frame->module) {
   150       printf("%s", PathnameStripper::File(frame->module->code_file()).c_str());
   151       if (!frame->function_name.empty()) {
   152         printf("!%s", frame->function_name.c_str());
   153         if (!frame->source_file_name.empty()) {
   154           string source_file = PathnameStripper::File(frame->source_file_name);
   155           printf(" [%s : %d + 0x%" PRIx64 "]",
   156                  source_file.c_str(),
   157                  frame->source_line,
   158                  instruction_address - frame->source_line_base);
   159         } else {
   160           printf(" + 0x%" PRIx64, instruction_address - frame->function_base);
   161         }
   162       } else {
   163         printf(" + 0x%" PRIx64,
   164                instruction_address - frame->module->base_address());
   165       }
   166     } else {
   167       printf("0x%" PRIx64, instruction_address);
   168     }
   169     printf("\n ");
   171     int sequence = 0;
   172     if (cpu == "x86") {
   173       const StackFrameX86 *frame_x86 =
   174         reinterpret_cast<const StackFrameX86*>(frame);
   176       if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EIP)
   177         sequence = PrintRegister("eip", frame_x86->context.eip, sequence);
   178       if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESP)
   179         sequence = PrintRegister("esp", frame_x86->context.esp, sequence);
   180       if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBP)
   181         sequence = PrintRegister("ebp", frame_x86->context.ebp, sequence);
   182       if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EBX)
   183         sequence = PrintRegister("ebx", frame_x86->context.ebx, sequence);
   184       if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_ESI)
   185         sequence = PrintRegister("esi", frame_x86->context.esi, sequence);
   186       if (frame_x86->context_validity & StackFrameX86::CONTEXT_VALID_EDI)
   187         sequence = PrintRegister("edi", frame_x86->context.edi, sequence);
   188       if (frame_x86->context_validity == StackFrameX86::CONTEXT_VALID_ALL) {
   189         sequence = PrintRegister("eax", frame_x86->context.eax, sequence);
   190         sequence = PrintRegister("ecx", frame_x86->context.ecx, sequence);
   191         sequence = PrintRegister("edx", frame_x86->context.edx, sequence);
   192         sequence = PrintRegister("efl", frame_x86->context.eflags, sequence);
   193       }
   194     } else if (cpu == "ppc") {
   195       const StackFramePPC *frame_ppc =
   196         reinterpret_cast<const StackFramePPC*>(frame);
   198       if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_SRR0)
   199         sequence = PrintRegister("srr0", frame_ppc->context.srr0, sequence);
   200       if (frame_ppc->context_validity & StackFramePPC::CONTEXT_VALID_GPR1)
   201         sequence = PrintRegister("r1", frame_ppc->context.gpr[1], sequence);
   202     } else if (cpu == "amd64") {
   203       const StackFrameAMD64 *frame_amd64 =
   204         reinterpret_cast<const StackFrameAMD64*>(frame);
   206       if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBX)
   207         sequence = PrintRegister64("rbx", frame_amd64->context.rbx, sequence);
   208       if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R12)
   209         sequence = PrintRegister64("r12", frame_amd64->context.r12, sequence);
   210       if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R13)
   211         sequence = PrintRegister64("r13", frame_amd64->context.r13, sequence);
   212       if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R14)
   213         sequence = PrintRegister64("r14", frame_amd64->context.r14, sequence);
   214       if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_R15)
   215         sequence = PrintRegister64("r15", frame_amd64->context.r15, sequence);
   216       if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RIP)
   217         sequence = PrintRegister64("rip", frame_amd64->context.rip, sequence);
   218       if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RSP)
   219         sequence = PrintRegister64("rsp", frame_amd64->context.rsp, sequence);
   220       if (frame_amd64->context_validity & StackFrameAMD64::CONTEXT_VALID_RBP)
   221         sequence = PrintRegister64("rbp", frame_amd64->context.rbp, sequence);
   222     } else if (cpu == "sparc") {
   223       const StackFrameSPARC *frame_sparc =
   224         reinterpret_cast<const StackFrameSPARC*>(frame);
   226       if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_SP)
   227         sequence = PrintRegister("sp", frame_sparc->context.g_r[14], sequence);
   228       if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_FP)
   229         sequence = PrintRegister("fp", frame_sparc->context.g_r[30], sequence);
   230       if (frame_sparc->context_validity & StackFrameSPARC::CONTEXT_VALID_PC)
   231         sequence = PrintRegister("pc", frame_sparc->context.pc, sequence);
   232     } else if (cpu == "arm") {
   233       const StackFrameARM *frame_arm =
   234         reinterpret_cast<const StackFrameARM*>(frame);
   236       // Argument registers (caller-saves), which will likely only be valid
   237       // for the youngest frame.
   238       if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R0)
   239         sequence = PrintRegister("r0", frame_arm->context.iregs[0], sequence);
   240       if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R1)
   241         sequence = PrintRegister("r1", frame_arm->context.iregs[1], sequence);
   242       if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R2)
   243         sequence = PrintRegister("r2", frame_arm->context.iregs[2], sequence);
   244       if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R3)
   245         sequence = PrintRegister("r3", frame_arm->context.iregs[3], sequence);
   247       // General-purpose callee-saves registers.
   248       if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R4)
   249         sequence = PrintRegister("r4", frame_arm->context.iregs[4], sequence);
   250       if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R5)
   251         sequence = PrintRegister("r5", frame_arm->context.iregs[5], sequence);
   252       if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R6)
   253         sequence = PrintRegister("r6", frame_arm->context.iregs[6], sequence);
   254       if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R7)
   255         sequence = PrintRegister("r7", frame_arm->context.iregs[7], sequence);
   256       if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R8)
   257         sequence = PrintRegister("r8", frame_arm->context.iregs[8], sequence);
   258       if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R9)
   259         sequence = PrintRegister("r9", frame_arm->context.iregs[9], sequence);
   260       if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_R10)
   261         sequence = PrintRegister("r10", frame_arm->context.iregs[10], sequence);
   263       // Registers with a dedicated or conventional purpose.
   264       if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_FP)
   265         sequence = PrintRegister("fp", frame_arm->context.iregs[11], sequence);
   266       if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_SP)
   267         sequence = PrintRegister("sp", frame_arm->context.iregs[13], sequence);
   268       if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_LR)
   269         sequence = PrintRegister("lr", frame_arm->context.iregs[14], sequence);
   270       if (frame_arm->context_validity & StackFrameARM::CONTEXT_VALID_PC)
   271         sequence = PrintRegister("pc", frame_arm->context.iregs[15], sequence);
   272     }
   273     printf("\n    Found by: %s\n", frame->trust_description().c_str());
   274   }
   275 }
   277 // PrintStackMachineReadable prints the call stack in |stack| to stdout,
   278 // in the following machine readable pipe-delimited text format:
   279 // thread number|frame number|module|function|source file|line|offset
   280 //
   281 // Module, function, source file, and source line may all be empty
   282 // depending on availability.  The code offset follows the same rules as
   283 // PrintStack above.
   284 static void PrintStackMachineReadable(int thread_num, const CallStack *stack) {
   285   int frame_count = stack->frames()->size();
   286   for (int frame_index = 0; frame_index < frame_count; ++frame_index) {
   287     const StackFrame *frame = stack->frames()->at(frame_index);
   288     printf("%d%c%d%c", thread_num, kOutputSeparator, frame_index,
   289            kOutputSeparator);
   291     uint64_t instruction_address = frame->ReturnAddress();
   293     if (frame->module) {
   294       assert(!frame->module->code_file().empty());
   295       printf("%s", StripSeparator(PathnameStripper::File(
   296                      frame->module->code_file())).c_str());
   297       if (!frame->function_name.empty()) {
   298         printf("%c%s", kOutputSeparator,
   299                StripSeparator(frame->function_name).c_str());
   300         if (!frame->source_file_name.empty()) {
   301           printf("%c%s%c%d%c0x%" PRIx64,
   302                  kOutputSeparator,
   303                  StripSeparator(frame->source_file_name).c_str(),
   304                  kOutputSeparator,
   305                  frame->source_line,
   306                  kOutputSeparator,
   307                  instruction_address - frame->source_line_base);
   308         } else {
   309           printf("%c%c%c0x%" PRIx64,
   310                  kOutputSeparator,  // empty source file
   311                  kOutputSeparator,  // empty source line
   312                  kOutputSeparator,
   313                  instruction_address - frame->function_base);
   314         }
   315       } else {
   316         printf("%c%c%c%c0x%" PRIx64,
   317                kOutputSeparator,  // empty function name
   318                kOutputSeparator,  // empty source file
   319                kOutputSeparator,  // empty source line
   320                kOutputSeparator,
   321                instruction_address - frame->module->base_address());
   322       }
   323     } else {
   324       // the printf before this prints a trailing separator for module name
   325       printf("%c%c%c%c0x%" PRIx64,
   326              kOutputSeparator,  // empty function name
   327              kOutputSeparator,  // empty source file
   328              kOutputSeparator,  // empty source line
   329              kOutputSeparator,
   330              instruction_address);
   331     }
   332     printf("\n");
   333   }
   334 }
   336 // ContainsModule checks whether a given |module| is in the vector
   337 // |modules_without_symbols|.
   338 static bool ContainsModule(
   339     const vector<const CodeModule*> *modules,
   340     const CodeModule *module) {
   341   assert(modules);
   342   assert(module);
   343   vector<const CodeModule*>::const_iterator iter;
   344   for (iter = modules->begin(); iter != modules->end(); ++iter) {
   345     if (module->debug_file().compare((*iter)->debug_file()) == 0 &&
   346         module->debug_identifier().compare((*iter)->debug_identifier()) == 0) {
   347       return true;
   348     }
   349   }
   350   return false;
   351 }
   353 // PrintModule prints a single |module| to stdout.
   354 // |modules_without_symbols| should contain the list of modules that were
   355 // confirmed to be missing their symbols during the stack walk.
   356 static void PrintModule(
   357     const CodeModule *module,
   358     const vector<const CodeModule*> *modules_without_symbols,
   359     uint64_t main_address) {
   360   string missing_symbols;
   361   if (ContainsModule(modules_without_symbols, module)) {
   362     missing_symbols = "  (WARNING: No symbols, " +
   363         PathnameStripper::File(module->debug_file()) + ", " +
   364         module->debug_identifier() + ")";
   365   }
   366   uint64_t base_address = module->base_address();
   367   printf("0x%08" PRIx64 " - 0x%08" PRIx64 "  %s  %s%s%s\n",
   368          base_address, base_address + module->size() - 1,
   369          PathnameStripper::File(module->code_file()).c_str(),
   370          module->version().empty() ? "???" : module->version().c_str(),
   371          main_address != 0 && base_address == main_address ? "  (main)" : "",
   372          missing_symbols.c_str());
   373 }
   375 // PrintModules prints the list of all loaded |modules| to stdout.
   376 // |modules_without_symbols| should contain the list of modules that were
   377 // confirmed to be missing their symbols during the stack walk.
   378 static void PrintModules(
   379     const CodeModules *modules,
   380     const vector<const CodeModule*> *modules_without_symbols) {
   381   if (!modules)
   382     return;
   384   printf("\n");
   385   printf("Loaded modules:\n");
   387   uint64_t main_address = 0;
   388   const CodeModule *main_module = modules->GetMainModule();
   389   if (main_module) {
   390     main_address = main_module->base_address();
   391   }
   393   unsigned int module_count = modules->module_count();
   394   for (unsigned int module_sequence = 0;
   395        module_sequence < module_count;
   396        ++module_sequence) {
   397     const CodeModule *module = modules->GetModuleAtSequence(module_sequence);
   398     PrintModule(module, modules_without_symbols, main_address);
   399   }
   400 }
   402 // PrintModulesMachineReadable outputs a list of loaded modules,
   403 // one per line, in the following machine-readable pipe-delimited
   404 // text format:
   405 // Module|{Module Filename}|{Version}|{Debug Filename}|{Debug Identifier}|
   406 // {Base Address}|{Max Address}|{Main}
   407 static void PrintModulesMachineReadable(const CodeModules *modules) {
   408   if (!modules)
   409     return;
   411   uint64_t main_address = 0;
   412   const CodeModule *main_module = modules->GetMainModule();
   413   if (main_module) {
   414     main_address = main_module->base_address();
   415   }
   417   unsigned int module_count = modules->module_count();
   418   for (unsigned int module_sequence = 0;
   419        module_sequence < module_count;
   420        ++module_sequence) {
   421     const CodeModule *module = modules->GetModuleAtSequence(module_sequence);
   422     uint64_t base_address = module->base_address();
   423     printf("Module%c%s%c%s%c%s%c%s%c0x%08" PRIx64 "%c0x%08" PRIx64 "%c%d\n",
   424            kOutputSeparator,
   425            StripSeparator(PathnameStripper::File(module->code_file())).c_str(),
   426            kOutputSeparator, StripSeparator(module->version()).c_str(),
   427            kOutputSeparator,
   428            StripSeparator(PathnameStripper::File(module->debug_file())).c_str(),
   429            kOutputSeparator,
   430            StripSeparator(module->debug_identifier()).c_str(),
   431            kOutputSeparator, base_address,
   432            kOutputSeparator, base_address + module->size() - 1,
   433            kOutputSeparator,
   434            main_module != NULL && base_address == main_address ? 1 : 0);
   435   }
   436 }
   438 static void PrintProcessState(const ProcessState& process_state) {
   439   // Print OS and CPU information.
   440   string cpu = process_state.system_info()->cpu;
   441   string cpu_info = process_state.system_info()->cpu_info;
   442   printf("Operating system: %s\n", process_state.system_info()->os.c_str());
   443   printf("                  %s\n",
   444          process_state.system_info()->os_version.c_str());
   445   printf("CPU: %s\n", cpu.c_str());
   446   if (!cpu_info.empty()) {
   447     // This field is optional.
   448     printf("     %s\n", cpu_info.c_str());
   449   }
   450   printf("     %d CPU%s\n",
   451          process_state.system_info()->cpu_count,
   452          process_state.system_info()->cpu_count != 1 ? "s" : "");
   453   printf("\n");
   455   // Print crash information.
   456   if (process_state.crashed()) {
   457     printf("Crash reason:  %s\n", process_state.crash_reason().c_str());
   458     printf("Crash address: 0x%" PRIx64 "\n", process_state.crash_address());
   459   } else {
   460     printf("No crash\n");
   461   }
   463   string assertion = process_state.assertion();
   464   if (!assertion.empty()) {
   465     printf("Assertion: %s\n", assertion.c_str());
   466   }
   468   // If the thread that requested the dump is known, print it first.
   469   int requesting_thread = process_state.requesting_thread();
   470   if (requesting_thread != -1) {
   471     printf("\n");
   472     printf("Thread %d (%s)\n",
   473           requesting_thread,
   474           process_state.crashed() ? "crashed" :
   475                                     "requested dump, did not crash");
   476     PrintStack(process_state.threads()->at(requesting_thread), cpu);
   477   }
   479   // Print all of the threads in the dump.
   480   int thread_count = process_state.threads()->size();
   481   for (int thread_index = 0; thread_index < thread_count; ++thread_index) {
   482     if (thread_index != requesting_thread) {
   483       // Don't print the crash thread again, it was already printed.
   484       printf("\n");
   485       printf("Thread %d\n", thread_index);
   486       PrintStack(process_state.threads()->at(thread_index), cpu);
   487     }
   488   }
   490   PrintModules(process_state.modules(),
   491                process_state.modules_without_symbols());
   492 }
   494 static void PrintProcessStateMachineReadable(const ProcessState& process_state)
   495 {
   496   // Print OS and CPU information.
   497   // OS|{OS Name}|{OS Version}
   498   // CPU|{CPU Name}|{CPU Info}|{Number of CPUs}
   499   printf("OS%c%s%c%s\n", kOutputSeparator,
   500          StripSeparator(process_state.system_info()->os).c_str(),
   501          kOutputSeparator,
   502          StripSeparator(process_state.system_info()->os_version).c_str());
   503   printf("CPU%c%s%c%s%c%d\n", kOutputSeparator,
   504          StripSeparator(process_state.system_info()->cpu).c_str(),
   505          kOutputSeparator,
   506          // this may be empty
   507          StripSeparator(process_state.system_info()->cpu_info).c_str(),
   508          kOutputSeparator,
   509          process_state.system_info()->cpu_count);
   511   int requesting_thread = process_state.requesting_thread();
   513   // Print crash information.
   514   // Crash|{Crash Reason}|{Crash Address}|{Crashed Thread}
   515   printf("Crash%c", kOutputSeparator);
   516   if (process_state.crashed()) {
   517     printf("%s%c0x%" PRIx64 "%c",
   518            StripSeparator(process_state.crash_reason()).c_str(),
   519            kOutputSeparator, process_state.crash_address(), kOutputSeparator);
   520   } else {
   521     // print assertion info, if available, in place of crash reason,
   522     // instead of the unhelpful "No crash"
   523     string assertion = process_state.assertion();
   524     if (!assertion.empty()) {
   525       printf("%s%c%c", StripSeparator(assertion).c_str(),
   526              kOutputSeparator, kOutputSeparator);
   527     } else {
   528       printf("No crash%c%c", kOutputSeparator, kOutputSeparator);
   529     }
   530   }
   532   if (requesting_thread != -1) {
   533     printf("%d\n", requesting_thread);
   534   } else {
   535     printf("\n");
   536   }
   538   PrintModulesMachineReadable(process_state.modules());
   540   // blank line to indicate start of threads
   541   printf("\n");
   543   // If the thread that requested the dump is known, print it first.
   544   if (requesting_thread != -1) {
   545     PrintStackMachineReadable(requesting_thread,
   546                               process_state.threads()->at(requesting_thread));
   547   }
   549   // Print all of the threads in the dump.
   550   int thread_count = process_state.threads()->size();
   551   for (int thread_index = 0; thread_index < thread_count; ++thread_index) {
   552     if (thread_index != requesting_thread) {
   553       // Don't print the crash thread again, it was already printed.
   554       PrintStackMachineReadable(thread_index,
   555                                 process_state.threads()->at(thread_index));
   556     }
   557   }
   558 }
   560 // Processes |minidump_file| using MinidumpProcessor.  |symbol_path|, if
   561 // non-empty, is the base directory of a symbol storage area, laid out in
   562 // the format required by SimpleSymbolSupplier.  If such a storage area
   563 // is specified, it is made available for use by the MinidumpProcessor.
   564 //
   565 // Returns the value of MinidumpProcessor::Process.  If processing succeeds,
   566 // prints identifying OS and CPU information from the minidump, crash
   567 // information if the minidump was produced as a result of a crash, and
   568 // call stacks for each thread contained in the minidump.  All information
   569 // is printed to stdout.
   570 static bool PrintMinidumpProcess(const string &minidump_file,
   571                                  const vector<string> &symbol_paths,
   572                                  bool machine_readable) {
   573   scoped_ptr<SimpleSymbolSupplier> symbol_supplier;
   574   if (!symbol_paths.empty()) {
   575     // TODO(mmentovai): check existence of symbol_path if specified?
   576     symbol_supplier.reset(new SimpleSymbolSupplier(symbol_paths));
   577   }
   579   BasicSourceLineResolver resolver;
   580   MinidumpProcessor minidump_processor(symbol_supplier.get(), &resolver);
   582   // Process the minidump.
   583   ProcessState process_state;
   584   if (minidump_processor.Process(minidump_file, &process_state) !=
   585       google_breakpad::PROCESS_OK) {
   586     BPLOG(ERROR) << "MinidumpProcessor::Process failed";
   587     return false;
   588   }
   590   if (machine_readable) {
   591     PrintProcessStateMachineReadable(process_state);
   592   } else {
   593     PrintProcessState(process_state);
   594   }
   596   return true;
   597 }
   599 }  // namespace
   601 static void usage(const char *program_name) {
   602   fprintf(stderr, "usage: %s [-m] <minidump-file> [symbol-path ...]\n"
   603           "    -m : Output in machine-readable format\n",
   604           program_name);
   605 }
   607 int main(int argc, char **argv) {
   608   BPLOG_INIT(&argc, &argv);
   610   if (argc < 2) {
   611     usage(argv[0]);
   612     return 1;
   613   }
   615   const char *minidump_file;
   616   bool machine_readable;
   617   int symbol_path_arg;
   619   if (strcmp(argv[1], "-m") == 0) {
   620     if (argc < 3) {
   621       usage(argv[0]);
   622       return 1;
   623     }
   625     machine_readable = true;
   626     minidump_file = argv[2];
   627     symbol_path_arg = 3;
   628   } else {
   629     machine_readable = false;
   630     minidump_file = argv[1];
   631     symbol_path_arg = 2;
   632   }
   634   // extra arguments are symbol paths
   635   std::vector<string> symbol_paths;
   636   if (argc > symbol_path_arg) {
   637     for (int argi = symbol_path_arg; argi < argc; ++argi)
   638       symbol_paths.push_back(argv[argi]);
   639   }
   641   return PrintMinidumpProcess(minidump_file,
   642                               symbol_paths,
   643                               machine_readable) ? 0 : 1;
   644 }

mercurial