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