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
49namespace google_breakpad {
50
51MinidumpProcessor::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
59MinidumpProcessor::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
68MinidumpProcessor::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
77MinidumpProcessor::~MinidumpProcessor() {
78 if (own_frame_symbolizer_) delete frame_symbolizer_;
79}
80
81ProcessResult MinidumpProcessor::Process(
82 Minidump* dump, ProcessState* process_state) {
83 assert(dump);
84 assert(process_state);
85
86 process_state->Clear();
87
88 const MDRawHeader* header = 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
352ProcessResult 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.
368static 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
380static 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.
403static 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
523bool 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
611bool 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
704bool 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
730string 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
1749string 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