PageRenderTime 82ms CodeModel.GetById 13ms app.highlight 61ms RepoModel.GetById 1ms app.codeStats 0ms

/thirdparty/breakpad/processor/minidump_processor.cc

http://github.com/tomahawk-player/tomahawk
C++ | 1133 lines | 955 code | 90 blank | 88 comment | 72 complexity | 23f12ecbae4560a20dc6c831a85340be MD5 | raw file
   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#include "google_breakpad/processor/minidump_processor.h"
  31
  32#include <assert.h>
  33#include <stdio.h>
  34
  35#include "google_breakpad/processor/call_stack.h"
  36#include "google_breakpad/processor/minidump.h"
  37#include "google_breakpad/processor/process_state.h"
  38#include "google_breakpad/processor/exploitability.h"
  39#include "processor/logging.h"
  40#include "processor/scoped_ptr.h"
  41#include "processor/stackwalker_x86.h"
  42
  43namespace google_breakpad {
  44
  45MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier,
  46                                     SourceLineResolverInterface *resolver)
  47    : supplier_(supplier), resolver_(resolver),
  48      enable_exploitability_(false) {
  49}
  50
  51MinidumpProcessor::MinidumpProcessor(SymbolSupplier *supplier,
  52                                     SourceLineResolverInterface *resolver,
  53                                     bool enable_exploitability)
  54    : supplier_(supplier), resolver_(resolver),
  55      enable_exploitability_(enable_exploitability) {
  56}
  57
  58MinidumpProcessor::~MinidumpProcessor() {
  59}
  60
  61ProcessResult MinidumpProcessor::Process(
  62    Minidump *dump, ProcessState *process_state) {
  63  assert(dump);
  64  assert(process_state);
  65
  66  process_state->Clear();
  67
  68  const MDRawHeader *header = dump->header();
  69  if (!header) {
  70    BPLOG(ERROR) << "Minidump " << dump->path() << " has no header";
  71    return PROCESS_ERROR_NO_MINIDUMP_HEADER;
  72  }
  73  process_state->time_date_stamp_ = header->time_date_stamp;
  74
  75  bool has_cpu_info = GetCPUInfo(dump, &process_state->system_info_);
  76  bool has_os_info = GetOSInfo(dump, &process_state->system_info_);
  77
  78  u_int32_t dump_thread_id = 0;
  79  bool has_dump_thread = false;
  80  u_int32_t requesting_thread_id = 0;
  81  bool has_requesting_thread = false;
  82
  83  MinidumpBreakpadInfo *breakpad_info = dump->GetBreakpadInfo();
  84  if (breakpad_info) {
  85    has_dump_thread = breakpad_info->GetDumpThreadID(&dump_thread_id);
  86    has_requesting_thread =
  87        breakpad_info->GetRequestingThreadID(&requesting_thread_id);
  88  }
  89
  90  MinidumpException *exception = dump->GetException();
  91  if (exception) {
  92    process_state->crashed_ = true;
  93    has_requesting_thread = exception->GetThreadID(&requesting_thread_id);
  94
  95    process_state->crash_reason_ = GetCrashReason(
  96        dump, &process_state->crash_address_);
  97  }
  98
  99  // This will just return an empty string if it doesn't exist.
 100  process_state->assertion_ = GetAssertion(dump);
 101
 102  MinidumpModuleList *module_list = dump->GetModuleList();
 103
 104  // Put a copy of the module list into ProcessState object.  This is not
 105  // necessarily a MinidumpModuleList, but it adheres to the CodeModules
 106  // interface, which is all that ProcessState needs to expose.
 107  if (module_list)
 108    process_state->modules_ = module_list->Copy();
 109
 110  MinidumpThreadList *threads = dump->GetThreadList();
 111  if (!threads) {
 112    BPLOG(ERROR) << "Minidump " << dump->path() << " has no thread list";
 113    return PROCESS_ERROR_NO_THREAD_LIST;
 114  }
 115
 116  BPLOG(INFO) << "Minidump " << dump->path() << " has " <<
 117      (has_cpu_info           ? "" : "no ") << "CPU info, " <<
 118      (has_os_info            ? "" : "no ") << "OS info, " <<
 119      (breakpad_info != NULL  ? "" : "no ") << "Breakpad info, " <<
 120      (exception != NULL      ? "" : "no ") << "exception, " <<
 121      (module_list != NULL    ? "" : "no ") << "module list, " <<
 122      (threads != NULL        ? "" : "no ") << "thread list, " <<
 123      (has_dump_thread        ? "" : "no ") << "dump thread, and " <<
 124      (has_requesting_thread  ? "" : "no ") << "requesting thread";
 125
 126  bool interrupted = false;
 127  bool found_requesting_thread = false;
 128  unsigned int thread_count = threads->thread_count();
 129  for (unsigned int thread_index = 0;
 130       thread_index < thread_count;
 131       ++thread_index) {
 132    char thread_string_buffer[64];
 133    snprintf(thread_string_buffer, sizeof(thread_string_buffer), "%d/%d",
 134             thread_index, thread_count);
 135    string thread_string = dump->path() + ":" + thread_string_buffer;
 136
 137    MinidumpThread *thread = threads->GetThreadAtIndex(thread_index);
 138    if (!thread) {
 139      BPLOG(ERROR) << "Could not get thread for " << thread_string;
 140      return PROCESS_ERROR_GETTING_THREAD;
 141    }
 142
 143    u_int32_t thread_id;
 144    if (!thread->GetThreadID(&thread_id)) {
 145      BPLOG(ERROR) << "Could not get thread ID for " << thread_string;
 146      return PROCESS_ERROR_GETTING_THREAD_ID;
 147    }
 148
 149    thread_string += " id " + HexString(thread_id);
 150    BPLOG(INFO) << "Looking at thread " << thread_string;
 151
 152    // If this thread is the thread that produced the minidump, don't process
 153    // it.  Because of the problems associated with a thread producing a
 154    // dump of itself (when both its context and its stack are in flux),
 155    // processing that stack wouldn't provide much useful data.
 156    if (has_dump_thread && thread_id == dump_thread_id) {
 157      continue;
 158    }
 159
 160    MinidumpContext *context = thread->GetContext();
 161
 162    if (has_requesting_thread && thread_id == requesting_thread_id) {
 163      if (found_requesting_thread) {
 164        // There can't be more than one requesting thread.
 165        BPLOG(ERROR) << "Duplicate requesting thread: " << thread_string;
 166        return PROCESS_ERROR_DUPLICATE_REQUESTING_THREADS;
 167      }
 168
 169      // Use processed_state->threads_.size() instead of thread_index.
 170      // thread_index points to the thread index in the minidump, which
 171      // might be greater than the thread index in the threads vector if
 172      // any of the minidump's threads are skipped and not placed into the
 173      // processed threads vector.  The thread vector's current size will
 174      // be the index of the current thread when it's pushed into the
 175      // vector.
 176      process_state->requesting_thread_ = process_state->threads_.size();
 177
 178      found_requesting_thread = true;
 179
 180      if (process_state->crashed_) {
 181        // Use the exception record's context for the crashed thread, instead
 182        // of the thread's own context.  For the crashed thread, the thread's
 183        // own context is the state inside the exception handler.  Using it
 184        // would not result in the expected stack trace from the time of the
 185        // crash. If the exception context is invalid, however, we fall back
 186        // on the thread context.
 187        MinidumpContext *ctx = exception->GetContext();
 188        context = ctx ? ctx : thread->GetContext();
 189      }
 190    }
 191
 192    MinidumpMemoryRegion *thread_memory = thread->GetMemory();
 193    if (!thread_memory) {
 194      BPLOG(ERROR) << "No memory region for " << thread_string;
 195      return PROCESS_ERROR_NO_MEMORY_FOR_THREAD;
 196    }
 197
 198    // Use process_state->modules_ instead of module_list, because the
 199    // |modules| argument will be used to populate the |module| fields in
 200    // the returned StackFrame objects, which will be placed into the
 201    // returned ProcessState object.  module_list's lifetime is only as
 202    // long as the Minidump object: it will be deleted when this function
 203    // returns.  process_state->modules_ is owned by the ProcessState object
 204    // (just like the StackFrame objects), and is much more suitable for this
 205    // task.
 206    scoped_ptr<Stackwalker> stackwalker(
 207        Stackwalker::StackwalkerForCPU(process_state->system_info(),
 208                                       context,
 209                                       thread_memory,
 210                                       process_state->modules_,
 211                                       supplier_,
 212                                       resolver_));
 213    if (!stackwalker.get()) {
 214      BPLOG(ERROR) << "No stackwalker for " << thread_string;
 215      return PROCESS_ERROR_NO_STACKWALKER_FOR_THREAD;
 216    }
 217
 218    scoped_ptr<CallStack> stack(new CallStack());
 219    if (!stackwalker->Walk(stack.get())) {
 220      BPLOG(INFO) << "Stackwalker interrupt (missing symbols?) at " <<
 221          thread_string;
 222      interrupted = true;
 223    }
 224    process_state->threads_.push_back(stack.release());
 225    process_state->thread_memory_regions_.push_back(thread_memory);
 226  }
 227
 228  if (interrupted) {
 229    BPLOG(INFO) << "Processing interrupted for " << dump->path();
 230    return PROCESS_SYMBOL_SUPPLIER_INTERRUPTED;
 231  }
 232
 233  // If a requesting thread was indicated, it must be present.
 234  if (has_requesting_thread && !found_requesting_thread) {
 235    // Don't mark as an error, but invalidate the requesting thread
 236    BPLOG(ERROR) << "Minidump indicated requesting thread " <<
 237        HexString(requesting_thread_id) << ", not found in " <<
 238        dump->path();
 239    process_state->requesting_thread_ = -1;
 240  }
 241
 242  // Exploitability defaults to EXPLOITABILITY_NOT_ANALYZED
 243  process_state->exploitability_ = EXPLOITABILITY_NOT_ANALYZED;
 244
 245  // If an exploitability run was requested we perform the platform specific
 246  // rating.
 247  if (enable_exploitability_) {
 248    scoped_ptr<Exploitability> exploitability(
 249        Exploitability::ExploitabilityForPlatform(dump, process_state));
 250    // The engine will be null if the platform is not supported
 251    if (exploitability != NULL) {
 252      process_state->exploitability_ = exploitability->CheckExploitability();
 253    } else {
 254      process_state->exploitability_ = EXPLOITABILITY_ERR_NOENGINE;
 255    }
 256  }
 257
 258  BPLOG(INFO) << "Processed " << dump->path();
 259  return PROCESS_OK;
 260}
 261
 262ProcessResult MinidumpProcessor::Process(
 263    const string &minidump_file, ProcessState *process_state) {
 264  BPLOG(INFO) << "Processing minidump in file " << minidump_file;
 265
 266  Minidump dump(minidump_file);
 267  if (!dump.Read()) {
 268     BPLOG(ERROR) << "Minidump " << dump.path() << " could not be read";
 269     return PROCESS_ERROR_MINIDUMP_NOT_FOUND;
 270  }
 271
 272  return Process(&dump, process_state);
 273}
 274
 275// Returns the MDRawSystemInfo from a minidump, or NULL if system info is
 276// not available from the minidump.  If system_info is non-NULL, it is used
 277// to pass back the MinidumpSystemInfo object.
 278static const MDRawSystemInfo* GetSystemInfo(Minidump *dump,
 279                                            MinidumpSystemInfo **system_info) {
 280  MinidumpSystemInfo *minidump_system_info = dump->GetSystemInfo();
 281  if (!minidump_system_info)
 282    return NULL;
 283
 284  if (system_info)
 285    *system_info = minidump_system_info;
 286
 287  return minidump_system_info->system_info();
 288}
 289
 290// static
 291bool MinidumpProcessor::GetCPUInfo(Minidump *dump, SystemInfo *info) {
 292  assert(dump);
 293  assert(info);
 294
 295  info->cpu.clear();
 296  info->cpu_info.clear();
 297
 298  MinidumpSystemInfo *system_info;
 299  const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info);
 300  if (!raw_system_info)
 301    return false;
 302
 303  switch (raw_system_info->processor_architecture) {
 304    case MD_CPU_ARCHITECTURE_X86:
 305    case MD_CPU_ARCHITECTURE_AMD64: {
 306      if (raw_system_info->processor_architecture ==
 307          MD_CPU_ARCHITECTURE_X86)
 308        info->cpu = "x86";
 309      else
 310        info->cpu = "amd64";
 311
 312      const string *cpu_vendor = system_info->GetCPUVendor();
 313      if (cpu_vendor) {
 314        info->cpu_info = *cpu_vendor;
 315        info->cpu_info.append(" ");
 316      }
 317
 318      char x86_info[36];
 319      snprintf(x86_info, sizeof(x86_info), "family %u model %u stepping %u",
 320               raw_system_info->processor_level,
 321               raw_system_info->processor_revision >> 8,
 322               raw_system_info->processor_revision & 0xff);
 323      info->cpu_info.append(x86_info);
 324      break;
 325    }
 326
 327    case MD_CPU_ARCHITECTURE_PPC: {
 328      info->cpu = "ppc";
 329      break;
 330    }
 331
 332    case MD_CPU_ARCHITECTURE_SPARC: {
 333      info->cpu = "sparc";
 334      break;
 335    }
 336
 337    case MD_CPU_ARCHITECTURE_ARM: {
 338      info->cpu = "arm";
 339      break;
 340    }
 341
 342    default: {
 343      // Assign the numeric architecture ID into the CPU string.
 344      char cpu_string[7];
 345      snprintf(cpu_string, sizeof(cpu_string), "0x%04x",
 346               raw_system_info->processor_architecture);
 347      info->cpu = cpu_string;
 348      break;
 349    }
 350  }
 351
 352  info->cpu_count = raw_system_info->number_of_processors;
 353
 354  return true;
 355}
 356
 357// static
 358bool MinidumpProcessor::GetOSInfo(Minidump *dump, SystemInfo *info) {
 359  assert(dump);
 360  assert(info);
 361
 362  info->os.clear();
 363  info->os_short.clear();
 364  info->os_version.clear();
 365
 366  MinidumpSystemInfo *system_info;
 367  const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, &system_info);
 368  if (!raw_system_info)
 369    return false;
 370
 371  info->os_short = system_info->GetOS();
 372
 373  switch (raw_system_info->platform_id) {
 374    case MD_OS_WIN32_NT: {
 375      info->os = "Windows NT";
 376      break;
 377    }
 378
 379    case MD_OS_WIN32_WINDOWS: {
 380      info->os = "Windows";
 381      break;
 382    }
 383
 384    case MD_OS_MAC_OS_X: {
 385      info->os = "Mac OS X";
 386      break;
 387    }
 388
 389    case MD_OS_IOS: {
 390      info->os = "iOS";
 391      break;
 392    }
 393
 394    case MD_OS_LINUX: {
 395      info->os = "Linux";
 396      break;
 397    }
 398
 399    case MD_OS_SOLARIS: {
 400      info->os = "Solaris";
 401      break;
 402    }
 403
 404    default: {
 405      // Assign the numeric platform ID into the OS string.
 406      char os_string[11];
 407      snprintf(os_string, sizeof(os_string), "0x%08x",
 408               raw_system_info->platform_id);
 409      info->os = os_string;
 410      break;
 411    }
 412  }
 413
 414  char os_version_string[33];
 415  snprintf(os_version_string, sizeof(os_version_string), "%u.%u.%u",
 416           raw_system_info->major_version,
 417           raw_system_info->minor_version,
 418           raw_system_info->build_number);
 419  info->os_version = os_version_string;
 420
 421  const string *csd_version = system_info->GetCSDVersion();
 422  if (csd_version) {
 423    info->os_version.append(" ");
 424    info->os_version.append(*csd_version);
 425  }
 426
 427  return true;
 428}
 429
 430// static
 431string MinidumpProcessor::GetCrashReason(Minidump *dump, u_int64_t *address) {
 432  MinidumpException *exception = dump->GetException();
 433  if (!exception)
 434    return "";
 435
 436  const MDRawExceptionStream *raw_exception = exception->exception();
 437  if (!raw_exception)
 438    return "";
 439
 440  if (address)
 441    *address = raw_exception->exception_record.exception_address;
 442
 443  // The reason value is OS-specific and possibly CPU-specific.  Set up
 444  // sensible numeric defaults for the reason string in case we can't
 445  // map the codes to a string (because there's no system info, or because
 446  // it's an unrecognized platform, or because it's an unrecognized code.)
 447  char reason_string[24];
 448  u_int32_t exception_code = raw_exception->exception_record.exception_code;
 449  u_int32_t exception_flags = raw_exception->exception_record.exception_flags;
 450  snprintf(reason_string, sizeof(reason_string), "0x%08x / 0x%08x",
 451           exception_code, exception_flags);
 452  string reason = reason_string;
 453
 454  const MDRawSystemInfo *raw_system_info = GetSystemInfo(dump, NULL);
 455  if (!raw_system_info)
 456    return reason;
 457
 458  switch (raw_system_info->platform_id) {
 459    case MD_OS_MAC_OS_X:
 460    case MD_OS_IOS: {
 461      char flags_string[11];
 462      snprintf(flags_string, sizeof(flags_string), "0x%08x", exception_flags);
 463      switch (exception_code) {
 464        case MD_EXCEPTION_MAC_BAD_ACCESS:
 465          reason = "EXC_BAD_ACCESS / ";
 466          switch (exception_flags) {
 467            case MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS:
 468              reason.append("KERN_INVALID_ADDRESS");
 469              break;
 470            case MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE:
 471              reason.append("KERN_PROTECTION_FAILURE");
 472              break;
 473            case MD_EXCEPTION_CODE_MAC_NO_ACCESS:
 474              reason.append("KERN_NO_ACCESS");
 475              break;
 476            case MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE:
 477              reason.append("KERN_MEMORY_FAILURE");
 478              break;
 479            case MD_EXCEPTION_CODE_MAC_MEMORY_ERROR:
 480              reason.append("KERN_MEMORY_ERROR");
 481              break;
 482            // These are ppc only but shouldn't be a problem as they're
 483            // unused on x86
 484            case MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ:
 485              reason.append("EXC_PPC_VM_PROT_READ");
 486              break;
 487            case MD_EXCEPTION_CODE_MAC_PPC_BADSPACE:
 488              reason.append("EXC_PPC_BADSPACE");
 489              break;
 490            case MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED:
 491              reason.append("EXC_PPC_UNALIGNED");
 492              break;
 493            default:
 494              reason.append(flags_string);
 495              BPLOG(INFO) << "Unknown exception reason " << reason;
 496              break;
 497          }
 498          break;
 499        case MD_EXCEPTION_MAC_BAD_INSTRUCTION:
 500          reason = "EXC_BAD_INSTRUCTION / ";
 501          switch (raw_system_info->processor_architecture) {
 502            case MD_CPU_ARCHITECTURE_PPC: {
 503              switch (exception_flags) {
 504                case MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL:
 505                  reason.append("EXC_PPC_INVALID_SYSCALL");
 506                  break;
 507                case MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION:
 508                  reason.append("EXC_PPC_UNIPL_INST");
 509                  break;
 510                case MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION:
 511                  reason.append("EXC_PPC_PRIVINST");
 512                  break;
 513                case MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER:
 514                  reason.append("EXC_PPC_PRIVREG");
 515                  break;
 516                case MD_EXCEPTION_CODE_MAC_PPC_TRACE:
 517                  reason.append("EXC_PPC_TRACE");
 518                  break;
 519                case MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR:
 520                  reason.append("EXC_PPC_PERFMON");
 521                  break;
 522                default:
 523                  reason.append(flags_string);
 524                  BPLOG(INFO) << "Unknown exception reason " << reason;
 525                  break;
 526              }
 527              break;
 528            }
 529            case MD_CPU_ARCHITECTURE_X86: {
 530              switch (exception_flags) {
 531                case MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION:
 532                  reason.append("EXC_I386_INVOP");
 533                  break;
 534                case MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT:
 535                  reason.append("EXC_INVTSSFLT");
 536                  break;
 537                case MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT:
 538                  reason.append("EXC_SEGNPFLT");
 539                  break;
 540                case MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT:
 541                  reason.append("EXC_STKFLT");
 542                  break;
 543                case MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT:
 544                  reason.append("EXC_GPFLT");
 545                  break;
 546                case MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT:
 547                  reason.append("EXC_ALIGNFLT");
 548                  break;
 549                default:
 550                  reason.append(flags_string);
 551                  BPLOG(INFO) << "Unknown exception reason " << reason;
 552                  break;
 553              }
 554              break;
 555            }
 556            default:
 557              reason.append(flags_string);
 558              BPLOG(INFO) << "Unknown exception reason " << reason;
 559              break;
 560          }
 561          break;
 562        case MD_EXCEPTION_MAC_ARITHMETIC:
 563          reason = "EXC_ARITHMETIC / ";
 564          switch (raw_system_info->processor_architecture) {
 565            case MD_CPU_ARCHITECTURE_PPC: {
 566              switch (exception_flags) {
 567                case MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW:
 568                  reason.append("EXC_PPC_OVERFLOW");
 569                  break;
 570                case MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE:
 571                  reason.append("EXC_PPC_ZERO_DIVIDE");
 572                  break;
 573                case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT:
 574                  reason.append("EXC_FLT_INEXACT");
 575                  break;
 576                case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE:
 577                  reason.append("EXC_PPC_FLT_ZERO_DIVIDE");
 578                  break;
 579                case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW:
 580                  reason.append("EXC_PPC_FLT_UNDERFLOW");
 581                  break;
 582                case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW:
 583                  reason.append("EXC_PPC_FLT_OVERFLOW");
 584                  break;
 585                case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER:
 586                  reason.append("EXC_PPC_FLT_NOT_A_NUMBER");
 587                  break;
 588                case MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION:
 589                  reason.append("EXC_PPC_NOEMULATION");
 590                  break;
 591                case MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST:
 592                  reason.append("EXC_PPC_ALTIVECASSIST");
 593                default:
 594                  reason.append(flags_string);
 595                  BPLOG(INFO) << "Unknown exception reason " << reason;
 596                  break;
 597              }
 598              break;
 599            }
 600            case MD_CPU_ARCHITECTURE_X86: {
 601              switch (exception_flags) {
 602                case MD_EXCEPTION_CODE_MAC_X86_DIV:
 603                  reason.append("EXC_I386_DIV");
 604                  break;
 605                case MD_EXCEPTION_CODE_MAC_X86_INTO:
 606                  reason.append("EXC_I386_INTO");
 607                  break;
 608                case MD_EXCEPTION_CODE_MAC_X86_NOEXT:
 609                  reason.append("EXC_I386_NOEXT");
 610                  break;
 611                case MD_EXCEPTION_CODE_MAC_X86_EXTOVR:
 612                  reason.append("EXC_I386_EXTOVR");
 613                  break;
 614                case MD_EXCEPTION_CODE_MAC_X86_EXTERR:
 615                  reason.append("EXC_I386_EXTERR");
 616                  break;
 617                case MD_EXCEPTION_CODE_MAC_X86_EMERR:
 618                  reason.append("EXC_I386_EMERR");
 619                  break;
 620                case MD_EXCEPTION_CODE_MAC_X86_BOUND:
 621                  reason.append("EXC_I386_BOUND");
 622                  break;
 623                case MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR:
 624                  reason.append("EXC_I386_SSEEXTERR");
 625                  break;
 626                default:
 627                  reason.append(flags_string);
 628                  BPLOG(INFO) << "Unknown exception reason " << reason;
 629                  break;
 630              }
 631              break;
 632            }
 633            default:
 634              reason.append(flags_string);
 635              BPLOG(INFO) << "Unknown exception reason " << reason;
 636              break;
 637          }
 638          break;
 639        case MD_EXCEPTION_MAC_EMULATION:
 640          reason = "EXC_EMULATION / ";
 641          reason.append(flags_string);
 642          break;
 643        case MD_EXCEPTION_MAC_SOFTWARE:
 644          reason = "EXC_SOFTWARE / ";
 645          switch (exception_flags) {
 646            case MD_EXCEPTION_CODE_MAC_ABORT:
 647              reason.append("SIGABRT");
 648              break;
 649            case MD_EXCEPTION_CODE_MAC_NS_EXCEPTION:
 650              reason.append("UNCAUGHT_NS_EXCEPTION");
 651              break;
 652            // These are ppc only but shouldn't be a problem as they're
 653            // unused on x86
 654            case MD_EXCEPTION_CODE_MAC_PPC_TRAP:
 655              reason.append("EXC_PPC_TRAP");
 656              break;
 657            case MD_EXCEPTION_CODE_MAC_PPC_MIGRATE:
 658              reason.append("EXC_PPC_MIGRATE");
 659              break;
 660            default:
 661              reason.append(flags_string);
 662              BPLOG(INFO) << "Unknown exception reason " << reason;
 663              break;
 664          }
 665          break;
 666        case MD_EXCEPTION_MAC_BREAKPOINT:
 667          reason = "EXC_BREAKPOINT / ";
 668          switch (raw_system_info->processor_architecture) {
 669            case MD_CPU_ARCHITECTURE_PPC: {
 670              switch (exception_flags) {
 671                case MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT:
 672                  reason.append("EXC_PPC_BREAKPOINT");
 673                  break;
 674                default:
 675                  reason.append(flags_string);
 676                  BPLOG(INFO) << "Unknown exception reason " << reason;
 677                  break;
 678              }
 679              break;
 680            }
 681            case MD_CPU_ARCHITECTURE_X86: {
 682              switch (exception_flags) {
 683                case MD_EXCEPTION_CODE_MAC_X86_SGL:
 684                  reason.append("EXC_I386_SGL");
 685                  break;
 686                case MD_EXCEPTION_CODE_MAC_X86_BPT:
 687                  reason.append("EXC_I386_BPT");
 688                  break;
 689                default:
 690                  reason.append(flags_string);
 691                  BPLOG(INFO) << "Unknown exception reason " << reason;
 692                  break;
 693              }
 694              break;
 695            }
 696            default:
 697              reason.append(flags_string);
 698              BPLOG(INFO) << "Unknown exception reason " << reason;
 699              break;
 700          }
 701          break;
 702        case MD_EXCEPTION_MAC_SYSCALL:
 703          reason = "EXC_SYSCALL / ";
 704          reason.append(flags_string);
 705          break;
 706        case MD_EXCEPTION_MAC_MACH_SYSCALL:
 707          reason = "EXC_MACH_SYSCALL / ";
 708          reason.append(flags_string);
 709          break;
 710        case MD_EXCEPTION_MAC_RPC_ALERT:
 711          reason = "EXC_RPC_ALERT / ";
 712          reason.append(flags_string);
 713          break;
 714      }
 715      break;
 716    }
 717
 718    case MD_OS_WIN32_NT:
 719    case MD_OS_WIN32_WINDOWS: {
 720      switch (exception_code) {
 721        case MD_EXCEPTION_CODE_WIN_CONTROL_C:
 722          reason = "DBG_CONTROL_C";
 723          break;
 724        case MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION:
 725          reason = "EXCEPTION_GUARD_PAGE";
 726          break;
 727        case MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT:
 728          reason = "EXCEPTION_DATATYPE_MISALIGNMENT";
 729          break;
 730        case MD_EXCEPTION_CODE_WIN_BREAKPOINT:
 731          reason = "EXCEPTION_BREAKPOINT";
 732          break;
 733        case MD_EXCEPTION_CODE_WIN_SINGLE_STEP:
 734          reason = "EXCEPTION_SINGLE_STEP";
 735          break;
 736        case MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION:
 737          // For EXCEPTION_ACCESS_VIOLATION, Windows puts the address that
 738          // caused the fault in exception_information[1].
 739          // exception_information[0] is 0 if the violation was caused by
 740          // an attempt to read data and 1 if it was an attempt to write
 741          // data.
 742          // This information is useful in addition to the code address, which
 743          // will be present in the crash thread's instruction field anyway.
 744          if (raw_exception->exception_record.number_parameters >= 1) {
 745            MDAccessViolationTypeWin av_type =
 746                static_cast<MDAccessViolationTypeWin>
 747                (raw_exception->exception_record.exception_information[0]);
 748            switch (av_type) {
 749              case MD_ACCESS_VIOLATION_WIN_READ:
 750                reason = "EXCEPTION_ACCESS_VIOLATION_READ";
 751                break;
 752              case MD_ACCESS_VIOLATION_WIN_WRITE:
 753                reason = "EXCEPTION_ACCESS_VIOLATION_WRITE";
 754                break;
 755              case MD_ACCESS_VIOLATION_WIN_EXEC:
 756                reason = "EXCEPTION_ACCESS_VIOLATION_EXEC";
 757                break;
 758              default:
 759                reason = "EXCEPTION_ACCESS_VIOLATION";
 760                break;
 761            }
 762          } else {
 763            reason = "EXCEPTION_ACCESS_VIOLATION";
 764          }
 765          if (address &&
 766              raw_exception->exception_record.number_parameters >= 2) {
 767            *address =
 768                raw_exception->exception_record.exception_information[1];
 769          }
 770          break;
 771        case MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR:
 772          reason = "EXCEPTION_IN_PAGE_ERROR";
 773          break;
 774        case MD_EXCEPTION_CODE_WIN_INVALID_HANDLE:
 775          reason = "EXCEPTION_INVALID_HANDLE";
 776          break;
 777        case MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION:
 778          reason = "EXCEPTION_ILLEGAL_INSTRUCTION";
 779          break;
 780        case MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION:
 781          reason = "EXCEPTION_NONCONTINUABLE_EXCEPTION";
 782          break;
 783        case MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION:
 784          reason = "EXCEPTION_INVALID_DISPOSITION";
 785          break;
 786        case MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED:
 787          reason = "EXCEPTION_BOUNDS_EXCEEDED";
 788          break;
 789        case MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND:
 790          reason = "EXCEPTION_FLT_DENORMAL_OPERAND";
 791          break;
 792        case MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO:
 793          reason = "EXCEPTION_FLT_DIVIDE_BY_ZERO";
 794          break;
 795        case MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT:
 796          reason = "EXCEPTION_FLT_INEXACT_RESULT";
 797          break;
 798        case MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION:
 799          reason = "EXCEPTION_FLT_INVALID_OPERATION";
 800          break;
 801        case MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW:
 802          reason = "EXCEPTION_FLT_OVERFLOW";
 803          break;
 804        case MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK:
 805          reason = "EXCEPTION_FLT_STACK_CHECK";
 806          break;
 807        case MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW:
 808          reason = "EXCEPTION_FLT_UNDERFLOW";
 809          break;
 810        case MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO:
 811          reason = "EXCEPTION_INT_DIVIDE_BY_ZERO";
 812          break;
 813        case MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW:
 814          reason = "EXCEPTION_INT_OVERFLOW";
 815          break;
 816        case MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION:
 817          reason = "EXCEPTION_PRIV_INSTRUCTION";
 818          break;
 819        case MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW:
 820          reason = "EXCEPTION_STACK_OVERFLOW";
 821          break;
 822        case MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK:
 823          reason = "EXCEPTION_POSSIBLE_DEADLOCK";
 824          break;
 825        case MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN:
 826          reason = "EXCEPTION_STACK_BUFFER_OVERRUN";
 827          break;
 828        case MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION:
 829          reason = "EXCEPTION_HEAP_CORRUPTION";
 830          break;
 831        case MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION:
 832          reason = "Unhandled C++ Exception";
 833          break;
 834        default:
 835          BPLOG(INFO) << "Unknown exception reason " << reason;
 836          break;
 837      }
 838      break;
 839    }
 840
 841    case MD_OS_LINUX: {
 842      switch (exception_code) {
 843        case MD_EXCEPTION_CODE_LIN_SIGHUP:
 844          reason = "SIGHUP";
 845          break;
 846        case MD_EXCEPTION_CODE_LIN_SIGINT:
 847          reason = "SIGINT";
 848          break;
 849        case MD_EXCEPTION_CODE_LIN_SIGQUIT:
 850          reason = "SIGQUIT";
 851          break;
 852        case MD_EXCEPTION_CODE_LIN_SIGILL:
 853          reason = "SIGILL";
 854          break;
 855        case MD_EXCEPTION_CODE_LIN_SIGTRAP:
 856          reason = "SIGTRAP";
 857          break;
 858        case MD_EXCEPTION_CODE_LIN_SIGABRT:
 859          reason = "SIGABRT";
 860          break;
 861        case MD_EXCEPTION_CODE_LIN_SIGBUS:
 862          reason = "SIGBUS";
 863          break;
 864        case MD_EXCEPTION_CODE_LIN_SIGFPE:
 865          reason = "SIGFPE";
 866          break;
 867        case MD_EXCEPTION_CODE_LIN_SIGKILL:
 868          reason = "SIGKILL";
 869          break;
 870        case MD_EXCEPTION_CODE_LIN_SIGUSR1:
 871          reason = "SIGUSR1";
 872          break;
 873        case MD_EXCEPTION_CODE_LIN_SIGSEGV:
 874          reason = "SIGSEGV";
 875          break;
 876        case MD_EXCEPTION_CODE_LIN_SIGUSR2:
 877          reason = "SIGUSR2";
 878          break;
 879        case MD_EXCEPTION_CODE_LIN_SIGPIPE:
 880          reason = "SIGPIPE";
 881          break;
 882        case MD_EXCEPTION_CODE_LIN_SIGALRM:
 883          reason = "SIGALRM";
 884          break;
 885        case MD_EXCEPTION_CODE_LIN_SIGTERM:
 886          reason = "SIGTERM";
 887          break;
 888        case MD_EXCEPTION_CODE_LIN_SIGSTKFLT:
 889          reason = "SIGSTKFLT";
 890          break;
 891        case MD_EXCEPTION_CODE_LIN_SIGCHLD:
 892          reason = "SIGCHLD";
 893          break;
 894        case MD_EXCEPTION_CODE_LIN_SIGCONT:
 895          reason = "SIGCONT";
 896          break;
 897        case MD_EXCEPTION_CODE_LIN_SIGSTOP:
 898          reason = "SIGSTOP";
 899          break;
 900        case MD_EXCEPTION_CODE_LIN_SIGTSTP:
 901          reason = "SIGTSTP";
 902          break;
 903        case MD_EXCEPTION_CODE_LIN_SIGTTIN:
 904          reason = "SIGTTIN";
 905          break;
 906        case MD_EXCEPTION_CODE_LIN_SIGTTOU:
 907          reason = "SIGTTOU";
 908          break;
 909        case MD_EXCEPTION_CODE_LIN_SIGURG:
 910          reason = "SIGURG";
 911          break;
 912        case MD_EXCEPTION_CODE_LIN_SIGXCPU:
 913          reason = "SIGXCPU";
 914          break;
 915        case MD_EXCEPTION_CODE_LIN_SIGXFSZ:
 916          reason = "SIGXFSZ";
 917          break;
 918        case MD_EXCEPTION_CODE_LIN_SIGVTALRM:
 919          reason = "SIGVTALRM";
 920          break;
 921        case MD_EXCEPTION_CODE_LIN_SIGPROF:
 922          reason = "SIGPROF";
 923          break;
 924        case MD_EXCEPTION_CODE_LIN_SIGWINCH:
 925          reason = "SIGWINCH";
 926          break;
 927        case MD_EXCEPTION_CODE_LIN_SIGIO:
 928          reason = "SIGIO";
 929          break;
 930        case MD_EXCEPTION_CODE_LIN_SIGPWR:
 931          reason = "SIGPWR";
 932          break;
 933        case MD_EXCEPTION_CODE_LIN_SIGSYS:
 934          reason = "SIGSYS";
 935          break;
 936        default:
 937          BPLOG(INFO) << "Unknown exception reason " << reason;
 938          break;
 939      }
 940      break;
 941    }
 942
 943    case MD_OS_SOLARIS: {
 944      switch (exception_code) {
 945        case MD_EXCEPTION_CODE_SOL_SIGHUP:
 946          reason = "SIGHUP";
 947          break;
 948        case MD_EXCEPTION_CODE_SOL_SIGINT:
 949          reason = "SIGINT";
 950          break;
 951        case MD_EXCEPTION_CODE_SOL_SIGQUIT:
 952          reason = "SIGQUIT";
 953          break;
 954        case MD_EXCEPTION_CODE_SOL_SIGILL:
 955          reason = "SIGILL";
 956          break;
 957        case MD_EXCEPTION_CODE_SOL_SIGTRAP:
 958          reason = "SIGTRAP";
 959          break;
 960        case MD_EXCEPTION_CODE_SOL_SIGIOT:
 961          reason = "SIGIOT | SIGABRT";
 962          break;
 963        case MD_EXCEPTION_CODE_SOL_SIGEMT:
 964          reason = "SIGEMT";
 965          break;
 966        case MD_EXCEPTION_CODE_SOL_SIGFPE:
 967          reason = "SIGFPE";
 968          break;
 969        case MD_EXCEPTION_CODE_SOL_SIGKILL:
 970          reason = "SIGKILL";
 971          break;
 972        case MD_EXCEPTION_CODE_SOL_SIGBUS:
 973          reason = "SIGBUS";
 974          break;
 975        case MD_EXCEPTION_CODE_SOL_SIGSEGV:
 976          reason = "SIGSEGV";
 977          break;
 978        case MD_EXCEPTION_CODE_SOL_SIGSYS:
 979          reason = "SIGSYS";
 980          break;
 981        case MD_EXCEPTION_CODE_SOL_SIGPIPE:
 982          reason = "SIGPIPE";
 983          break;
 984        case MD_EXCEPTION_CODE_SOL_SIGALRM:
 985          reason = "SIGALRM";
 986          break;
 987        case MD_EXCEPTION_CODE_SOL_SIGTERM:
 988          reason = "SIGTERM";
 989          break;
 990        case MD_EXCEPTION_CODE_SOL_SIGUSR1:
 991          reason = "SIGUSR1";
 992          break;
 993        case MD_EXCEPTION_CODE_SOL_SIGUSR2:
 994          reason = "SIGUSR2";
 995          break;
 996        case MD_EXCEPTION_CODE_SOL_SIGCLD:
 997          reason = "SIGCLD | SIGCHLD";
 998          break;
 999        case MD_EXCEPTION_CODE_SOL_SIGPWR:
1000          reason = "SIGPWR";
1001          break;
1002        case MD_EXCEPTION_CODE_SOL_SIGWINCH:
1003          reason = "SIGWINCH";
1004          break;
1005        case MD_EXCEPTION_CODE_SOL_SIGURG:
1006          reason = "SIGURG";
1007          break;
1008        case MD_EXCEPTION_CODE_SOL_SIGPOLL:
1009          reason = "SIGPOLL | SIGIO";
1010          break;
1011        case MD_EXCEPTION_CODE_SOL_SIGSTOP:
1012          reason = "SIGSTOP";
1013          break;
1014        case MD_EXCEPTION_CODE_SOL_SIGTSTP:
1015          reason = "SIGTSTP";
1016          break;
1017        case MD_EXCEPTION_CODE_SOL_SIGCONT:
1018          reason = "SIGCONT";
1019          break;
1020        case MD_EXCEPTION_CODE_SOL_SIGTTIN:
1021          reason = "SIGTTIN";
1022          break;
1023        case MD_EXCEPTION_CODE_SOL_SIGTTOU:
1024          reason = "SIGTTOU";
1025          break;
1026        case MD_EXCEPTION_CODE_SOL_SIGVTALRM:
1027          reason = "SIGVTALRM";
1028          break;
1029        case MD_EXCEPTION_CODE_SOL_SIGPROF:
1030          reason = "SIGPROF";
1031          break;
1032        case MD_EXCEPTION_CODE_SOL_SIGXCPU:
1033          reason = "SIGXCPU";
1034          break;
1035        case MD_EXCEPTION_CODE_SOL_SIGXFSZ:
1036          reason = "SIGXFSZ";
1037          break;
1038        case MD_EXCEPTION_CODE_SOL_SIGWAITING:
1039          reason = "SIGWAITING";
1040          break;
1041        case MD_EXCEPTION_CODE_SOL_SIGLWP:
1042          reason = "SIGLWP";
1043          break;
1044        case MD_EXCEPTION_CODE_SOL_SIGFREEZE:
1045          reason = "SIGFREEZE";
1046          break;
1047        case MD_EXCEPTION_CODE_SOL_SIGTHAW:
1048          reason = "SIGTHAW";
1049          break;
1050        case MD_EXCEPTION_CODE_SOL_SIGCANCEL:
1051          reason = "SIGCANCEL";
1052          break;
1053        case MD_EXCEPTION_CODE_SOL_SIGLOST:
1054          reason = "SIGLOST";
1055          break;
1056        case MD_EXCEPTION_CODE_SOL_SIGXRES:
1057          reason = "SIGXRES";
1058          break;
1059        case MD_EXCEPTION_CODE_SOL_SIGJVM1:
1060          reason = "SIGJVM1";
1061          break;
1062        case MD_EXCEPTION_CODE_SOL_SIGJVM2:
1063          reason = "SIGJVM2";
1064          break;
1065        default:
1066          BPLOG(INFO) << "Unknown exception reason " << reason;
1067          break;
1068      }
1069      break;
1070    }
1071
1072    default: {
1073      BPLOG(INFO) << "Unknown exception reason " << reason;
1074      break;
1075    }
1076  }
1077
1078  return reason;
1079}
1080
1081// static
1082string MinidumpProcessor::GetAssertion(Minidump *dump) {
1083  MinidumpAssertion *assertion = dump->GetAssertion();
1084  if (!assertion)
1085    return "";
1086
1087  const MDRawAssertionInfo *raw_assertion = assertion->assertion();
1088  if (!raw_assertion)
1089    return "";
1090
1091  string assertion_string;
1092  switch (raw_assertion->type) {
1093  case MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER:
1094    assertion_string = "Invalid parameter passed to library function";
1095    break;
1096  case MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL:
1097    assertion_string = "Pure virtual function called";
1098    break;
1099  default: {
1100    char assertion_type[32];
1101    sprintf(assertion_type, "0x%08x", raw_assertion->type);
1102    assertion_string = "Unknown assertion type ";
1103    assertion_string += assertion_type;
1104    break;
1105  }
1106  }
1107
1108  string expression = assertion->expression();
1109  if (!expression.empty()) {
1110    assertion_string.append(" " + expression);
1111  }
1112
1113  string function = assertion->function();
1114  if (!function.empty()) {
1115    assertion_string.append(" in function " + function);
1116  }
1117
1118  string file = assertion->file();
1119  if (!file.empty()) {
1120    assertion_string.append(", in file " + file);
1121  }
1122
1123  if (raw_assertion->line != 0) {
1124    char assertion_line[32];
1125    sprintf(assertion_line, "%u", raw_assertion->line);
1126    assertion_string.append(" at line ");
1127    assertion_string.append(assertion_line);
1128  }
1129
1130  return assertion_string;
1131}
1132
1133}  // namespace google_breakpad