Left: | ||
Right: |
OLD | NEW |
---|---|
1 // Copyright (c) 2009, Google Inc. | 1 // Copyright (c) 2009, Google Inc. |
2 // All rights reserved. | 2 // All rights reserved. |
3 // | 3 // |
4 // Redistribution and use in source and binary forms, with or without | 4 // Redistribution and use in source and binary forms, with or without |
5 // modification, are permitted provided that the following conditions are | 5 // modification, are permitted provided that the following conditions are |
6 // met: | 6 // met: |
7 // | 7 // |
8 // * Redistributions of source code must retain the above copyright | 8 // * Redistributions of source code must retain the above copyright |
9 // notice, this list of conditions and the following disclaimer. | 9 // notice, this list of conditions and the following disclaimer. |
10 // * Redistributions in binary form must reproduce the above | 10 // * Redistributions in binary form must reproduce the above |
(...skipping 28 matching lines...) Expand all Loading... | |
39 // * You may not call syscalls via the libc wrappers. This rule is a subset | 39 // * You may not call syscalls via the libc wrappers. This rule is a subset |
40 // of the first rule but it bears repeating. We have direct wrappers | 40 // of the first rule but it bears repeating. We have direct wrappers |
41 // around the system calls in linux_syscall_support.h. | 41 // around the system calls in linux_syscall_support.h. |
42 // * You may not malloc. There's an alternative allocator in memory.h and | 42 // * You may not malloc. There's an alternative allocator in memory.h and |
43 // a canonical instance in the LinuxDumper object. We use the placement | 43 // a canonical instance in the LinuxDumper object. We use the placement |
44 // new form to allocate objects and we don't delete them. | 44 // new form to allocate objects and we don't delete them. |
45 | 45 |
46 #include "client/linux/minidump_writer/minidump_writer.h" | 46 #include "client/linux/minidump_writer/minidump_writer.h" |
47 #include "client/minidump_file_writer-inl.h" | 47 #include "client/minidump_file_writer-inl.h" |
48 | 48 |
49 #include <algorithm> | |
50 | |
49 #include <errno.h> | 51 #include <errno.h> |
50 #include <fcntl.h> | 52 #include <fcntl.h> |
51 #include <link.h> | 53 #include <link.h> |
52 #include <stdio.h> | 54 #include <stdio.h> |
53 #include <unistd.h> | 55 #include <unistd.h> |
54 #include <sys/ucontext.h> | 56 #include <sys/ucontext.h> |
55 #include <sys/user.h> | 57 #include <sys/user.h> |
56 #include <sys/utsname.h> | 58 #include <sys/utsname.h> |
57 | 59 |
58 #include "client/minidump_file_writer.h" | 60 #include "client/minidump_file_writer.h" |
(...skipping 301 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
360 : filename_(filename), | 362 : filename_(filename), |
361 siginfo_(&context->siginfo), | 363 siginfo_(&context->siginfo), |
362 ucontext_(&context->context), | 364 ucontext_(&context->context), |
363 #if !defined(__ARM_EABI__) | 365 #if !defined(__ARM_EABI__) |
364 float_state_(&context->float_state), | 366 float_state_(&context->float_state), |
365 #else | 367 #else |
366 //TODO: fix this after fixing ExceptionHandler | 368 //TODO: fix this after fixing ExceptionHandler |
367 float_state_(NULL), | 369 float_state_(NULL), |
368 #endif | 370 #endif |
369 crashing_tid_(context->tid), | 371 crashing_tid_(context->tid), |
370 dumper_(crashing_pid) { | 372 dumper_(crashing_pid), |
373 memory_blocks_(dumper_.allocator()) { | |
371 } | 374 } |
372 | 375 |
373 bool Init() { | 376 bool Init() { |
374 return dumper_.Init() && minidump_writer_.Open(filename_) && | 377 return dumper_.Init() && minidump_writer_.Open(filename_) && |
375 dumper_.ThreadsSuspend(); | 378 dumper_.ThreadsSuspend(); |
376 } | 379 } |
377 | 380 |
378 ~MinidumpWriter() { | 381 ~MinidumpWriter() { |
379 minidump_writer_.Close(); | 382 minidump_writer_.Close(); |
380 dumper_.ThreadsResume(); | 383 dumper_.ThreadsResume(); |
(...skipping 12 matching lines...) Expand all Loading... | |
393 dumper_.CopyFromProcess(&dyn, crashing_tid_, _DYNAMIC+i++, sizeof(dyn)); | 396 dumper_.CopyFromProcess(&dyn, crashing_tid_, _DYNAMIC+i++, sizeof(dyn)); |
394 if (dyn.d_tag == DT_DEBUG) { | 397 if (dyn.d_tag == DT_DEBUG) { |
395 r_debug = (struct r_debug*)dyn.d_un.d_ptr; | 398 r_debug = (struct r_debug*)dyn.d_un.d_ptr; |
396 continue; | 399 continue; |
397 } else if (dyn.d_tag == DT_NULL) | 400 } else if (dyn.d_tag == DT_NULL) |
398 break; | 401 break; |
399 } | 402 } |
400 | 403 |
401 // A minidump file contains a number of tagged streams. This is the number | 404 // A minidump file contains a number of tagged streams. This is the number |
402 // of stream which we write. | 405 // of stream which we write. |
403 const unsigned kNumWriters = 11 + !!r_debug; | 406 unsigned kNumWriters = 12; |
407 if (r_debug) | |
408 ++kNumWriters; | |
mochalatte
2010/09/16 20:50:22
wow, thank you for rewriting this.
| |
404 | 409 |
405 TypedMDRVA<MDRawHeader> header(&minidump_writer_); | 410 TypedMDRVA<MDRawHeader> header(&minidump_writer_); |
406 TypedMDRVA<MDRawDirectory> dir(&minidump_writer_); | 411 TypedMDRVA<MDRawDirectory> dir(&minidump_writer_); |
407 if (!header.Allocate()) | 412 if (!header.Allocate()) |
408 return false; | 413 return false; |
409 if (!dir.AllocateArray(kNumWriters)) | 414 if (!dir.AllocateArray(kNumWriters)) |
410 return false; | 415 return false; |
411 memset(header.get(), 0, sizeof(MDRawHeader)); | 416 memset(header.get(), 0, sizeof(MDRawHeader)); |
412 | 417 |
413 header.get()->signature = MD_HEADER_SIGNATURE; | 418 header.get()->signature = MD_HEADER_SIGNATURE; |
414 header.get()->version = MD_HEADER_VERSION; | 419 header.get()->version = MD_HEADER_VERSION; |
415 header.get()->time_date_stamp = time(NULL); | 420 header.get()->time_date_stamp = time(NULL); |
416 header.get()->stream_count = kNumWriters; | 421 header.get()->stream_count = kNumWriters; |
417 header.get()->stream_directory_rva = dir.position(); | 422 header.get()->stream_directory_rva = dir.position(); |
418 | 423 |
419 unsigned dir_index = 0; | 424 unsigned dir_index = 0; |
420 MDRawDirectory dirent; | 425 MDRawDirectory dirent; |
421 | 426 |
422 if (!WriteThreadListStream(&dirent)) | 427 if (!WriteThreadListStream(&dirent)) |
423 return false; | 428 return false; |
424 dir.CopyIndex(dir_index++, &dirent); | 429 dir.CopyIndex(dir_index++, &dirent); |
425 | 430 |
426 if (!WriteMappings(&dirent)) | 431 if (!WriteMappings(&dirent)) |
427 return false; | 432 return false; |
428 dir.CopyIndex(dir_index++, &dirent); | 433 dir.CopyIndex(dir_index++, &dirent); |
429 | 434 |
435 if (!WriteMemoryListStream(&dirent)) | |
436 return false; | |
437 dir.CopyIndex(dir_index++, &dirent); | |
438 | |
430 if (!WriteExceptionStream(&dirent)) | 439 if (!WriteExceptionStream(&dirent)) |
431 return false; | 440 return false; |
432 dir.CopyIndex(dir_index++, &dirent); | 441 dir.CopyIndex(dir_index++, &dirent); |
433 | 442 |
434 if (!WriteSystemInfoStream(&dirent)) | 443 if (!WriteSystemInfoStream(&dirent)) |
435 return false; | 444 return false; |
436 dir.CopyIndex(dir_index++, &dirent); | 445 dir.CopyIndex(dir_index++, &dirent); |
437 | 446 |
438 dirent.stream_type = MD_LINUX_CPU_INFO; | 447 dirent.stream_type = MD_LINUX_CPU_INFO; |
439 if (!WriteFile(&dirent.location, "/proc/cpuinfo")) | 448 if (!WriteFile(&dirent.location, "/proc/cpuinfo")) |
(...skipping 188 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
628 if (!dumper_.GetStackInfo(&stack, &stack_len, GetStackPointer())) | 637 if (!dumper_.GetStackInfo(&stack, &stack_len, GetStackPointer())) |
629 return false; | 638 return false; |
630 UntypedMDRVA memory(&minidump_writer_); | 639 UntypedMDRVA memory(&minidump_writer_); |
631 if (!memory.Allocate(stack_len)) | 640 if (!memory.Allocate(stack_len)) |
632 return false; | 641 return false; |
633 uint8_t* stack_copy = (uint8_t*) dumper_.allocator()->Alloc(stack_len); | 642 uint8_t* stack_copy = (uint8_t*) dumper_.allocator()->Alloc(stack_len); |
634 dumper_.CopyFromProcess(stack_copy, thread.thread_id, stack, stack_len); | 643 dumper_.CopyFromProcess(stack_copy, thread.thread_id, stack, stack_len); |
635 memory.Copy(stack_copy, stack_len); | 644 memory.Copy(stack_copy, stack_len); |
636 thread.stack.start_of_memory_range = (uintptr_t) (stack); | 645 thread.stack.start_of_memory_range = (uintptr_t) (stack); |
637 thread.stack.memory = memory.location(); | 646 thread.stack.memory = memory.location(); |
647 memory_blocks_.push_back(thread.stack); | |
648 | |
649 // Copy 256 bytes around crashing instruction pointer to minidump. | |
650 const size_t ip_memory_size = 256; | |
mochalatte
2010/09/16 20:50:22
precede constant variable names with k
| |
651 u_int64_t ip = GetInstructionPointer(); | |
652 // Bound it to the upper and lower bounds of the memory map | |
653 // it's contained within. If it's not in mapped memory, | |
654 // don't bother trying to write it. | |
655 bool ip_is_mapped = false; | |
656 MDMemoryDescriptor ip_memory_d; | |
657 for (unsigned i = 0; i < dumper_.mappings().size(); ++i) { | |
658 const MappingInfo& mapping = *dumper_.mappings()[i]; | |
659 if (ip >= mapping.start_addr && | |
660 ip < mapping.start_addr + mapping.size) { | |
661 ip_is_mapped = true; | |
662 // Try to get 128 bytes before and after the IP, but | |
663 // settle for whatever's available. | |
664 ip_memory_d.start_of_memory_range = | |
665 std::min(mapping.start_addr, | |
666 uintptr_t(ip - ip_memory_size / 2)); | |
mochalatte
2010/09/16 20:50:22
i know the order of operations is like elementary
| |
667 ip_memory_d.memory.data_size = | |
668 std::min(ptrdiff_t(ip_memory_size), | |
669 ptrdiff_t(mapping.start_addr + mapping.size | |
670 - ip_memory_d.start_of_memory_range)); | |
671 break; | |
672 } | |
673 } | |
674 | |
675 if (ip_is_mapped) { | |
676 UntypedMDRVA ip_memory(&minidump_writer_); | |
677 if (!ip_memory.Allocate(ip_memory_d.memory.data_size)) | |
678 return false; | |
679 uint8_t* memory_copy = | |
680 (uint8_t*) dumper_.allocator()->Alloc(ip_memory_d.memory.data_size); | |
681 dumper_.CopyFromProcess( | |
682 memory_copy, | |
683 thread.thread_id, | |
684 reinterpret_cast<void*>(ip_memory_d.start_of_memory_range), | |
685 ip_memory_d.memory.data_size); | |
686 ip_memory.Copy(memory_copy, ip_memory_d.memory.data_size); | |
687 ip_memory_d.memory = ip_memory.location(); | |
688 memory_blocks_.push_back(ip_memory_d); | |
689 } | |
690 | |
638 TypedMDRVA<RawContextCPU> cpu(&minidump_writer_); | 691 TypedMDRVA<RawContextCPU> cpu(&minidump_writer_); |
639 if (!cpu.Allocate()) | 692 if (!cpu.Allocate()) |
640 return false; | 693 return false; |
641 my_memset(cpu.get(), 0, sizeof(RawContextCPU)); | 694 my_memset(cpu.get(), 0, sizeof(RawContextCPU)); |
642 CPUFillFromUContext(cpu.get(), ucontext_, float_state_); | 695 CPUFillFromUContext(cpu.get(), ucontext_, float_state_); |
643 PopSeccompStackFrame(cpu.get(), thread, stack_copy); | 696 PopSeccompStackFrame(cpu.get(), thread, stack_copy); |
644 thread.thread_context = cpu.location(); | 697 thread.thread_context = cpu.location(); |
645 crashing_thread_context_ = cpu.location(); | 698 crashing_thread_context_ = cpu.location(); |
646 } else { | 699 } else { |
647 ThreadInfo info; | 700 ThreadInfo info; |
648 if (!dumper_.ThreadInfoGet(dumper_.threads()[i], &info)) | 701 if (!dumper_.ThreadInfoGet(dumper_.threads()[i], &info)) |
649 return false; | 702 return false; |
650 UntypedMDRVA memory(&minidump_writer_); | 703 UntypedMDRVA memory(&minidump_writer_); |
651 if (!memory.Allocate(info.stack_len)) | 704 if (!memory.Allocate(info.stack_len)) |
652 return false; | 705 return false; |
653 uint8_t* stack_copy = | 706 uint8_t* stack_copy = |
654 (uint8_t*) dumper_.allocator()->Alloc(info.stack_len); | 707 (uint8_t*) dumper_.allocator()->Alloc(info.stack_len); |
655 dumper_.CopyFromProcess(stack_copy, thread.thread_id, info.stack, | 708 dumper_.CopyFromProcess(stack_copy, thread.thread_id, info.stack, |
656 info.stack_len); | 709 info.stack_len); |
657 memory.Copy(stack_copy, info.stack_len); | 710 memory.Copy(stack_copy, info.stack_len); |
658 thread.stack.start_of_memory_range = (uintptr_t)(info.stack); | 711 thread.stack.start_of_memory_range = (uintptr_t)(info.stack); |
659 thread.stack.memory = memory.location(); | 712 thread.stack.memory = memory.location(); |
713 memory_blocks_.push_back(thread.stack); | |
714 | |
660 TypedMDRVA<RawContextCPU> cpu(&minidump_writer_); | 715 TypedMDRVA<RawContextCPU> cpu(&minidump_writer_); |
661 if (!cpu.Allocate()) | 716 if (!cpu.Allocate()) |
662 return false; | 717 return false; |
663 my_memset(cpu.get(), 0, sizeof(RawContextCPU)); | 718 my_memset(cpu.get(), 0, sizeof(RawContextCPU)); |
664 CPUFillFromThreadInfo(cpu.get(), info); | 719 CPUFillFromThreadInfo(cpu.get(), info); |
665 PopSeccompStackFrame(cpu.get(), thread, stack_copy); | 720 PopSeccompStackFrame(cpu.get(), thread, stack_copy); |
666 thread.thread_context = cpu.location(); | 721 thread.thread_context = cpu.location(); |
667 } | 722 } |
668 | 723 |
669 list.CopyIndexAfterObject(i, &thread, sizeof(thread)); | 724 list.CopyIndexAfterObject(i, &thread, sizeof(thread)); |
(...skipping 80 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
750 if (!minidump_writer_.WriteString(mapping.name, filepath_len, &ld)) | 805 if (!minidump_writer_.WriteString(mapping.name, filepath_len, &ld)) |
751 return false; | 806 return false; |
752 mod.module_name_rva = ld.rva; | 807 mod.module_name_rva = ld.rva; |
753 | 808 |
754 list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); | 809 list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); |
755 } | 810 } |
756 | 811 |
757 return true; | 812 return true; |
758 } | 813 } |
759 | 814 |
815 bool WriteMemoryListStream(MDRawDirectory* dirent) { | |
816 TypedMDRVA<uint32_t> list(&minidump_writer_); | |
817 if (!list.AllocateObjectAndArray(memory_blocks_.size(), | |
818 sizeof(MDMemoryDescriptor))) | |
819 return false; | |
820 | |
821 dirent->stream_type = MD_MEMORY_LIST_STREAM; | |
822 dirent->location = list.location(); | |
823 | |
824 *list.get() = memory_blocks_.size(); | |
825 | |
826 for (size_t i = 0; i < memory_blocks_.size(); ++i) { | |
827 list.CopyIndexAfterObject(i, &memory_blocks_[i], | |
828 sizeof(MDMemoryDescriptor)); | |
829 } | |
830 return true; | |
831 } | |
832 | |
760 bool WriteExceptionStream(MDRawDirectory* dirent) { | 833 bool WriteExceptionStream(MDRawDirectory* dirent) { |
761 TypedMDRVA<MDRawExceptionStream> exc(&minidump_writer_); | 834 TypedMDRVA<MDRawExceptionStream> exc(&minidump_writer_); |
762 if (!exc.Allocate()) | 835 if (!exc.Allocate()) |
763 return false; | 836 return false; |
764 my_memset(exc.get(), 0, sizeof(MDRawExceptionStream)); | 837 my_memset(exc.get(), 0, sizeof(MDRawExceptionStream)); |
765 | 838 |
766 dirent->stream_type = MD_EXCEPTION_STREAM; | 839 dirent->stream_type = MD_EXCEPTION_STREAM; |
767 dirent->location = exc.location(); | 840 dirent->location = exc.location(); |
768 | 841 |
769 exc.get()->thread_id = crashing_tid_; | 842 exc.get()->thread_id = crashing_tid_; |
(...skipping 95 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
865 delete[] dso_debug_data; | 938 delete[] dso_debug_data; |
866 | 939 |
867 return true; | 940 return true; |
868 } | 941 } |
869 | 942 |
870 private: | 943 private: |
871 #if defined(__i386) | 944 #if defined(__i386) |
872 uintptr_t GetStackPointer() { | 945 uintptr_t GetStackPointer() { |
873 return ucontext_->uc_mcontext.gregs[REG_ESP]; | 946 return ucontext_->uc_mcontext.gregs[REG_ESP]; |
874 } | 947 } |
948 | |
949 uintptr_t GetInstructionPointer() { | |
950 return ucontext)->uc_mcontext.gregs[REG_EIP]; | |
951 } | |
875 #elif defined(__x86_64) | 952 #elif defined(__x86_64) |
876 uintptr_t GetStackPointer() { | 953 uintptr_t GetStackPointer() { |
877 return ucontext_->uc_mcontext.gregs[REG_RSP]; | 954 return ucontext_->uc_mcontext.gregs[REG_RSP]; |
878 } | 955 } |
956 | |
957 uintptr_t GetInstructionPointer() { | |
958 return ucontext_->uc_mcontext.gregs[REG_RIP]; | |
959 } | |
879 #elif defined(__ARM_EABI__) | 960 #elif defined(__ARM_EABI__) |
880 uintptr_t GetStackPointer() { | 961 uintptr_t GetStackPointer() { |
881 return ucontext_->uc_mcontext.arm_sp; | 962 return ucontext_->uc_mcontext.arm_sp; |
882 } | 963 } |
964 | |
965 uintptr_t GetInstructionPointer() { | |
966 return ucontext_->uc_mcontext.arm_ip; | |
967 } | |
883 #else | 968 #else |
884 #error "This code has not been ported to your platform yet." | 969 #error "This code has not been ported to your platform yet." |
885 #endif | 970 #endif |
886 | 971 |
887 void NullifyDirectoryEntry(MDRawDirectory* dirent) { | 972 void NullifyDirectoryEntry(MDRawDirectory* dirent) { |
888 dirent->stream_type = 0; | 973 dirent->stream_type = 0; |
889 dirent->location.data_size = 0; | 974 dirent->location.data_size = 0; |
890 dirent->location.rva = 0; | 975 dirent->location.rva = 0; |
891 } | 976 } |
892 | 977 |
(...skipping 229 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
1122 } | 1207 } |
1123 | 1208 |
1124 const char* const filename_; // output filename | 1209 const char* const filename_; // output filename |
1125 const siginfo_t* const siginfo_; // from the signal handler (see sigaction) | 1210 const siginfo_t* const siginfo_; // from the signal handler (see sigaction) |
1126 const struct ucontext* const ucontext_; // also from the signal handler | 1211 const struct ucontext* const ucontext_; // also from the signal handler |
1127 const struct _libc_fpstate* const float_state_; // ditto | 1212 const struct _libc_fpstate* const float_state_; // ditto |
1128 const pid_t crashing_tid_; // the process which actually crashed | 1213 const pid_t crashing_tid_; // the process which actually crashed |
1129 LinuxDumper dumper_; | 1214 LinuxDumper dumper_; |
1130 MinidumpFileWriter minidump_writer_; | 1215 MinidumpFileWriter minidump_writer_; |
1131 MDLocationDescriptor crashing_thread_context_; | 1216 MDLocationDescriptor crashing_thread_context_; |
1217 // Blocks of memory written to the dump. These are all currently | |
1218 // written while writing the thread list stream, but saved here | |
1219 // so a memory list stream can be written afterwards. | |
1220 wasteful_vector<MDMemoryDescriptor> memory_blocks_; | |
1132 }; | 1221 }; |
1133 | 1222 |
1134 bool WriteMinidump(const char* filename, pid_t crashing_process, | 1223 bool WriteMinidump(const char* filename, pid_t crashing_process, |
1135 const void* blob, size_t blob_size) { | 1224 const void* blob, size_t blob_size) { |
1136 if (blob_size != sizeof(ExceptionHandler::CrashContext)) | 1225 if (blob_size != sizeof(ExceptionHandler::CrashContext)) |
1137 return false; | 1226 return false; |
1138 const ExceptionHandler::CrashContext* context = | 1227 const ExceptionHandler::CrashContext* context = |
1139 reinterpret_cast<const ExceptionHandler::CrashContext*>(blob); | 1228 reinterpret_cast<const ExceptionHandler::CrashContext*>(blob); |
1140 MinidumpWriter writer(filename, crashing_process, context); | 1229 MinidumpWriter writer(filename, crashing_process, context); |
1141 if (!writer.Init()) | 1230 if (!writer.Init()) |
1142 return false; | 1231 return false; |
1143 return writer.Dump(); | 1232 return writer.Dump(); |
1144 } | 1233 } |
1145 | 1234 |
1146 } // namespace google_breakpad | 1235 } // namespace google_breakpad |
OLD | NEW |