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 | |
34 | #include <algorithm> |
35 | #include <string> |
36 | |
37 | #include "common/scoped_ptr.h" |
38 | #include "common/stdio_wrapper.h" |
39 | #include "common/using_std_string.h" |
40 | #include "google_breakpad/processor/call_stack.h" |
41 | #include "google_breakpad/processor/minidump.h" |
42 | #include "google_breakpad/processor/process_state.h" |
43 | #include "google_breakpad/processor/exploitability.h" |
44 | #include "google_breakpad/processor/stack_frame_symbolizer.h" |
45 | #include "processor/logging.h" |
46 | #include "processor/stackwalker_x86.h" |
47 | #include "processor/symbolic_constants_win.h" |
48 | |
49 | namespace google_breakpad { |
50 | |
51 | MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier, |
52 | SourceLineResolverInterface* resolver) |
53 | : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)), |
54 | own_frame_symbolizer_(true), |
55 | enable_exploitability_(false), |
56 | enable_objdump_(false) { |
57 | } |
58 | |
59 | MinidumpProcessor::MinidumpProcessor(SymbolSupplier* supplier, |
60 | SourceLineResolverInterface* resolver, |
61 | bool enable_exploitability) |
62 | : frame_symbolizer_(new StackFrameSymbolizer(supplier, resolver)), |
63 | own_frame_symbolizer_(true), |
64 | enable_exploitability_(enable_exploitability), |
65 | enable_objdump_(false) { |
66 | } |
67 | |
68 | MinidumpProcessor::MinidumpProcessor(StackFrameSymbolizer* frame_symbolizer, |
69 | bool enable_exploitability) |
70 | : frame_symbolizer_(frame_symbolizer), |
71 | own_frame_symbolizer_(false), |
72 | enable_exploitability_(enable_exploitability), |
73 | enable_objdump_(false) { |
74 | assert(frame_symbolizer_); |
75 | } |
76 | |
77 | MinidumpProcessor::~MinidumpProcessor() { |
78 | if (own_frame_symbolizer_) delete frame_symbolizer_; |
79 | } |
80 | |
81 | ProcessResult MinidumpProcessor::Process( |
82 | Minidump* dump, ProcessState* process_state) { |
83 | assert(dump); |
84 | assert(process_state); |
85 | |
86 | process_state->Clear(); |
87 | |
88 | const MDRawHeader* = dump->header(); |
89 | if (!header) { |
90 | BPLOG(ERROR) << "Minidump " << dump->path() << " has no header" ; |
91 | return PROCESS_ERROR_NO_MINIDUMP_HEADER; |
92 | } |
93 | process_state->time_date_stamp_ = header->time_date_stamp; |
94 | |
95 | bool has_process_create_time = |
96 | GetProcessCreateTime(dump, &process_state->process_create_time_); |
97 | |
98 | bool has_cpu_info = GetCPUInfo(dump, &process_state->system_info_); |
99 | bool has_os_info = GetOSInfo(dump, &process_state->system_info_); |
100 | |
101 | uint32_t dump_thread_id = 0; |
102 | bool has_dump_thread = false; |
103 | uint32_t requesting_thread_id = 0; |
104 | bool has_requesting_thread = false; |
105 | |
106 | MinidumpBreakpadInfo* breakpad_info = dump->GetBreakpadInfo(); |
107 | if (breakpad_info) { |
108 | has_dump_thread = breakpad_info->GetDumpThreadID(&dump_thread_id); |
109 | has_requesting_thread = |
110 | breakpad_info->GetRequestingThreadID(&requesting_thread_id); |
111 | } |
112 | |
113 | MinidumpException* exception = dump->GetException(); |
114 | if (exception) { |
115 | process_state->crashed_ = true; |
116 | has_requesting_thread = exception->GetThreadID(&requesting_thread_id); |
117 | |
118 | process_state->crash_reason_ = GetCrashReason( |
119 | dump, &process_state->crash_address_); |
120 | |
121 | process_state->exception_record_.set_code( |
122 | exception->exception()->exception_record.exception_code, |
123 | // TODO(ivanpe): Populate description. |
124 | /* description = */ "" ); |
125 | process_state->exception_record_.set_flags( |
126 | exception->exception()->exception_record.exception_flags, |
127 | // TODO(ivanpe): Populate description. |
128 | /* description = */ "" ); |
129 | process_state->exception_record_.set_nested_exception_record_address( |
130 | exception->exception()->exception_record.exception_record); |
131 | process_state->exception_record_.set_address(process_state->crash_address_); |
132 | const uint32_t num_parameters = |
133 | std::min(exception->exception()->exception_record.number_parameters, |
134 | MD_EXCEPTION_MAXIMUM_PARAMETERS); |
135 | for (uint32_t i = 0; i < num_parameters; ++i) { |
136 | process_state->exception_record_.add_parameter( |
137 | exception->exception()->exception_record.exception_information[i], |
138 | // TODO(ivanpe): Populate description. |
139 | /* description = */ "" ); |
140 | } |
141 | } |
142 | |
143 | // This will just return an empty string if it doesn't exist. |
144 | process_state->assertion_ = GetAssertion(dump); |
145 | |
146 | MinidumpModuleList* module_list = dump->GetModuleList(); |
147 | |
148 | // Put a copy of the module list into ProcessState object. This is not |
149 | // necessarily a MinidumpModuleList, but it adheres to the CodeModules |
150 | // interface, which is all that ProcessState needs to expose. |
151 | if (module_list) { |
152 | process_state->modules_ = module_list->Copy(); |
153 | process_state->shrunk_range_modules_ = |
154 | process_state->modules_->GetShrunkRangeModules(); |
155 | for (unsigned int i = 0; |
156 | i < process_state->shrunk_range_modules_.size(); |
157 | i++) { |
158 | linked_ptr<const CodeModule> module = |
159 | process_state->shrunk_range_modules_[i]; |
160 | BPLOG(INFO) << "The range for module " << module->code_file() |
161 | << " was shrunk down by " << HexString( |
162 | module->shrink_down_delta()) << " bytes. " ; |
163 | } |
164 | } |
165 | |
166 | MinidumpUnloadedModuleList* unloaded_module_list = |
167 | dump->GetUnloadedModuleList(); |
168 | if (unloaded_module_list) { |
169 | process_state->unloaded_modules_ = unloaded_module_list->Copy(); |
170 | } |
171 | |
172 | MinidumpMemoryList* memory_list = dump->GetMemoryList(); |
173 | if (memory_list) { |
174 | BPLOG(INFO) << "Found " << memory_list->region_count() |
175 | << " memory regions." ; |
176 | } |
177 | |
178 | MinidumpThreadList* threads = dump->GetThreadList(); |
179 | if (!threads) { |
180 | BPLOG(ERROR) << "Minidump " << dump->path() << " has no thread list" ; |
181 | return PROCESS_ERROR_NO_THREAD_LIST; |
182 | } |
183 | |
184 | BPLOG(INFO) << "Minidump " << dump->path() << " has " << |
185 | (has_cpu_info ? "" : "no " ) << "CPU info, " << |
186 | (has_os_info ? "" : "no " ) << "OS info, " << |
187 | (breakpad_info != NULL ? "" : "no " ) << "Breakpad info, " << |
188 | (exception != NULL ? "" : "no " ) << "exception, " << |
189 | (module_list != NULL ? "" : "no " ) << "module list, " << |
190 | (threads != NULL ? "" : "no " ) << "thread list, " << |
191 | (has_dump_thread ? "" : "no " ) << "dump thread, " << |
192 | (has_requesting_thread ? "" : "no " ) << "requesting thread, and " << |
193 | (has_process_create_time ? "" : "no " ) << "process create time" ; |
194 | |
195 | bool interrupted = false; |
196 | bool found_requesting_thread = false; |
197 | unsigned int thread_count = threads->thread_count(); |
198 | |
199 | // Reset frame_symbolizer_ at the beginning of stackwalk for each minidump. |
200 | frame_symbolizer_->Reset(); |
201 | |
202 | for (unsigned int thread_index = 0; |
203 | thread_index < thread_count; |
204 | ++thread_index) { |
205 | char thread_string_buffer[64]; |
206 | snprintf(thread_string_buffer, sizeof(thread_string_buffer), "%d/%d" , |
207 | thread_index, thread_count); |
208 | string thread_string = dump->path() + ":" + thread_string_buffer; |
209 | |
210 | MinidumpThread* thread = threads->GetThreadAtIndex(thread_index); |
211 | if (!thread) { |
212 | BPLOG(ERROR) << "Could not get thread for " << thread_string; |
213 | return PROCESS_ERROR_GETTING_THREAD; |
214 | } |
215 | |
216 | uint32_t thread_id; |
217 | if (!thread->GetThreadID(&thread_id)) { |
218 | BPLOG(ERROR) << "Could not get thread ID for " << thread_string; |
219 | return PROCESS_ERROR_GETTING_THREAD_ID; |
220 | } |
221 | |
222 | thread_string += " id " + HexString(thread_id); |
223 | BPLOG(INFO) << "Looking at thread " << thread_string; |
224 | |
225 | // If this thread is the thread that produced the minidump, don't process |
226 | // it. Because of the problems associated with a thread producing a |
227 | // dump of itself (when both its context and its stack are in flux), |
228 | // processing that stack wouldn't provide much useful data. |
229 | if (has_dump_thread && thread_id == dump_thread_id) { |
230 | continue; |
231 | } |
232 | |
233 | MinidumpContext* context = thread->GetContext(); |
234 | |
235 | if (has_requesting_thread && thread_id == requesting_thread_id) { |
236 | if (found_requesting_thread) { |
237 | // There can't be more than one requesting thread. |
238 | BPLOG(ERROR) << "Duplicate requesting thread: " << thread_string; |
239 | return PROCESS_ERROR_DUPLICATE_REQUESTING_THREADS; |
240 | } |
241 | |
242 | // Use processed_state->threads_.size() instead of thread_index. |
243 | // thread_index points to the thread index in the minidump, which |
244 | // might be greater than the thread index in the threads vector if |
245 | // any of the minidump's threads are skipped and not placed into the |
246 | // processed threads vector. The thread vector's current size will |
247 | // be the index of the current thread when it's pushed into the |
248 | // vector. |
249 | process_state->requesting_thread_ = process_state->threads_.size(); |
250 | |
251 | found_requesting_thread = true; |
252 | |
253 | if (process_state->crashed_) { |
254 | // Use the exception record's context for the crashed thread, instead |
255 | // of the thread's own context. For the crashed thread, the thread's |
256 | // own context is the state inside the exception handler. Using it |
257 | // would not result in the expected stack trace from the time of the |
258 | // crash. If the exception context is invalid, however, we fall back |
259 | // on the thread context. |
260 | MinidumpContext* ctx = exception->GetContext(); |
261 | context = ctx ? ctx : thread->GetContext(); |
262 | } |
263 | } |
264 | |
265 | // If the memory region for the stack cannot be read using the RVA stored |
266 | // in the memory descriptor inside MINIDUMP_THREAD, try to locate and use |
267 | // a memory region (containing the stack) from the minidump memory list. |
268 | MinidumpMemoryRegion* thread_memory = thread->GetMemory(); |
269 | if (!thread_memory && memory_list) { |
270 | uint64_t start_stack_memory_range = thread->GetStartOfStackMemoryRange(); |
271 | if (start_stack_memory_range) { |
272 | thread_memory = memory_list->GetMemoryRegionForAddress( |
273 | start_stack_memory_range); |
274 | } |
275 | } |
276 | if (!thread_memory) { |
277 | BPLOG(ERROR) << "No memory region for " << thread_string; |
278 | } |
279 | |
280 | // Use process_state->modules_ instead of module_list, because the |
281 | // |modules| argument will be used to populate the |module| fields in |
282 | // the returned StackFrame objects, which will be placed into the |
283 | // returned ProcessState object. module_list's lifetime is only as |
284 | // long as the Minidump object: it will be deleted when this function |
285 | // returns. process_state->modules_ is owned by the ProcessState object |
286 | // (just like the StackFrame objects), and is much more suitable for this |
287 | // task. |
288 | scoped_ptr<Stackwalker> stackwalker( |
289 | Stackwalker::StackwalkerForCPU(process_state->system_info(), |
290 | context, |
291 | thread_memory, |
292 | process_state->modules_, |
293 | process_state->unloaded_modules_, |
294 | frame_symbolizer_)); |
295 | |
296 | scoped_ptr<CallStack> stack(new CallStack()); |
297 | if (stackwalker.get()) { |
298 | if (!stackwalker->Walk(stack.get(), |
299 | &process_state->modules_without_symbols_, |
300 | &process_state->modules_with_corrupt_symbols_)) { |
301 | BPLOG(INFO) << "Stackwalker interrupt (missing symbols?) at " |
302 | << thread_string; |
303 | interrupted = true; |
304 | } |
305 | } else { |
306 | // Threads with missing CPU contexts will hit this, but |
307 | // don't abort processing the rest of the dump just for |
308 | // one bad thread. |
309 | BPLOG(ERROR) << "No stackwalker for " << thread_string; |
310 | } |
311 | stack->set_tid(thread_id); |
312 | process_state->threads_.push_back(stack.release()); |
313 | process_state->thread_memory_regions_.push_back(thread_memory); |
314 | } |
315 | |
316 | if (interrupted) { |
317 | BPLOG(INFO) << "Processing interrupted for " << dump->path(); |
318 | return PROCESS_SYMBOL_SUPPLIER_INTERRUPTED; |
319 | } |
320 | |
321 | // If a requesting thread was indicated, it must be present. |
322 | if (has_requesting_thread && !found_requesting_thread) { |
323 | // Don't mark as an error, but invalidate the requesting thread |
324 | BPLOG(ERROR) << "Minidump indicated requesting thread " << |
325 | HexString(requesting_thread_id) << ", not found in " << |
326 | dump->path(); |
327 | process_state->requesting_thread_ = -1; |
328 | } |
329 | |
330 | // Exploitability defaults to EXPLOITABILITY_NOT_ANALYZED |
331 | process_state->exploitability_ = EXPLOITABILITY_NOT_ANALYZED; |
332 | |
333 | // If an exploitability run was requested we perform the platform specific |
334 | // rating. |
335 | if (enable_exploitability_) { |
336 | scoped_ptr<Exploitability> exploitability( |
337 | Exploitability::ExploitabilityForPlatform(dump, |
338 | process_state, |
339 | enable_objdump_)); |
340 | // The engine will be null if the platform is not supported |
341 | if (exploitability != NULL) { |
342 | process_state->exploitability_ = exploitability->CheckExploitability(); |
343 | } else { |
344 | process_state->exploitability_ = EXPLOITABILITY_ERR_NOENGINE; |
345 | } |
346 | } |
347 | |
348 | BPLOG(INFO) << "Processed " << dump->path(); |
349 | return PROCESS_OK; |
350 | } |
351 | |
352 | ProcessResult MinidumpProcessor::Process( |
353 | const string& minidump_file, ProcessState* process_state) { |
354 | BPLOG(INFO) << "Processing minidump in file " << minidump_file; |
355 | |
356 | Minidump dump(minidump_file); |
357 | if (!dump.Read()) { |
358 | BPLOG(ERROR) << "Minidump " << dump.path() << " could not be read" ; |
359 | return PROCESS_ERROR_MINIDUMP_NOT_FOUND; |
360 | } |
361 | |
362 | return Process(&dump, process_state); |
363 | } |
364 | |
365 | // Returns the MDRawSystemInfo from a minidump, or NULL if system info is |
366 | // not available from the minidump. If system_info is non-NULL, it is used |
367 | // to pass back the MinidumpSystemInfo object. |
368 | static const MDRawSystemInfo* GetSystemInfo(Minidump* dump, |
369 | MinidumpSystemInfo** system_info) { |
370 | MinidumpSystemInfo* minidump_system_info = dump->GetSystemInfo(); |
371 | if (!minidump_system_info) |
372 | return NULL; |
373 | |
374 | if (system_info) |
375 | *system_info = minidump_system_info; |
376 | |
377 | return minidump_system_info->system_info(); |
378 | } |
379 | |
380 | static uint64_t GetAddressForArchitecture(const MDCPUArchitecture architecture, |
381 | size_t raw_address) |
382 | { |
383 | switch (architecture) { |
384 | case MD_CPU_ARCHITECTURE_X86: |
385 | case MD_CPU_ARCHITECTURE_MIPS: |
386 | case MD_CPU_ARCHITECTURE_PPC: |
387 | case MD_CPU_ARCHITECTURE_SHX: |
388 | case MD_CPU_ARCHITECTURE_ARM: |
389 | case MD_CPU_ARCHITECTURE_X86_WIN64: |
390 | // 32-bit architectures, mask the upper bits. |
391 | return raw_address & 0xffffffffULL; |
392 | |
393 | default: |
394 | // All other architectures either have 64-bit pointers or it's impossible |
395 | // to tell from the minidump (e.g. MSIL or SPARC) so use 64-bits anyway. |
396 | return raw_address; |
397 | } |
398 | } |
399 | |
400 | // Extract CPU info string from ARM-specific MDRawSystemInfo structure. |
401 | // raw_info: pointer to source MDRawSystemInfo. |
402 | // cpu_info: address of target string, cpu info text will be appended to it. |
403 | static void GetARMCpuInfo(const MDRawSystemInfo* raw_info, |
404 | string* cpu_info) { |
405 | assert(raw_info != NULL && cpu_info != NULL); |
406 | |
407 | // Write ARM architecture version. |
408 | char cpu_string[32]; |
409 | snprintf(cpu_string, sizeof(cpu_string), "ARMv%d" , |
410 | raw_info->processor_level); |
411 | cpu_info->append(cpu_string); |
412 | |
413 | // There is no good list of implementer id values, but the following |
414 | // pages provide some help: |
415 | // http://comments.gmane.org/gmane.linux.linaro.devel/6903 |
416 | // http://forum.xda-developers.com/archive/index.php/t-480226.html |
417 | const struct { |
418 | uint32_t id; |
419 | const char* name; |
420 | } vendors[] = { |
421 | { 0x41, "ARM" }, |
422 | { 0x51, "Qualcomm" }, |
423 | { 0x56, "Marvell" }, |
424 | { 0x69, "Intel/Marvell" }, |
425 | }; |
426 | const struct { |
427 | uint32_t id; |
428 | const char* name; |
429 | } parts[] = { |
430 | { 0x4100c050, "Cortex-A5" }, |
431 | { 0x4100c080, "Cortex-A8" }, |
432 | { 0x4100c090, "Cortex-A9" }, |
433 | { 0x4100c0f0, "Cortex-A15" }, |
434 | { 0x4100c140, "Cortex-R4" }, |
435 | { 0x4100c150, "Cortex-R5" }, |
436 | { 0x4100b360, "ARM1136" }, |
437 | { 0x4100b560, "ARM1156" }, |
438 | { 0x4100b760, "ARM1176" }, |
439 | { 0x4100b020, "ARM11-MPCore" }, |
440 | { 0x41009260, "ARM926" }, |
441 | { 0x41009460, "ARM946" }, |
442 | { 0x41009660, "ARM966" }, |
443 | { 0x510006f0, "Krait" }, |
444 | { 0x510000f0, "Scorpion" }, |
445 | }; |
446 | |
447 | const struct { |
448 | uint32_t hwcap; |
449 | const char* name; |
450 | } features[] = { |
451 | { MD_CPU_ARM_ELF_HWCAP_SWP, "swp" }, |
452 | { MD_CPU_ARM_ELF_HWCAP_HALF, "half" }, |
453 | { MD_CPU_ARM_ELF_HWCAP_THUMB, "thumb" }, |
454 | { MD_CPU_ARM_ELF_HWCAP_26BIT, "26bit" }, |
455 | { MD_CPU_ARM_ELF_HWCAP_FAST_MULT, "fastmult" }, |
456 | { MD_CPU_ARM_ELF_HWCAP_FPA, "fpa" }, |
457 | { MD_CPU_ARM_ELF_HWCAP_VFP, "vfpv2" }, |
458 | { MD_CPU_ARM_ELF_HWCAP_EDSP, "edsp" }, |
459 | { MD_CPU_ARM_ELF_HWCAP_JAVA, "java" }, |
460 | { MD_CPU_ARM_ELF_HWCAP_IWMMXT, "iwmmxt" }, |
461 | { MD_CPU_ARM_ELF_HWCAP_CRUNCH, "crunch" }, |
462 | { MD_CPU_ARM_ELF_HWCAP_THUMBEE, "thumbee" }, |
463 | { MD_CPU_ARM_ELF_HWCAP_NEON, "neon" }, |
464 | { MD_CPU_ARM_ELF_HWCAP_VFPv3, "vfpv3" }, |
465 | { MD_CPU_ARM_ELF_HWCAP_VFPv3D16, "vfpv3d16" }, |
466 | { MD_CPU_ARM_ELF_HWCAP_TLS, "tls" }, |
467 | { MD_CPU_ARM_ELF_HWCAP_VFPv4, "vfpv4" }, |
468 | { MD_CPU_ARM_ELF_HWCAP_IDIVA, "idiva" }, |
469 | { MD_CPU_ARM_ELF_HWCAP_IDIVT, "idivt" }, |
470 | }; |
471 | |
472 | uint32_t cpuid = raw_info->cpu.arm_cpu_info.cpuid; |
473 | if (cpuid != 0) { |
474 | // Extract vendor name from CPUID |
475 | const char* vendor = NULL; |
476 | uint32_t vendor_id = (cpuid >> 24) & 0xff; |
477 | for (size_t i = 0; i < sizeof(vendors)/sizeof(vendors[0]); ++i) { |
478 | if (vendors[i].id == vendor_id) { |
479 | vendor = vendors[i].name; |
480 | break; |
481 | } |
482 | } |
483 | cpu_info->append(" " ); |
484 | if (vendor) { |
485 | cpu_info->append(vendor); |
486 | } else { |
487 | snprintf(cpu_string, sizeof(cpu_string), "vendor(0x%x)" , vendor_id); |
488 | cpu_info->append(cpu_string); |
489 | } |
490 | |
491 | // Extract part name from CPUID |
492 | uint32_t part_id = (cpuid & 0xff00fff0); |
493 | const char* part = NULL; |
494 | for (size_t i = 0; i < sizeof(parts)/sizeof(parts[0]); ++i) { |
495 | if (parts[i].id == part_id) { |
496 | part = parts[i].name; |
497 | break; |
498 | } |
499 | } |
500 | cpu_info->append(" " ); |
501 | if (part != NULL) { |
502 | cpu_info->append(part); |
503 | } else { |
504 | snprintf(cpu_string, sizeof(cpu_string), "part(0x%x)" , part_id); |
505 | cpu_info->append(cpu_string); |
506 | } |
507 | } |
508 | uint32_t elf_hwcaps = raw_info->cpu.arm_cpu_info.elf_hwcaps; |
509 | if (elf_hwcaps != 0) { |
510 | cpu_info->append(" features: " ); |
511 | const char* comma = "" ; |
512 | for (size_t i = 0; i < sizeof(features)/sizeof(features[0]); ++i) { |
513 | if (elf_hwcaps & features[i].hwcap) { |
514 | cpu_info->append(comma); |
515 | cpu_info->append(features[i].name); |
516 | comma = "," ; |
517 | } |
518 | } |
519 | } |
520 | } |
521 | |
522 | // static |
523 | bool MinidumpProcessor::GetCPUInfo(Minidump* dump, SystemInfo* info) { |
524 | assert(dump); |
525 | assert(info); |
526 | |
527 | info->cpu.clear(); |
528 | info->cpu_info.clear(); |
529 | |
530 | MinidumpSystemInfo* system_info; |
531 | const MDRawSystemInfo* raw_system_info = GetSystemInfo(dump, &system_info); |
532 | if (!raw_system_info) |
533 | return false; |
534 | |
535 | switch (raw_system_info->processor_architecture) { |
536 | case MD_CPU_ARCHITECTURE_X86: |
537 | case MD_CPU_ARCHITECTURE_AMD64: { |
538 | if (raw_system_info->processor_architecture == |
539 | MD_CPU_ARCHITECTURE_X86) |
540 | info->cpu = "x86" ; |
541 | else |
542 | info->cpu = "amd64" ; |
543 | |
544 | const string* cpu_vendor = system_info->GetCPUVendor(); |
545 | if (cpu_vendor) { |
546 | info->cpu_info = *cpu_vendor; |
547 | info->cpu_info.append(" " ); |
548 | } |
549 | |
550 | char x86_info[36]; |
551 | snprintf(x86_info, sizeof(x86_info), "family %u model %u stepping %u" , |
552 | raw_system_info->processor_level, |
553 | raw_system_info->processor_revision >> 8, |
554 | raw_system_info->processor_revision & 0xff); |
555 | info->cpu_info.append(x86_info); |
556 | break; |
557 | } |
558 | |
559 | case MD_CPU_ARCHITECTURE_PPC: { |
560 | info->cpu = "ppc" ; |
561 | break; |
562 | } |
563 | |
564 | case MD_CPU_ARCHITECTURE_PPC64: { |
565 | info->cpu = "ppc64" ; |
566 | break; |
567 | } |
568 | |
569 | case MD_CPU_ARCHITECTURE_SPARC: { |
570 | info->cpu = "sparc" ; |
571 | break; |
572 | } |
573 | |
574 | case MD_CPU_ARCHITECTURE_ARM: { |
575 | info->cpu = "arm" ; |
576 | GetARMCpuInfo(raw_system_info, &info->cpu_info); |
577 | break; |
578 | } |
579 | |
580 | case MD_CPU_ARCHITECTURE_ARM64: |
581 | case MD_CPU_ARCHITECTURE_ARM64_OLD: { |
582 | info->cpu = "arm64" ; |
583 | break; |
584 | } |
585 | |
586 | case MD_CPU_ARCHITECTURE_MIPS: { |
587 | info->cpu = "mips" ; |
588 | break; |
589 | } |
590 | case MD_CPU_ARCHITECTURE_MIPS64: { |
591 | info->cpu = "mips64" ; |
592 | break; |
593 | } |
594 | |
595 | default: { |
596 | // Assign the numeric architecture ID into the CPU string. |
597 | char cpu_string[7]; |
598 | snprintf(cpu_string, sizeof(cpu_string), "0x%04x" , |
599 | raw_system_info->processor_architecture); |
600 | info->cpu = cpu_string; |
601 | break; |
602 | } |
603 | } |
604 | |
605 | info->cpu_count = raw_system_info->number_of_processors; |
606 | |
607 | return true; |
608 | } |
609 | |
610 | // static |
611 | bool MinidumpProcessor::GetOSInfo(Minidump* dump, SystemInfo* info) { |
612 | assert(dump); |
613 | assert(info); |
614 | |
615 | info->os.clear(); |
616 | info->os_short.clear(); |
617 | info->os_version.clear(); |
618 | |
619 | MinidumpSystemInfo* system_info; |
620 | const MDRawSystemInfo* raw_system_info = GetSystemInfo(dump, &system_info); |
621 | if (!raw_system_info) |
622 | return false; |
623 | |
624 | info->os_short = system_info->GetOS(); |
625 | |
626 | switch (raw_system_info->platform_id) { |
627 | case MD_OS_WIN32_NT: { |
628 | info->os = "Windows NT" ; |
629 | break; |
630 | } |
631 | |
632 | case MD_OS_WIN32_WINDOWS: { |
633 | info->os = "Windows" ; |
634 | break; |
635 | } |
636 | |
637 | case MD_OS_MAC_OS_X: { |
638 | info->os = "Mac OS X" ; |
639 | break; |
640 | } |
641 | |
642 | case MD_OS_IOS: { |
643 | info->os = "iOS" ; |
644 | break; |
645 | } |
646 | |
647 | case MD_OS_LINUX: { |
648 | info->os = "Linux" ; |
649 | break; |
650 | } |
651 | |
652 | case MD_OS_SOLARIS: { |
653 | info->os = "Solaris" ; |
654 | break; |
655 | } |
656 | |
657 | case MD_OS_ANDROID: { |
658 | info->os = "Android" ; |
659 | break; |
660 | } |
661 | |
662 | case MD_OS_PS3: { |
663 | info->os = "PS3" ; |
664 | break; |
665 | } |
666 | |
667 | case MD_OS_NACL: { |
668 | info->os = "NaCl" ; |
669 | break; |
670 | } |
671 | |
672 | case MD_OS_FUCHSIA: { |
673 | info->os = "Fuchsia" ; |
674 | break; |
675 | } |
676 | |
677 | default: { |
678 | // Assign the numeric platform ID into the OS string. |
679 | char os_string[11]; |
680 | snprintf(os_string, sizeof(os_string), "0x%08x" , |
681 | raw_system_info->platform_id); |
682 | info->os = os_string; |
683 | break; |
684 | } |
685 | } |
686 | |
687 | char os_version_string[33]; |
688 | snprintf(os_version_string, sizeof(os_version_string), "%u.%u.%u" , |
689 | raw_system_info->major_version, |
690 | raw_system_info->minor_version, |
691 | raw_system_info->build_number); |
692 | info->os_version = os_version_string; |
693 | |
694 | const string* csd_version = system_info->GetCSDVersion(); |
695 | if (csd_version) { |
696 | info->os_version.append(" " ); |
697 | info->os_version.append(*csd_version); |
698 | } |
699 | |
700 | return true; |
701 | } |
702 | |
703 | // static |
704 | bool MinidumpProcessor::GetProcessCreateTime(Minidump* dump, |
705 | uint32_t* process_create_time) { |
706 | assert(dump); |
707 | assert(process_create_time); |
708 | |
709 | *process_create_time = 0; |
710 | |
711 | MinidumpMiscInfo* minidump_misc_info = dump->GetMiscInfo(); |
712 | if (!minidump_misc_info) { |
713 | return false; |
714 | } |
715 | |
716 | const MDRawMiscInfo* md_raw_misc_info = minidump_misc_info->misc_info(); |
717 | if (!md_raw_misc_info) { |
718 | return false; |
719 | } |
720 | |
721 | if (!(md_raw_misc_info->flags1 & MD_MISCINFO_FLAGS1_PROCESS_TIMES)) { |
722 | return false; |
723 | } |
724 | |
725 | *process_create_time = md_raw_misc_info->process_create_time; |
726 | return true; |
727 | } |
728 | |
729 | // static |
730 | string MinidumpProcessor::GetCrashReason(Minidump* dump, uint64_t* address) { |
731 | MinidumpException* exception = dump->GetException(); |
732 | if (!exception) |
733 | return "" ; |
734 | |
735 | const MDRawExceptionStream* raw_exception = exception->exception(); |
736 | if (!raw_exception) |
737 | return "" ; |
738 | |
739 | if (address) |
740 | *address = raw_exception->exception_record.exception_address; |
741 | |
742 | // The reason value is OS-specific and possibly CPU-specific. Set up |
743 | // sensible numeric defaults for the reason string in case we can't |
744 | // map the codes to a string (because there's no system info, or because |
745 | // it's an unrecognized platform, or because it's an unrecognized code.) |
746 | char reason_string[24]; |
747 | char flags_string[11]; |
748 | uint32_t exception_code = raw_exception->exception_record.exception_code; |
749 | uint32_t exception_flags = raw_exception->exception_record.exception_flags; |
750 | snprintf(flags_string, sizeof(flags_string), "0x%08x" , exception_flags); |
751 | snprintf(reason_string, sizeof(reason_string), "0x%08x / %s" , exception_code, |
752 | flags_string); |
753 | string reason = reason_string; |
754 | |
755 | const MDRawSystemInfo* raw_system_info = GetSystemInfo(dump, NULL); |
756 | if (!raw_system_info) |
757 | return reason; |
758 | |
759 | switch (raw_system_info->platform_id) { |
760 | case MD_OS_FUCHSIA: { |
761 | switch (exception_code) { |
762 | case MD_EXCEPTION_CODE_FUCHSIA_GENERAL: |
763 | reason = "GENERAL / " ; |
764 | reason.append(flags_string); |
765 | break; |
766 | case MD_EXCEPTION_CODE_FUCHSIA_FATAL_PAGE_FAULT: |
767 | reason = "FATAL_PAGE_FAULT / " ; |
768 | reason.append(flags_string); |
769 | break; |
770 | case MD_EXCEPTION_CODE_FUCHSIA_UNDEFINED_INSTRUCTION: |
771 | reason = "UNDEFINED_INSTRUCTION / " ; |
772 | reason.append(flags_string); |
773 | break; |
774 | case MD_EXCEPTION_CODE_FUCHSIA_SW_BREAKPOINT: |
775 | reason = "SW_BREAKPOINT / " ; |
776 | reason.append(flags_string); |
777 | break; |
778 | case MD_EXCEPTION_CODE_FUCHSIA_HW_BREAKPOINT: |
779 | reason = "HW_BREAKPOINT / " ; |
780 | reason.append(flags_string); |
781 | break; |
782 | case MD_EXCEPTION_CODE_FUCHSIA_UNALIGNED_ACCESS: |
783 | reason = "UNALIGNED_ACCESS / " ; |
784 | reason.append(flags_string); |
785 | break; |
786 | case MD_EXCEPTION_CODE_FUCHSIA_THREAD_STARTING: |
787 | reason = "THREAD_STARTING / " ; |
788 | reason.append(flags_string); |
789 | break; |
790 | case MD_EXCEPTION_CODE_FUCHSIA_THREAD_EXITING: |
791 | reason = "THREAD_EXITING / " ; |
792 | reason.append(flags_string); |
793 | break; |
794 | case MD_EXCEPTION_CODE_FUCHSIA_POLICY_ERROR: |
795 | reason = "POLICY_ERROR / " ; |
796 | reason.append(flags_string); |
797 | break; |
798 | case MD_EXCEPTION_CODE_FUCHSIA_PROCESS_STARTING: |
799 | reason = "PROCESS_STARTING / " ; |
800 | reason.append(flags_string); |
801 | break; |
802 | default: |
803 | BPLOG(INFO) << "Unknown exception reason " << reason; |
804 | } |
805 | break; |
806 | } |
807 | |
808 | case MD_OS_MAC_OS_X: |
809 | case MD_OS_IOS: { |
810 | switch (exception_code) { |
811 | case MD_EXCEPTION_MAC_BAD_ACCESS: |
812 | reason = "EXC_BAD_ACCESS / " ; |
813 | switch (exception_flags) { |
814 | case MD_EXCEPTION_CODE_MAC_INVALID_ADDRESS: |
815 | reason.append("KERN_INVALID_ADDRESS" ); |
816 | break; |
817 | case MD_EXCEPTION_CODE_MAC_PROTECTION_FAILURE: |
818 | reason.append("KERN_PROTECTION_FAILURE" ); |
819 | break; |
820 | case MD_EXCEPTION_CODE_MAC_NO_ACCESS: |
821 | reason.append("KERN_NO_ACCESS" ); |
822 | break; |
823 | case MD_EXCEPTION_CODE_MAC_MEMORY_FAILURE: |
824 | reason.append("KERN_MEMORY_FAILURE" ); |
825 | break; |
826 | case MD_EXCEPTION_CODE_MAC_MEMORY_ERROR: |
827 | reason.append("KERN_MEMORY_ERROR" ); |
828 | break; |
829 | case MD_EXCEPTION_CODE_MAC_CODESIGN_ERROR: |
830 | reason.append("KERN_CODESIGN_ERROR" ); |
831 | break; |
832 | default: |
833 | // arm and ppc overlap |
834 | if (raw_system_info->processor_architecture == |
835 | MD_CPU_ARCHITECTURE_ARM || |
836 | raw_system_info->processor_architecture == |
837 | MD_CPU_ARCHITECTURE_ARM64_OLD) { |
838 | switch (exception_flags) { |
839 | case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN: |
840 | reason.append("EXC_ARM_DA_ALIGN" ); |
841 | break; |
842 | case MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG: |
843 | reason.append("EXC_ARM_DA_DEBUG" ); |
844 | break; |
845 | default: |
846 | reason.append(flags_string); |
847 | BPLOG(INFO) << "Unknown exception reason " << reason; |
848 | break; |
849 | } |
850 | } else if (raw_system_info->processor_architecture == |
851 | MD_CPU_ARCHITECTURE_PPC) { |
852 | switch (exception_flags) { |
853 | case MD_EXCEPTION_CODE_MAC_PPC_VM_PROT_READ: |
854 | reason.append("EXC_PPC_VM_PROT_READ" ); |
855 | break; |
856 | case MD_EXCEPTION_CODE_MAC_PPC_BADSPACE: |
857 | reason.append("EXC_PPC_BADSPACE" ); |
858 | break; |
859 | case MD_EXCEPTION_CODE_MAC_PPC_UNALIGNED: |
860 | reason.append("EXC_PPC_UNALIGNED" ); |
861 | break; |
862 | default: |
863 | reason.append(flags_string); |
864 | BPLOG(INFO) << "Unknown exception reason " << reason; |
865 | break; |
866 | } |
867 | } else if (raw_system_info->processor_architecture == |
868 | MD_CPU_ARCHITECTURE_X86 || |
869 | raw_system_info->processor_architecture == |
870 | MD_CPU_ARCHITECTURE_AMD64) { |
871 | switch (exception_flags) { |
872 | case MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT: |
873 | reason.append("EXC_I386_GPFLT" ); |
874 | break; |
875 | default: |
876 | reason.append(flags_string); |
877 | BPLOG(INFO) << "Unknown exception reason " << reason; |
878 | break; |
879 | } |
880 | } else { |
881 | reason.append(flags_string); |
882 | BPLOG(INFO) << "Unknown exception reason " << reason; |
883 | } |
884 | break; |
885 | } |
886 | break; |
887 | case MD_EXCEPTION_MAC_BAD_INSTRUCTION: |
888 | reason = "EXC_BAD_INSTRUCTION / " ; |
889 | switch (raw_system_info->processor_architecture) { |
890 | case MD_CPU_ARCHITECTURE_ARM: |
891 | case MD_CPU_ARCHITECTURE_ARM64_OLD: { |
892 | switch (exception_flags) { |
893 | case MD_EXCEPTION_CODE_MAC_ARM_UNDEFINED: |
894 | reason.append("EXC_ARM_UNDEFINED" ); |
895 | break; |
896 | default: |
897 | reason.append(flags_string); |
898 | BPLOG(INFO) << "Unknown exception reason " << reason; |
899 | break; |
900 | } |
901 | break; |
902 | } |
903 | case MD_CPU_ARCHITECTURE_PPC: { |
904 | switch (exception_flags) { |
905 | case MD_EXCEPTION_CODE_MAC_PPC_INVALID_SYSCALL: |
906 | reason.append("EXC_PPC_INVALID_SYSCALL" ); |
907 | break; |
908 | case MD_EXCEPTION_CODE_MAC_PPC_UNIMPLEMENTED_INSTRUCTION: |
909 | reason.append("EXC_PPC_UNIPL_INST" ); |
910 | break; |
911 | case MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_INSTRUCTION: |
912 | reason.append("EXC_PPC_PRIVINST" ); |
913 | break; |
914 | case MD_EXCEPTION_CODE_MAC_PPC_PRIVILEGED_REGISTER: |
915 | reason.append("EXC_PPC_PRIVREG" ); |
916 | break; |
917 | case MD_EXCEPTION_CODE_MAC_PPC_TRACE: |
918 | reason.append("EXC_PPC_TRACE" ); |
919 | break; |
920 | case MD_EXCEPTION_CODE_MAC_PPC_PERFORMANCE_MONITOR: |
921 | reason.append("EXC_PPC_PERFMON" ); |
922 | break; |
923 | default: |
924 | reason.append(flags_string); |
925 | BPLOG(INFO) << "Unknown exception reason " << reason; |
926 | break; |
927 | } |
928 | break; |
929 | } |
930 | case MD_CPU_ARCHITECTURE_AMD64: |
931 | case MD_CPU_ARCHITECTURE_X86: { |
932 | switch (exception_flags) { |
933 | case MD_EXCEPTION_CODE_MAC_X86_INVALID_OPERATION: |
934 | reason.append("EXC_I386_INVOP" ); |
935 | break; |
936 | case MD_EXCEPTION_CODE_MAC_X86_INVALID_TASK_STATE_SEGMENT: |
937 | reason.append("EXC_I386_INVTSSFLT" ); |
938 | break; |
939 | case MD_EXCEPTION_CODE_MAC_X86_SEGMENT_NOT_PRESENT: |
940 | reason.append("EXC_I386_SEGNPFLT" ); |
941 | break; |
942 | case MD_EXCEPTION_CODE_MAC_X86_STACK_FAULT: |
943 | reason.append("EXC_I386_STKFLT" ); |
944 | break; |
945 | case MD_EXCEPTION_CODE_MAC_X86_GENERAL_PROTECTION_FAULT: |
946 | reason.append("EXC_I386_GPFLT" ); |
947 | break; |
948 | case MD_EXCEPTION_CODE_MAC_X86_ALIGNMENT_FAULT: |
949 | reason.append("EXC_I386_ALIGNFLT" ); |
950 | break; |
951 | default: |
952 | reason.append(flags_string); |
953 | BPLOG(INFO) << "Unknown exception reason " << reason; |
954 | break; |
955 | } |
956 | break; |
957 | } |
958 | default: |
959 | reason.append(flags_string); |
960 | BPLOG(INFO) << "Unknown exception reason " << reason; |
961 | break; |
962 | } |
963 | break; |
964 | case MD_EXCEPTION_MAC_ARITHMETIC: |
965 | reason = "EXC_ARITHMETIC / " ; |
966 | switch (raw_system_info->processor_architecture) { |
967 | case MD_CPU_ARCHITECTURE_PPC: { |
968 | switch (exception_flags) { |
969 | case MD_EXCEPTION_CODE_MAC_PPC_OVERFLOW: |
970 | reason.append("EXC_PPC_OVERFLOW" ); |
971 | break; |
972 | case MD_EXCEPTION_CODE_MAC_PPC_ZERO_DIVIDE: |
973 | reason.append("EXC_PPC_ZERO_DIVIDE" ); |
974 | break; |
975 | case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_INEXACT: |
976 | reason.append("EXC_FLT_INEXACT" ); |
977 | break; |
978 | case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_ZERO_DIVIDE: |
979 | reason.append("EXC_PPC_FLT_ZERO_DIVIDE" ); |
980 | break; |
981 | case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_UNDERFLOW: |
982 | reason.append("EXC_PPC_FLT_UNDERFLOW" ); |
983 | break; |
984 | case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_OVERFLOW: |
985 | reason.append("EXC_PPC_FLT_OVERFLOW" ); |
986 | break; |
987 | case MD_EXCEPTION_CODE_MAC_PPC_FLOAT_NOT_A_NUMBER: |
988 | reason.append("EXC_PPC_FLT_NOT_A_NUMBER" ); |
989 | break; |
990 | case MD_EXCEPTION_CODE_MAC_PPC_NO_EMULATION: |
991 | reason.append("EXC_PPC_NOEMULATION" ); |
992 | break; |
993 | case MD_EXCEPTION_CODE_MAC_PPC_ALTIVEC_ASSIST: |
994 | reason.append("EXC_PPC_ALTIVECASSIST" ); |
995 | break; |
996 | default: |
997 | reason.append(flags_string); |
998 | BPLOG(INFO) << "Unknown exception reason " << reason; |
999 | break; |
1000 | } |
1001 | break; |
1002 | } |
1003 | case MD_CPU_ARCHITECTURE_AMD64: |
1004 | case MD_CPU_ARCHITECTURE_X86: { |
1005 | switch (exception_flags) { |
1006 | case MD_EXCEPTION_CODE_MAC_X86_DIV: |
1007 | reason.append("EXC_I386_DIV" ); |
1008 | break; |
1009 | case MD_EXCEPTION_CODE_MAC_X86_INTO: |
1010 | reason.append("EXC_I386_INTO" ); |
1011 | break; |
1012 | case MD_EXCEPTION_CODE_MAC_X86_NOEXT: |
1013 | reason.append("EXC_I386_NOEXT" ); |
1014 | break; |
1015 | case MD_EXCEPTION_CODE_MAC_X86_EXTOVR: |
1016 | reason.append("EXC_I386_EXTOVR" ); |
1017 | break; |
1018 | case MD_EXCEPTION_CODE_MAC_X86_EXTERR: |
1019 | reason.append("EXC_I386_EXTERR" ); |
1020 | break; |
1021 | case MD_EXCEPTION_CODE_MAC_X86_EMERR: |
1022 | reason.append("EXC_I386_EMERR" ); |
1023 | break; |
1024 | case MD_EXCEPTION_CODE_MAC_X86_BOUND: |
1025 | reason.append("EXC_I386_BOUND" ); |
1026 | break; |
1027 | case MD_EXCEPTION_CODE_MAC_X86_SSEEXTERR: |
1028 | reason.append("EXC_I386_SSEEXTERR" ); |
1029 | break; |
1030 | default: |
1031 | reason.append(flags_string); |
1032 | BPLOG(INFO) << "Unknown exception reason " << reason; |
1033 | break; |
1034 | } |
1035 | break; |
1036 | } |
1037 | default: |
1038 | reason.append(flags_string); |
1039 | BPLOG(INFO) << "Unknown exception reason " << reason; |
1040 | break; |
1041 | } |
1042 | break; |
1043 | case MD_EXCEPTION_MAC_EMULATION: |
1044 | reason = "EXC_EMULATION / " ; |
1045 | reason.append(flags_string); |
1046 | break; |
1047 | case MD_EXCEPTION_MAC_SOFTWARE: |
1048 | reason = "EXC_SOFTWARE / " ; |
1049 | switch (exception_flags) { |
1050 | case MD_EXCEPTION_CODE_MAC_ABORT: |
1051 | reason.append("SIGABRT" ); |
1052 | break; |
1053 | case MD_EXCEPTION_CODE_MAC_NS_EXCEPTION: |
1054 | reason.append("UNCAUGHT_NS_EXCEPTION" ); |
1055 | break; |
1056 | // These are ppc only but shouldn't be a problem as they're |
1057 | // unused on x86 |
1058 | case MD_EXCEPTION_CODE_MAC_PPC_TRAP: |
1059 | reason.append("EXC_PPC_TRAP" ); |
1060 | break; |
1061 | case MD_EXCEPTION_CODE_MAC_PPC_MIGRATE: |
1062 | reason.append("EXC_PPC_MIGRATE" ); |
1063 | break; |
1064 | default: |
1065 | reason.append(flags_string); |
1066 | BPLOG(INFO) << "Unknown exception reason " << reason; |
1067 | break; |
1068 | } |
1069 | break; |
1070 | case MD_EXCEPTION_MAC_BREAKPOINT: |
1071 | reason = "EXC_BREAKPOINT / " ; |
1072 | switch (raw_system_info->processor_architecture) { |
1073 | case MD_CPU_ARCHITECTURE_ARM: |
1074 | case MD_CPU_ARCHITECTURE_ARM64_OLD: { |
1075 | switch (exception_flags) { |
1076 | case MD_EXCEPTION_CODE_MAC_ARM_DA_ALIGN: |
1077 | reason.append("EXC_ARM_DA_ALIGN" ); |
1078 | break; |
1079 | case MD_EXCEPTION_CODE_MAC_ARM_DA_DEBUG: |
1080 | reason.append("EXC_ARM_DA_DEBUG" ); |
1081 | break; |
1082 | case MD_EXCEPTION_CODE_MAC_ARM_BREAKPOINT: |
1083 | reason.append("EXC_ARM_BREAKPOINT" ); |
1084 | break; |
1085 | default: |
1086 | reason.append(flags_string); |
1087 | BPLOG(INFO) << "Unknown exception reason " << reason; |
1088 | break; |
1089 | } |
1090 | break; |
1091 | } |
1092 | case MD_CPU_ARCHITECTURE_PPC: { |
1093 | switch (exception_flags) { |
1094 | case MD_EXCEPTION_CODE_MAC_PPC_BREAKPOINT: |
1095 | reason.append("EXC_PPC_BREAKPOINT" ); |
1096 | break; |
1097 | default: |
1098 | reason.append(flags_string); |
1099 | BPLOG(INFO) << "Unknown exception reason " << reason; |
1100 | break; |
1101 | } |
1102 | break; |
1103 | } |
1104 | case MD_CPU_ARCHITECTURE_AMD64: |
1105 | case MD_CPU_ARCHITECTURE_X86: { |
1106 | switch (exception_flags) { |
1107 | case MD_EXCEPTION_CODE_MAC_X86_SGL: |
1108 | reason.append("EXC_I386_SGL" ); |
1109 | break; |
1110 | case MD_EXCEPTION_CODE_MAC_X86_BPT: |
1111 | reason.append("EXC_I386_BPT" ); |
1112 | break; |
1113 | default: |
1114 | reason.append(flags_string); |
1115 | BPLOG(INFO) << "Unknown exception reason " << reason; |
1116 | break; |
1117 | } |
1118 | break; |
1119 | } |
1120 | default: |
1121 | reason.append(flags_string); |
1122 | BPLOG(INFO) << "Unknown exception reason " << reason; |
1123 | break; |
1124 | } |
1125 | break; |
1126 | case MD_EXCEPTION_MAC_SYSCALL: |
1127 | reason = "EXC_SYSCALL / " ; |
1128 | reason.append(flags_string); |
1129 | break; |
1130 | case MD_EXCEPTION_MAC_MACH_SYSCALL: |
1131 | reason = "EXC_MACH_SYSCALL / " ; |
1132 | reason.append(flags_string); |
1133 | break; |
1134 | case MD_EXCEPTION_MAC_RPC_ALERT: |
1135 | reason = "EXC_RPC_ALERT / " ; |
1136 | reason.append(flags_string); |
1137 | break; |
1138 | case MD_EXCEPTION_MAC_SIMULATED: |
1139 | reason = "Simulated Exception" ; |
1140 | break; |
1141 | case MD_NS_EXCEPTION_SIMULATED: |
1142 | reason = "Uncaught NSException" ; |
1143 | break; |
1144 | } |
1145 | break; |
1146 | } |
1147 | |
1148 | case MD_OS_WIN32_NT: |
1149 | case MD_OS_WIN32_WINDOWS: { |
1150 | switch (exception_code) { |
1151 | case MD_EXCEPTION_CODE_WIN_CONTROL_C: |
1152 | reason = "DBG_CONTROL_C" ; |
1153 | break; |
1154 | case MD_EXCEPTION_CODE_WIN_GUARD_PAGE_VIOLATION: |
1155 | reason = "EXCEPTION_GUARD_PAGE" ; |
1156 | break; |
1157 | case MD_EXCEPTION_CODE_WIN_DATATYPE_MISALIGNMENT: |
1158 | reason = "EXCEPTION_DATATYPE_MISALIGNMENT" ; |
1159 | break; |
1160 | case MD_EXCEPTION_CODE_WIN_BREAKPOINT: |
1161 | reason = "EXCEPTION_BREAKPOINT" ; |
1162 | break; |
1163 | case MD_EXCEPTION_CODE_WIN_SINGLE_STEP: |
1164 | reason = "EXCEPTION_SINGLE_STEP" ; |
1165 | break; |
1166 | case MD_EXCEPTION_CODE_WIN_ACCESS_VIOLATION: |
1167 | // For EXCEPTION_ACCESS_VIOLATION, Windows puts the address that |
1168 | // caused the fault in exception_information[1]. |
1169 | // exception_information[0] is 0 if the violation was caused by |
1170 | // an attempt to read data, 1 if it was an attempt to write data, |
1171 | // and 8 if this was a data execution violation. |
1172 | // This information is useful in addition to the code address, which |
1173 | // will be present in the crash thread's instruction field anyway. |
1174 | if (raw_exception->exception_record.number_parameters >= 1) { |
1175 | MDAccessViolationTypeWin av_type = |
1176 | static_cast<MDAccessViolationTypeWin> |
1177 | (raw_exception->exception_record.exception_information[0]); |
1178 | switch (av_type) { |
1179 | case MD_ACCESS_VIOLATION_WIN_READ: |
1180 | reason = "EXCEPTION_ACCESS_VIOLATION_READ" ; |
1181 | break; |
1182 | case MD_ACCESS_VIOLATION_WIN_WRITE: |
1183 | reason = "EXCEPTION_ACCESS_VIOLATION_WRITE" ; |
1184 | break; |
1185 | case MD_ACCESS_VIOLATION_WIN_EXEC: |
1186 | reason = "EXCEPTION_ACCESS_VIOLATION_EXEC" ; |
1187 | break; |
1188 | default: |
1189 | reason = "EXCEPTION_ACCESS_VIOLATION" ; |
1190 | break; |
1191 | } |
1192 | } else { |
1193 | reason = "EXCEPTION_ACCESS_VIOLATION" ; |
1194 | } |
1195 | if (address && |
1196 | raw_exception->exception_record.number_parameters >= 2) { |
1197 | *address = |
1198 | raw_exception->exception_record.exception_information[1]; |
1199 | } |
1200 | break; |
1201 | case MD_EXCEPTION_CODE_WIN_IN_PAGE_ERROR: |
1202 | // For EXCEPTION_IN_PAGE_ERROR, Windows puts the address that |
1203 | // caused the fault in exception_information[1]. |
1204 | // exception_information[0] is 0 if the violation was caused by |
1205 | // an attempt to read data, 1 if it was an attempt to write data, |
1206 | // and 8 if this was a data execution violation. |
1207 | // exception_information[2] contains the underlying NTSTATUS code, |
1208 | // which is the explanation for why this error occured. |
1209 | // This information is useful in addition to the code address, which |
1210 | // will be present in the crash thread's instruction field anyway. |
1211 | if (raw_exception->exception_record.number_parameters >= 1) { |
1212 | MDInPageErrorTypeWin av_type = |
1213 | static_cast<MDInPageErrorTypeWin> |
1214 | (raw_exception->exception_record.exception_information[0]); |
1215 | switch (av_type) { |
1216 | case MD_IN_PAGE_ERROR_WIN_READ: |
1217 | reason = "EXCEPTION_IN_PAGE_ERROR_READ" ; |
1218 | break; |
1219 | case MD_IN_PAGE_ERROR_WIN_WRITE: |
1220 | reason = "EXCEPTION_IN_PAGE_ERROR_WRITE" ; |
1221 | break; |
1222 | case MD_IN_PAGE_ERROR_WIN_EXEC: |
1223 | reason = "EXCEPTION_IN_PAGE_ERROR_EXEC" ; |
1224 | break; |
1225 | default: |
1226 | reason = "EXCEPTION_IN_PAGE_ERROR" ; |
1227 | break; |
1228 | } |
1229 | } else { |
1230 | reason = "EXCEPTION_IN_PAGE_ERROR" ; |
1231 | } |
1232 | if (address && |
1233 | raw_exception->exception_record.number_parameters >= 2) { |
1234 | *address = |
1235 | raw_exception->exception_record.exception_information[1]; |
1236 | } |
1237 | if (raw_exception->exception_record.number_parameters >= 3) { |
1238 | uint32_t ntstatus = |
1239 | static_cast<uint32_t> |
1240 | (raw_exception->exception_record.exception_information[2]); |
1241 | reason.append(" / " ); |
1242 | reason.append(NTStatusToString(ntstatus)); |
1243 | } |
1244 | break; |
1245 | case MD_EXCEPTION_CODE_WIN_INVALID_HANDLE: |
1246 | reason = "EXCEPTION_INVALID_HANDLE" ; |
1247 | break; |
1248 | case MD_EXCEPTION_CODE_WIN_ILLEGAL_INSTRUCTION: |
1249 | reason = "EXCEPTION_ILLEGAL_INSTRUCTION" ; |
1250 | break; |
1251 | case MD_EXCEPTION_CODE_WIN_NONCONTINUABLE_EXCEPTION: |
1252 | reason = "EXCEPTION_NONCONTINUABLE_EXCEPTION" ; |
1253 | break; |
1254 | case MD_EXCEPTION_CODE_WIN_INVALID_DISPOSITION: |
1255 | reason = "EXCEPTION_INVALID_DISPOSITION" ; |
1256 | break; |
1257 | case MD_EXCEPTION_CODE_WIN_ARRAY_BOUNDS_EXCEEDED: |
1258 | reason = "EXCEPTION_BOUNDS_EXCEEDED" ; |
1259 | break; |
1260 | case MD_EXCEPTION_CODE_WIN_FLOAT_DENORMAL_OPERAND: |
1261 | reason = "EXCEPTION_FLT_DENORMAL_OPERAND" ; |
1262 | break; |
1263 | case MD_EXCEPTION_CODE_WIN_FLOAT_DIVIDE_BY_ZERO: |
1264 | reason = "EXCEPTION_FLT_DIVIDE_BY_ZERO" ; |
1265 | break; |
1266 | case MD_EXCEPTION_CODE_WIN_FLOAT_INEXACT_RESULT: |
1267 | reason = "EXCEPTION_FLT_INEXACT_RESULT" ; |
1268 | break; |
1269 | case MD_EXCEPTION_CODE_WIN_FLOAT_INVALID_OPERATION: |
1270 | reason = "EXCEPTION_FLT_INVALID_OPERATION" ; |
1271 | break; |
1272 | case MD_EXCEPTION_CODE_WIN_FLOAT_OVERFLOW: |
1273 | reason = "EXCEPTION_FLT_OVERFLOW" ; |
1274 | break; |
1275 | case MD_EXCEPTION_CODE_WIN_FLOAT_STACK_CHECK: |
1276 | reason = "EXCEPTION_FLT_STACK_CHECK" ; |
1277 | break; |
1278 | case MD_EXCEPTION_CODE_WIN_FLOAT_UNDERFLOW: |
1279 | reason = "EXCEPTION_FLT_UNDERFLOW" ; |
1280 | break; |
1281 | case MD_EXCEPTION_CODE_WIN_INTEGER_DIVIDE_BY_ZERO: |
1282 | reason = "EXCEPTION_INT_DIVIDE_BY_ZERO" ; |
1283 | break; |
1284 | case MD_EXCEPTION_CODE_WIN_INTEGER_OVERFLOW: |
1285 | reason = "EXCEPTION_INT_OVERFLOW" ; |
1286 | break; |
1287 | case MD_EXCEPTION_CODE_WIN_PRIVILEGED_INSTRUCTION: |
1288 | reason = "EXCEPTION_PRIV_INSTRUCTION" ; |
1289 | break; |
1290 | case MD_EXCEPTION_CODE_WIN_STACK_OVERFLOW: |
1291 | reason = "EXCEPTION_STACK_OVERFLOW" ; |
1292 | break; |
1293 | case MD_EXCEPTION_CODE_WIN_BAD_FUNCTION_TABLE: |
1294 | reason = "EXCEPTION_BAD_FUNCTION_TABLE" ; |
1295 | break; |
1296 | case MD_EXCEPTION_CODE_WIN_POSSIBLE_DEADLOCK: |
1297 | reason = "EXCEPTION_POSSIBLE_DEADLOCK" ; |
1298 | break; |
1299 | case MD_EXCEPTION_CODE_WIN_STACK_BUFFER_OVERRUN: |
1300 | reason = "EXCEPTION_STACK_BUFFER_OVERRUN" ; |
1301 | break; |
1302 | case MD_EXCEPTION_CODE_WIN_HEAP_CORRUPTION: |
1303 | reason = "EXCEPTION_HEAP_CORRUPTION" ; |
1304 | break; |
1305 | case MD_EXCEPTION_OUT_OF_MEMORY: |
1306 | reason = "Out of Memory" ; |
1307 | break; |
1308 | case MD_EXCEPTION_CODE_WIN_UNHANDLED_CPP_EXCEPTION: |
1309 | reason = "Unhandled C++ Exception" ; |
1310 | break; |
1311 | case MD_EXCEPTION_CODE_WIN_SIMULATED: |
1312 | reason = "Simulated Exception" ; |
1313 | break; |
1314 | default: |
1315 | BPLOG(INFO) << "Unknown exception reason " << reason; |
1316 | break; |
1317 | } |
1318 | break; |
1319 | } |
1320 | |
1321 | case MD_OS_ANDROID: |
1322 | case MD_OS_LINUX: { |
1323 | switch (exception_code) { |
1324 | case MD_EXCEPTION_CODE_LIN_SIGHUP: |
1325 | reason = "SIGHUP" ; |
1326 | break; |
1327 | case MD_EXCEPTION_CODE_LIN_SIGINT: |
1328 | reason = "SIGINT" ; |
1329 | break; |
1330 | case MD_EXCEPTION_CODE_LIN_SIGQUIT: |
1331 | reason = "SIGQUIT" ; |
1332 | break; |
1333 | case MD_EXCEPTION_CODE_LIN_SIGILL: |
1334 | reason = "SIGILL / " ; |
1335 | switch (exception_flags) { |
1336 | case MD_EXCEPTION_FLAG_LIN_ILL_ILLOPC: |
1337 | reason.append("ILL_ILLOPC" ); |
1338 | break; |
1339 | case MD_EXCEPTION_FLAG_LIN_ILL_ILLOPN: |
1340 | reason.append("ILL_ILLOPN" ); |
1341 | break; |
1342 | case MD_EXCEPTION_FLAG_LIN_ILL_ILLADR: |
1343 | reason.append("ILL_ILLADR" ); |
1344 | break; |
1345 | case MD_EXCEPTION_FLAG_LIN_ILL_ILLTRP: |
1346 | reason.append("ILL_ILLTRP" ); |
1347 | break; |
1348 | case MD_EXCEPTION_FLAG_LIN_ILL_PRVOPC: |
1349 | reason.append("ILL_PRVOPC" ); |
1350 | break; |
1351 | case MD_EXCEPTION_FLAG_LIN_ILL_PRVREG: |
1352 | reason.append("ILL_PRVREG" ); |
1353 | break; |
1354 | case MD_EXCEPTION_FLAG_LIN_ILL_COPROC: |
1355 | reason.append("ILL_COPROC" ); |
1356 | break; |
1357 | case MD_EXCEPTION_FLAG_LIN_ILL_BADSTK: |
1358 | reason.append("ILL_BADSTK" ); |
1359 | break; |
1360 | default: |
1361 | reason.append(flags_string); |
1362 | BPLOG(INFO) << "Unknown exception reason " << reason; |
1363 | break; |
1364 | } |
1365 | break; |
1366 | case MD_EXCEPTION_CODE_LIN_SIGTRAP: |
1367 | reason = "SIGTRAP" ; |
1368 | break; |
1369 | case MD_EXCEPTION_CODE_LIN_SIGABRT: |
1370 | reason = "SIGABRT" ; |
1371 | break; |
1372 | case MD_EXCEPTION_CODE_LIN_SIGBUS: |
1373 | reason = "SIGBUS / " ; |
1374 | switch (exception_flags) { |
1375 | case MD_EXCEPTION_FLAG_LIN_BUS_ADRALN: |
1376 | reason.append("BUS_ADRALN" ); |
1377 | break; |
1378 | case MD_EXCEPTION_FLAG_LIN_BUS_ADRERR: |
1379 | reason.append("BUS_ADRERR" ); |
1380 | break; |
1381 | case MD_EXCEPTION_FLAG_LIN_BUS_OBJERR: |
1382 | reason.append("BUS_OBJERR" ); |
1383 | break; |
1384 | case MD_EXCEPTION_FLAG_LIN_BUS_MCEERR_AR: |
1385 | reason.append("BUS_MCEERR_AR" ); |
1386 | break; |
1387 | case MD_EXCEPTION_FLAG_LIN_BUS_MCEERR_AO: |
1388 | reason.append("BUS_MCEERR_AO" ); |
1389 | break; |
1390 | default: |
1391 | reason.append(flags_string); |
1392 | BPLOG(INFO) << "Unknown exception reason " << reason; |
1393 | break; |
1394 | } |
1395 | break; |
1396 | case MD_EXCEPTION_CODE_LIN_SIGFPE: |
1397 | reason = "SIGFPE / " ; |
1398 | switch (exception_flags) { |
1399 | case MD_EXCEPTION_FLAG_LIN_FPE_INTDIV: |
1400 | reason.append("FPE_INTDIV" ); |
1401 | break; |
1402 | case MD_EXCEPTION_FLAG_LIN_FPE_INTOVF: |
1403 | reason.append("FPE_INTOVF" ); |
1404 | break; |
1405 | case MD_EXCEPTION_FLAG_LIN_FPE_FLTDIV: |
1406 | reason.append("FPE_FLTDIV" ); |
1407 | break; |
1408 | case MD_EXCEPTION_FLAG_LIN_FPE_FLTOVF: |
1409 | reason.append("FPE_FLTOVF" ); |
1410 | break; |
1411 | case MD_EXCEPTION_FLAG_LIN_FPE_FLTUND: |
1412 | reason.append("FPE_FLTUND" ); |
1413 | break; |
1414 | case MD_EXCEPTION_FLAG_LIN_FPE_FLTRES: |
1415 | reason.append("FPE_FLTRES" ); |
1416 | break; |
1417 | case MD_EXCEPTION_FLAG_LIN_FPE_FLTINV: |
1418 | reason.append("FPE_FLTINV" ); |
1419 | break; |
1420 | case MD_EXCEPTION_FLAG_LIN_FPE_FLTSUB: |
1421 | reason.append("FPE_FLTSUB" ); |
1422 | break; |
1423 | default: |
1424 | reason.append(flags_string); |
1425 | BPLOG(INFO) << "Unknown exception reason " << reason; |
1426 | break; |
1427 | } |
1428 | break; |
1429 | case MD_EXCEPTION_CODE_LIN_SIGKILL: |
1430 | reason = "SIGKILL" ; |
1431 | break; |
1432 | case MD_EXCEPTION_CODE_LIN_SIGUSR1: |
1433 | reason = "SIGUSR1" ; |
1434 | break; |
1435 | case MD_EXCEPTION_CODE_LIN_SIGSEGV: |
1436 | reason = "SIGSEGV /" ; |
1437 | switch (exception_flags) { |
1438 | case MD_EXCEPTION_FLAG_LIN_SEGV_MAPERR: |
1439 | reason.append("SEGV_MAPERR" ); |
1440 | break; |
1441 | case MD_EXCEPTION_FLAG_LIN_SEGV_ACCERR: |
1442 | reason.append("SEGV_ACCERR" ); |
1443 | break; |
1444 | case MD_EXCEPTION_FLAG_LIN_SEGV_BNDERR: |
1445 | reason.append("SEGV_BNDERR" ); |
1446 | break; |
1447 | case MD_EXCEPTION_FLAG_LIN_SEGV_PKUERR: |
1448 | reason.append("SEGV_PKUERR" ); |
1449 | break; |
1450 | default: |
1451 | reason.append(flags_string); |
1452 | BPLOG(INFO) << "Unknown exception reason " << reason; |
1453 | break; |
1454 | } |
1455 | break; |
1456 | case MD_EXCEPTION_CODE_LIN_SIGUSR2: |
1457 | reason = "SIGUSR2" ; |
1458 | break; |
1459 | case MD_EXCEPTION_CODE_LIN_SIGPIPE: |
1460 | reason = "SIGPIPE" ; |
1461 | break; |
1462 | case MD_EXCEPTION_CODE_LIN_SIGALRM: |
1463 | reason = "SIGALRM" ; |
1464 | break; |
1465 | case MD_EXCEPTION_CODE_LIN_SIGTERM: |
1466 | reason = "SIGTERM" ; |
1467 | break; |
1468 | case MD_EXCEPTION_CODE_LIN_SIGSTKFLT: |
1469 | reason = "SIGSTKFLT" ; |
1470 | break; |
1471 | case MD_EXCEPTION_CODE_LIN_SIGCHLD: |
1472 | reason = "SIGCHLD" ; |
1473 | break; |
1474 | case MD_EXCEPTION_CODE_LIN_SIGCONT: |
1475 | reason = "SIGCONT" ; |
1476 | break; |
1477 | case MD_EXCEPTION_CODE_LIN_SIGSTOP: |
1478 | reason = "SIGSTOP" ; |
1479 | break; |
1480 | case MD_EXCEPTION_CODE_LIN_SIGTSTP: |
1481 | reason = "SIGTSTP" ; |
1482 | break; |
1483 | case MD_EXCEPTION_CODE_LIN_SIGTTIN: |
1484 | reason = "SIGTTIN" ; |
1485 | break; |
1486 | case MD_EXCEPTION_CODE_LIN_SIGTTOU: |
1487 | reason = "SIGTTOU" ; |
1488 | break; |
1489 | case MD_EXCEPTION_CODE_LIN_SIGURG: |
1490 | reason = "SIGURG" ; |
1491 | break; |
1492 | case MD_EXCEPTION_CODE_LIN_SIGXCPU: |
1493 | reason = "SIGXCPU" ; |
1494 | break; |
1495 | case MD_EXCEPTION_CODE_LIN_SIGXFSZ: |
1496 | reason = "SIGXFSZ" ; |
1497 | break; |
1498 | case MD_EXCEPTION_CODE_LIN_SIGVTALRM: |
1499 | reason = "SIGVTALRM" ; |
1500 | break; |
1501 | case MD_EXCEPTION_CODE_LIN_SIGPROF: |
1502 | reason = "SIGPROF" ; |
1503 | break; |
1504 | case MD_EXCEPTION_CODE_LIN_SIGWINCH: |
1505 | reason = "SIGWINCH" ; |
1506 | break; |
1507 | case MD_EXCEPTION_CODE_LIN_SIGIO: |
1508 | reason = "SIGIO" ; |
1509 | break; |
1510 | case MD_EXCEPTION_CODE_LIN_SIGPWR: |
1511 | reason = "SIGPWR" ; |
1512 | break; |
1513 | case MD_EXCEPTION_CODE_LIN_SIGSYS: |
1514 | reason = "SIGSYS" ; |
1515 | break; |
1516 | case MD_EXCEPTION_CODE_LIN_DUMP_REQUESTED: |
1517 | reason = "DUMP_REQUESTED" ; |
1518 | break; |
1519 | default: |
1520 | BPLOG(INFO) << "Unknown exception reason " << reason; |
1521 | break; |
1522 | } |
1523 | break; |
1524 | } |
1525 | |
1526 | case MD_OS_SOLARIS: { |
1527 | switch (exception_code) { |
1528 | case MD_EXCEPTION_CODE_SOL_SIGHUP: |
1529 | reason = "SIGHUP" ; |
1530 | break; |
1531 | case MD_EXCEPTION_CODE_SOL_SIGINT: |
1532 | reason = "SIGINT" ; |
1533 | break; |
1534 | case MD_EXCEPTION_CODE_SOL_SIGQUIT: |
1535 | reason = "SIGQUIT" ; |
1536 | break; |
1537 | case MD_EXCEPTION_CODE_SOL_SIGILL: |
1538 | reason = "SIGILL" ; |
1539 | break; |
1540 | case MD_EXCEPTION_CODE_SOL_SIGTRAP: |
1541 | reason = "SIGTRAP" ; |
1542 | break; |
1543 | case MD_EXCEPTION_CODE_SOL_SIGIOT: |
1544 | reason = "SIGIOT | SIGABRT" ; |
1545 | break; |
1546 | case MD_EXCEPTION_CODE_SOL_SIGEMT: |
1547 | reason = "SIGEMT" ; |
1548 | break; |
1549 | case MD_EXCEPTION_CODE_SOL_SIGFPE: |
1550 | reason = "SIGFPE" ; |
1551 | break; |
1552 | case MD_EXCEPTION_CODE_SOL_SIGKILL: |
1553 | reason = "SIGKILL" ; |
1554 | break; |
1555 | case MD_EXCEPTION_CODE_SOL_SIGBUS: |
1556 | reason = "SIGBUS" ; |
1557 | break; |
1558 | case MD_EXCEPTION_CODE_SOL_SIGSEGV: |
1559 | reason = "SIGSEGV" ; |
1560 | break; |
1561 | case MD_EXCEPTION_CODE_SOL_SIGSYS: |
1562 | reason = "SIGSYS" ; |
1563 | break; |
1564 | case MD_EXCEPTION_CODE_SOL_SIGPIPE: |
1565 | reason = "SIGPIPE" ; |
1566 | break; |
1567 | case MD_EXCEPTION_CODE_SOL_SIGALRM: |
1568 | reason = "SIGALRM" ; |
1569 | break; |
1570 | case MD_EXCEPTION_CODE_SOL_SIGTERM: |
1571 | reason = "SIGTERM" ; |
1572 | break; |
1573 | case MD_EXCEPTION_CODE_SOL_SIGUSR1: |
1574 | reason = "SIGUSR1" ; |
1575 | break; |
1576 | case MD_EXCEPTION_CODE_SOL_SIGUSR2: |
1577 | reason = "SIGUSR2" ; |
1578 | break; |
1579 | case MD_EXCEPTION_CODE_SOL_SIGCLD: |
1580 | reason = "SIGCLD | SIGCHLD" ; |
1581 | break; |
1582 | case MD_EXCEPTION_CODE_SOL_SIGPWR: |
1583 | reason = "SIGPWR" ; |
1584 | break; |
1585 | case MD_EXCEPTION_CODE_SOL_SIGWINCH: |
1586 | reason = "SIGWINCH" ; |
1587 | break; |
1588 | case MD_EXCEPTION_CODE_SOL_SIGURG: |
1589 | reason = "SIGURG" ; |
1590 | break; |
1591 | case MD_EXCEPTION_CODE_SOL_SIGPOLL: |
1592 | reason = "SIGPOLL | SIGIO" ; |
1593 | break; |
1594 | case MD_EXCEPTION_CODE_SOL_SIGSTOP: |
1595 | reason = "SIGSTOP" ; |
1596 | break; |
1597 | case MD_EXCEPTION_CODE_SOL_SIGTSTP: |
1598 | reason = "SIGTSTP" ; |
1599 | break; |
1600 | case MD_EXCEPTION_CODE_SOL_SIGCONT: |
1601 | reason = "SIGCONT" ; |
1602 | break; |
1603 | case MD_EXCEPTION_CODE_SOL_SIGTTIN: |
1604 | reason = "SIGTTIN" ; |
1605 | break; |
1606 | case MD_EXCEPTION_CODE_SOL_SIGTTOU: |
1607 | reason = "SIGTTOU" ; |
1608 | break; |
1609 | case MD_EXCEPTION_CODE_SOL_SIGVTALRM: |
1610 | reason = "SIGVTALRM" ; |
1611 | break; |
1612 | case MD_EXCEPTION_CODE_SOL_SIGPROF: |
1613 | reason = "SIGPROF" ; |
1614 | break; |
1615 | case MD_EXCEPTION_CODE_SOL_SIGXCPU: |
1616 | reason = "SIGXCPU" ; |
1617 | break; |
1618 | case MD_EXCEPTION_CODE_SOL_SIGXFSZ: |
1619 | reason = "SIGXFSZ" ; |
1620 | break; |
1621 | case MD_EXCEPTION_CODE_SOL_SIGWAITING: |
1622 | reason = "SIGWAITING" ; |
1623 | break; |
1624 | case MD_EXCEPTION_CODE_SOL_SIGLWP: |
1625 | reason = "SIGLWP" ; |
1626 | break; |
1627 | case MD_EXCEPTION_CODE_SOL_SIGFREEZE: |
1628 | reason = "SIGFREEZE" ; |
1629 | break; |
1630 | case MD_EXCEPTION_CODE_SOL_SIGTHAW: |
1631 | reason = "SIGTHAW" ; |
1632 | break; |
1633 | case MD_EXCEPTION_CODE_SOL_SIGCANCEL: |
1634 | reason = "SIGCANCEL" ; |
1635 | break; |
1636 | case MD_EXCEPTION_CODE_SOL_SIGLOST: |
1637 | reason = "SIGLOST" ; |
1638 | break; |
1639 | case MD_EXCEPTION_CODE_SOL_SIGXRES: |
1640 | reason = "SIGXRES" ; |
1641 | break; |
1642 | case MD_EXCEPTION_CODE_SOL_SIGJVM1: |
1643 | reason = "SIGJVM1" ; |
1644 | break; |
1645 | case MD_EXCEPTION_CODE_SOL_SIGJVM2: |
1646 | reason = "SIGJVM2" ; |
1647 | break; |
1648 | default: |
1649 | BPLOG(INFO) << "Unknown exception reason " << reason; |
1650 | break; |
1651 | } |
1652 | break; |
1653 | } |
1654 | |
1655 | case MD_OS_PS3: { |
1656 | switch (exception_code) { |
1657 | case MD_EXCEPTION_CODE_PS3_UNKNOWN: |
1658 | reason = "UNKNOWN" ; |
1659 | break; |
1660 | case MD_EXCEPTION_CODE_PS3_TRAP_EXCEP: |
1661 | reason = "TRAP_EXCEP" ; |
1662 | break; |
1663 | case MD_EXCEPTION_CODE_PS3_PRIV_INSTR: |
1664 | reason = "PRIV_INSTR" ; |
1665 | break; |
1666 | case MD_EXCEPTION_CODE_PS3_ILLEGAL_INSTR: |
1667 | reason = "ILLEGAL_INSTR" ; |
1668 | break; |
1669 | case MD_EXCEPTION_CODE_PS3_INSTR_STORAGE: |
1670 | reason = "INSTR_STORAGE" ; |
1671 | break; |
1672 | case MD_EXCEPTION_CODE_PS3_INSTR_SEGMENT: |
1673 | reason = "INSTR_SEGMENT" ; |
1674 | break; |
1675 | case MD_EXCEPTION_CODE_PS3_DATA_STORAGE: |
1676 | reason = "DATA_STORAGE" ; |
1677 | break; |
1678 | case MD_EXCEPTION_CODE_PS3_DATA_SEGMENT: |
1679 | reason = "DATA_SEGMENT" ; |
1680 | break; |
1681 | case MD_EXCEPTION_CODE_PS3_FLOAT_POINT: |
1682 | reason = "FLOAT_POINT" ; |
1683 | break; |
1684 | case MD_EXCEPTION_CODE_PS3_DABR_MATCH: |
1685 | reason = "DABR_MATCH" ; |
1686 | break; |
1687 | case MD_EXCEPTION_CODE_PS3_ALIGN_EXCEP: |
1688 | reason = "ALIGN_EXCEP" ; |
1689 | break; |
1690 | case MD_EXCEPTION_CODE_PS3_MEMORY_ACCESS: |
1691 | reason = "MEMORY_ACCESS" ; |
1692 | break; |
1693 | case MD_EXCEPTION_CODE_PS3_COPRO_ALIGN: |
1694 | reason = "COPRO_ALIGN" ; |
1695 | break; |
1696 | case MD_EXCEPTION_CODE_PS3_COPRO_INVALID_COM: |
1697 | reason = "COPRO_INVALID_COM" ; |
1698 | break; |
1699 | case MD_EXCEPTION_CODE_PS3_COPRO_ERR: |
1700 | reason = "COPRO_ERR" ; |
1701 | break; |
1702 | case MD_EXCEPTION_CODE_PS3_COPRO_FIR: |
1703 | reason = "COPRO_FIR" ; |
1704 | break; |
1705 | case MD_EXCEPTION_CODE_PS3_COPRO_DATA_SEGMENT: |
1706 | reason = "COPRO_DATA_SEGMENT" ; |
1707 | break; |
1708 | case MD_EXCEPTION_CODE_PS3_COPRO_DATA_STORAGE: |
1709 | reason = "COPRO_DATA_STORAGE" ; |
1710 | break; |
1711 | case MD_EXCEPTION_CODE_PS3_COPRO_STOP_INSTR: |
1712 | reason = "COPRO_STOP_INSTR" ; |
1713 | break; |
1714 | case MD_EXCEPTION_CODE_PS3_COPRO_HALT_INSTR: |
1715 | reason = "COPRO_HALT_INSTR" ; |
1716 | break; |
1717 | case MD_EXCEPTION_CODE_PS3_COPRO_HALTINST_UNKNOWN: |
1718 | reason = "COPRO_HALTINSTR_UNKNOWN" ; |
1719 | break; |
1720 | case MD_EXCEPTION_CODE_PS3_COPRO_MEMORY_ACCESS: |
1721 | reason = "COPRO_MEMORY_ACCESS" ; |
1722 | break; |
1723 | case MD_EXCEPTION_CODE_PS3_GRAPHIC: |
1724 | reason = "GRAPHIC" ; |
1725 | break; |
1726 | default: |
1727 | BPLOG(INFO) << "Unknown exception reason " << reason; |
1728 | break; |
1729 | } |
1730 | break; |
1731 | } |
1732 | |
1733 | default: { |
1734 | BPLOG(INFO) << "Unknown exception reason " << reason; |
1735 | break; |
1736 | } |
1737 | } |
1738 | |
1739 | if (address) { |
1740 | *address = GetAddressForArchitecture( |
1741 | static_cast<MDCPUArchitecture>(raw_system_info->processor_architecture), |
1742 | *address); |
1743 | } |
1744 | |
1745 | return reason; |
1746 | } |
1747 | |
1748 | // static |
1749 | string MinidumpProcessor::GetAssertion(Minidump* dump) { |
1750 | MinidumpAssertion* assertion = dump->GetAssertion(); |
1751 | if (!assertion) |
1752 | return "" ; |
1753 | |
1754 | const MDRawAssertionInfo* raw_assertion = assertion->assertion(); |
1755 | if (!raw_assertion) |
1756 | return "" ; |
1757 | |
1758 | string assertion_string; |
1759 | switch (raw_assertion->type) { |
1760 | case MD_ASSERTION_INFO_TYPE_INVALID_PARAMETER: |
1761 | assertion_string = "Invalid parameter passed to library function" ; |
1762 | break; |
1763 | case MD_ASSERTION_INFO_TYPE_PURE_VIRTUAL_CALL: |
1764 | assertion_string = "Pure virtual function called" ; |
1765 | break; |
1766 | default: { |
1767 | char assertion_type[32]; |
1768 | snprintf(assertion_type, sizeof(assertion_type), |
1769 | "0x%08x" , raw_assertion->type); |
1770 | assertion_string = "Unknown assertion type " ; |
1771 | assertion_string += assertion_type; |
1772 | break; |
1773 | } |
1774 | } |
1775 | |
1776 | string expression = assertion->expression(); |
1777 | if (!expression.empty()) { |
1778 | assertion_string.append(" " + expression); |
1779 | } |
1780 | |
1781 | string function = assertion->function(); |
1782 | if (!function.empty()) { |
1783 | assertion_string.append(" in function " + function); |
1784 | } |
1785 | |
1786 | string file = assertion->file(); |
1787 | if (!file.empty()) { |
1788 | assertion_string.append(", in file " + file); |
1789 | } |
1790 | |
1791 | if (raw_assertion->line != 0) { |
1792 | char assertion_line[32]; |
1793 | snprintf(assertion_line, sizeof(assertion_line), "%u" , raw_assertion->line); |
1794 | assertion_string.append(" at line " ); |
1795 | assertion_string.append(assertion_line); |
1796 | } |
1797 | |
1798 | return assertion_string; |
1799 | } |
1800 | |
1801 | } // namespace google_breakpad |
1802 | |