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