Rietveld Code Review Tool
Help | Bug tracker | Discussion group | Source code | Sign in
(61)

Side by Side Diff: src/client/linux/minidump_writer/minidump_writer.cc

Issue 194001: Write a memory around the instruction pointer from the crashing thread to the minidump on Linux (Closed)
Patch Set: Created 14 years, 7 months ago
Left:
Right:
Use n/p to move between diff chunks; N/P to move between comments. Please Sign in to add in-line comments.
Jump to:
View unified diff | Download patch
OLDNEW
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
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
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
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
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
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
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
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
OLDNEW

Powered by Google App Engine
RSS Feeds Recent Issues | This issue
This is Rietveld 1004:630ec63f810e-tainted