OLD | NEW |
1 // Copyright (c) 2010, Google Inc. | 1 // Copyright (c) 2010, 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 491 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
502 *list.get() = num_output_mappings; | 502 *list.get() = num_output_mappings; |
503 | 503 |
504 // First write all the mappings from the dumper | 504 // First write all the mappings from the dumper |
505 unsigned int j = 0; | 505 unsigned int j = 0; |
506 for (unsigned i = 0; i < num_mappings; ++i) { | 506 for (unsigned i = 0; i < num_mappings; ++i) { |
507 const MappingInfo& mapping = *dumper_->mappings()[i]; | 507 const MappingInfo& mapping = *dumper_->mappings()[i]; |
508 if (!ShouldIncludeMapping(mapping) || HaveMappingInfo(mapping)) | 508 if (!ShouldIncludeMapping(mapping) || HaveMappingInfo(mapping)) |
509 continue; | 509 continue; |
510 | 510 |
511 MDRawModule mod; | 511 MDRawModule mod; |
512 if (!FillRawModule(mapping, true, i, mod, NULL)) | 512 if (!FillRawModule(mapping, true, i, &mod, NULL)) |
513 return false; | 513 return false; |
514 list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); | 514 list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); |
515 } | 515 } |
516 // Next write all the mappings provided by the caller | 516 // Next write all the mappings provided by the caller |
517 for (MappingList::const_iterator iter = mapping_list_.begin(); | 517 for (MappingList::const_iterator iter = mapping_list_.begin(); |
518 iter != mapping_list_.end(); | 518 iter != mapping_list_.end(); |
519 ++iter) { | 519 ++iter) { |
520 MDRawModule mod; | 520 MDRawModule mod; |
521 if (!FillRawModule(iter->first, false, 0, mod, iter->second)) | 521 if (!FillRawModule(iter->first, false, 0, &mod, iter->second)) |
522 return false; | 522 return false; |
523 list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); | 523 list.CopyIndexAfterObject(j++, &mod, MD_MODULE_SIZE); |
524 } | 524 } |
525 | 525 |
526 return true; | 526 return true; |
527 } | 527 } |
528 | 528 |
529 // Fill the MDRawModule |mod| with information about the provided | 529 // Fill the MDRawModule |mod| with information about the provided |
530 // |mapping|. If |identifier| is non-NULL, use it instead of calculating | 530 // |mapping|. If |identifier| is non-NULL, use it instead of calculating |
531 // a file ID from the mapping. | 531 // a file ID from the mapping. |
532 bool FillRawModule(const MappingInfo& mapping, | 532 bool FillRawModule(const MappingInfo& mapping, |
533 bool member, | 533 bool member, |
534 unsigned int mapping_id, | 534 unsigned int mapping_id, |
535 MDRawModule& mod, | 535 MDRawModule* mod, |
536 const uint8_t* identifier) { | 536 const uint8_t* identifier) { |
537 my_memset(&mod, 0, MD_MODULE_SIZE); | 537 my_memset(mod, 0, MD_MODULE_SIZE); |
538 | 538 |
539 mod.base_of_image = mapping.start_addr; | 539 mod->base_of_image = mapping.start_addr; |
540 mod.size_of_image = mapping.size; | 540 mod->size_of_image = mapping.size; |
541 | 541 |
542 uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX]; | 542 uint8_t cv_buf[MDCVInfoPDB70_minsize + NAME_MAX]; |
543 uint8_t* cv_ptr = cv_buf; | 543 uint8_t* cv_ptr = cv_buf; |
544 | 544 |
545 const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE; | 545 const uint32_t cv_signature = MD_CVINFOPDB70_SIGNATURE; |
546 my_memcpy(cv_ptr, &cv_signature, sizeof(cv_signature)); | 546 my_memcpy(cv_ptr, &cv_signature, sizeof(cv_signature)); |
547 cv_ptr += sizeof(cv_signature); | 547 cv_ptr += sizeof(cv_signature); |
548 uint8_t* signature = cv_ptr; | 548 uint8_t* signature = cv_ptr; |
549 cv_ptr += sizeof(MDGUID); | 549 cv_ptr += sizeof(MDGUID); |
550 if (identifier) { | 550 if (identifier) { |
(...skipping 14 matching lines...) Expand all Loading... |
565 | 565 |
566 const size_t file_name_len = my_strlen(file_name); | 566 const size_t file_name_len = my_strlen(file_name); |
567 UntypedMDRVA cv(&minidump_writer_); | 567 UntypedMDRVA cv(&minidump_writer_); |
568 if (!cv.Allocate(MDCVInfoPDB70_minsize + file_name_len + 1)) | 568 if (!cv.Allocate(MDCVInfoPDB70_minsize + file_name_len + 1)) |
569 return false; | 569 return false; |
570 | 570 |
571 // Write pdb_file_name | 571 // Write pdb_file_name |
572 my_memcpy(cv_ptr, file_name, file_name_len + 1); | 572 my_memcpy(cv_ptr, file_name, file_name_len + 1); |
573 cv.Copy(cv_buf, MDCVInfoPDB70_minsize + file_name_len + 1); | 573 cv.Copy(cv_buf, MDCVInfoPDB70_minsize + file_name_len + 1); |
574 | 574 |
575 mod.cv_record = cv.location(); | 575 mod->cv_record = cv.location(); |
576 | 576 |
577 MDLocationDescriptor ld; | 577 MDLocationDescriptor ld; |
578 if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld)) | 578 if (!minidump_writer_.WriteString(file_path, my_strlen(file_path), &ld)) |
579 return false; | 579 return false; |
580 mod.module_name_rva = ld.rva; | 580 mod->module_name_rva = ld.rva; |
581 return true; | 581 return true; |
582 } | 582 } |
583 | 583 |
584 bool WriteMemoryListStream(MDRawDirectory* dirent) { | 584 bool WriteMemoryListStream(MDRawDirectory* dirent) { |
585 TypedMDRVA<uint32_t> list(&minidump_writer_); | 585 TypedMDRVA<uint32_t> list(&minidump_writer_); |
586 if (memory_blocks_.size()) { | 586 if (memory_blocks_.size()) { |
587 if (!list.AllocateObjectAndArray(memory_blocks_.size(), | 587 if (!list.AllocateObjectAndArray(memory_blocks_.size(), |
588 sizeof(MDMemoryDescriptor))) | 588 sizeof(MDMemoryDescriptor))) |
589 return false; | 589 return false; |
590 } else { | 590 } else { |
(...skipping 86 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
677 | 677 |
678 for (int i = 0; ; ++i) { | 678 for (int i = 0; ; ++i) { |
679 ElfW(Dyn) dyn; | 679 ElfW(Dyn) dyn; |
680 dynamic_length += sizeof(dyn); | 680 dynamic_length += sizeof(dyn); |
681 if (!dumper_->CopyFromProcess(&dyn, GetCrashThread(), dynamic + i, | 681 if (!dumper_->CopyFromProcess(&dyn, GetCrashThread(), dynamic + i, |
682 sizeof(dyn))) { | 682 sizeof(dyn))) { |
683 return false; | 683 return false; |
684 } | 684 } |
685 | 685 |
686 #ifdef __mips__ | 686 #ifdef __mips__ |
687 if (dyn.d_tag == DT_MIPS_RLD_MAP) { | 687 const int32_t debug_tag = DT_MIPS_RLD_MAP; |
| 688 #else |
| 689 const int32_t debug_tag = DT_DEBUG; |
| 690 #endif |
| 691 if (dyn.d_tag == debug_tag) { |
688 r_debug = reinterpret_cast<struct r_debug*>(dyn.d_un.d_ptr); | 692 r_debug = reinterpret_cast<struct r_debug*>(dyn.d_un.d_ptr); |
689 continue; | 693 continue; |
690 } | 694 } else if (dyn.d_tag == DT_NULL) { |
691 #else | |
692 if (dyn.d_tag == DT_DEBUG) { | |
693 r_debug = reinterpret_cast<struct r_debug*>(dyn.d_un.d_ptr); | |
694 continue; | |
695 } | |
696 #endif | |
697 else if (dyn.d_tag == DT_NULL) { | |
698 break; | 695 break; |
699 } | 696 } |
700 } | 697 } |
701 | 698 |
702 // The "r_map" field of that r_debug struct contains a linked list of all | 699 // The "r_map" field of that r_debug struct contains a linked list of all |
703 // loaded DSOs. | 700 // loaded DSOs. |
704 // Our list of DSOs potentially is different from the ones in the crashing | 701 // Our list of DSOs potentially is different from the ones in the crashing |
705 // process. So, we have to be careful to never dereference pointers | 702 // process. So, we have to be careful to never dereference pointers |
706 // directly. Instead, we use CopyFromProcess() everywhere. | 703 // directly. Instead, we use CopyFromProcess() everywhere. |
707 // See <link.h> for a more detailed discussion of the how the dynamic | 704 // See <link.h> for a more detailed discussion of the how the dynamic |
(...skipping 121 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
829 | 826 |
830 const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0); | 827 const int fd = sys_open("/proc/cpuinfo", O_RDONLY, 0); |
831 if (fd < 0) | 828 if (fd < 0) |
832 return false; | 829 return false; |
833 | 830 |
834 { | 831 { |
835 PageAllocator allocator; | 832 PageAllocator allocator; |
836 ProcCpuInfoReader* const reader = new(allocator) ProcCpuInfoReader(fd); | 833 ProcCpuInfoReader* const reader = new(allocator) ProcCpuInfoReader(fd); |
837 const char* field; | 834 const char* field; |
838 while (reader->GetNextField(&field)) { | 835 while (reader->GetNextField(&field)) { |
839 for (size_t i = 0; | 836 bool is_first_entry = true; |
840 i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]); | 837 for (CpuInfoEntry& entry : cpu_info_table) { |
841 i++) { | 838 if (!is_first_entry && entry.found) { |
842 CpuInfoEntry* entry = &cpu_info_table[i]; | |
843 if (i > 0 && entry->found) { | |
844 // except for the 'processor' field, ignore repeated values. | 839 // except for the 'processor' field, ignore repeated values. |
845 continue; | 840 continue; |
846 } | 841 } |
847 if (!my_strcmp(field, entry->info_name)) { | 842 is_first_entry = false; |
| 843 if (!my_strcmp(field, entry.info_name)) { |
848 size_t value_len; | 844 size_t value_len; |
849 const char* value = reader->GetValueAndLen(&value_len); | 845 const char* value = reader->GetValueAndLen(&value_len); |
850 if (value_len == 0) | 846 if (value_len == 0) |
851 continue; | 847 continue; |
852 | 848 |
853 uintptr_t val; | 849 uintptr_t val; |
854 if (my_read_decimal_ptr(&val, value) == value) | 850 if (my_read_decimal_ptr(&val, value) == value) |
855 continue; | 851 continue; |
856 | 852 |
857 entry->value = static_cast<int>(val); | 853 entry.value = static_cast<int>(val); |
858 entry->found = true; | 854 entry.found = true; |
859 } | 855 } |
860 } | 856 } |
861 | 857 |
862 // special case for vendor_id | 858 // special case for vendor_id |
863 if (!my_strcmp(field, vendor_id_name)) { | 859 if (!my_strcmp(field, vendor_id_name)) { |
864 size_t value_len; | 860 size_t value_len; |
865 const char* value = reader->GetValueAndLen(&value_len); | 861 const char* value = reader->GetValueAndLen(&value_len); |
866 if (value_len > 0) | 862 if (value_len > 0) |
867 my_strlcpy(vendor_id, value, sizeof(vendor_id)); | 863 my_strlcpy(vendor_id, value, sizeof(vendor_id)); |
868 } | 864 } |
869 } | 865 } |
870 sys_close(fd); | 866 sys_close(fd); |
871 } | 867 } |
872 | 868 |
873 // make sure we got everything we wanted | 869 // make sure we got everything we wanted |
874 for (size_t i = 0; | 870 for (const CpuInfoEntry& entry : cpu_info_table) { |
875 i < sizeof(cpu_info_table) / sizeof(cpu_info_table[0]); | 871 if (!entry.found) { |
876 i++) { | |
877 if (!cpu_info_table[i].found) { | |
878 return false; | 872 return false; |
879 } | 873 } |
880 } | 874 } |
881 // cpu_info_table[0] holds the last cpu id listed in /proc/cpuinfo, | 875 // cpu_info_table[0] holds the last cpu id listed in /proc/cpuinfo, |
882 // assuming this is the highest id, change it to the number of CPUs | 876 // assuming this is the highest id, change it to the number of CPUs |
883 // by adding one. | 877 // by adding one. |
884 cpu_info_table[0].value++; | 878 cpu_info_table[0].value++; |
885 | 879 |
886 sys_info->number_of_processors = cpu_info_table[0].value; | 880 sys_info->number_of_processors = cpu_info_table[0].value; |
887 #if defined(__i386__) || defined(__x86_64__) | 881 #if defined(__i386__) || defined(__x86_64__) |
(...skipping 115 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1003 // to happen properly. | 997 // to happen properly. |
1004 return true; | 998 return true; |
1005 } | 999 } |
1006 | 1000 |
1007 { | 1001 { |
1008 PageAllocator allocator; | 1002 PageAllocator allocator; |
1009 ProcCpuInfoReader* const reader = | 1003 ProcCpuInfoReader* const reader = |
1010 new(allocator) ProcCpuInfoReader(fd); | 1004 new(allocator) ProcCpuInfoReader(fd); |
1011 const char* field; | 1005 const char* field; |
1012 while (reader->GetNextField(&field)) { | 1006 while (reader->GetNextField(&field)) { |
1013 for (size_t i = 0; | 1007 for (const CpuInfoEntry& entry : cpu_info_table) { |
1014 i < sizeof(cpu_id_entries)/sizeof(cpu_id_entries[0]); | 1008 if (my_strcmp(entry.field, field) != 0) |
1015 ++i) { | |
1016 const CpuIdEntry* entry = &cpu_id_entries[i]; | |
1017 if (my_strcmp(entry->field, field) != 0) | |
1018 continue; | 1009 continue; |
1019 uintptr_t result = 0; | 1010 uintptr_t result = 0; |
1020 const char* value = reader->GetValue(); | 1011 const char* value = reader->GetValue(); |
1021 const char* p = value; | 1012 const char* p = value; |
1022 if (value[0] == '0' && value[1] == 'x') { | 1013 if (value[0] == '0' && value[1] == 'x') { |
1023 p = my_read_hex_ptr(&result, value+2); | 1014 p = my_read_hex_ptr(&result, value+2); |
1024 } else if (entry->format == 'x') { | 1015 } else if (entry.format == 'x') { |
1025 p = my_read_hex_ptr(&result, value); | 1016 p = my_read_hex_ptr(&result, value); |
1026 } else { | 1017 } else { |
1027 p = my_read_decimal_ptr(&result, value); | 1018 p = my_read_decimal_ptr(&result, value); |
1028 } | 1019 } |
1029 if (p == value) | 1020 if (p == value) |
1030 continue; | 1021 continue; |
1031 | 1022 |
1032 result &= (1U << entry->bit_length)-1; | 1023 result &= (1U << entry.bit_length)-1; |
1033 result <<= entry->bit_lshift; | 1024 result <<= entry.bit_lshift; |
1034 sys_info->cpu.arm_cpu_info.cpuid |= | 1025 sys_info->cpu.arm_cpu_info.cpuid |= |
1035 static_cast<uint32_t>(result); | 1026 static_cast<uint32_t>(result); |
1036 } | 1027 } |
1037 #if defined(__arm__) | 1028 #if defined(__arm__) |
1038 // Get the architecture version from the "Processor" field. | 1029 // Get the architecture version from the "Processor" field. |
1039 // Note that it is also available in the "CPU architecture" field, | 1030 // Note that it is also available in the "CPU architecture" field, |
1040 // however, some existing kernels are misconfigured and will report | 1031 // however, some existing kernels are misconfigured and will report |
1041 // invalid values here (e.g. 6, while the CPU is ARMv7-A based). | 1032 // invalid values here (e.g. 6, while the CPU is ARMv7-A based). |
1042 // The "Processor" field doesn't have this issue. | 1033 // The "Processor" field doesn't have this issue. |
1043 if (!my_strcmp(field, "Processor")) { | 1034 if (!my_strcmp(field, "Processor")) { |
(...skipping 33 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1077 // Rebuild the ELF hwcaps from the 'Features' field. | 1068 // Rebuild the ELF hwcaps from the 'Features' field. |
1078 if (!my_strcmp(field, "Features")) { | 1069 if (!my_strcmp(field, "Features")) { |
1079 size_t value_len; | 1070 size_t value_len; |
1080 const char* value = reader->GetValueAndLen(&value_len); | 1071 const char* value = reader->GetValueAndLen(&value_len); |
1081 | 1072 |
1082 // Parse each space-separated tag. | 1073 // Parse each space-separated tag. |
1083 while (value_len > 0) { | 1074 while (value_len > 0) { |
1084 const char* tag = value; | 1075 const char* tag = value; |
1085 size_t tag_len = value_len; | 1076 size_t tag_len = value_len; |
1086 const char* p = my_strchr(tag, ' '); | 1077 const char* p = my_strchr(tag, ' '); |
1087 if (p != NULL) { | 1078 if (p) { |
1088 tag_len = static_cast<size_t>(p - tag); | 1079 tag_len = static_cast<size_t>(p - tag); |
1089 value += tag_len + 1; | 1080 value += tag_len + 1; |
1090 value_len -= tag_len + 1; | 1081 value_len -= tag_len + 1; |
1091 } else { | 1082 } else { |
1092 tag_len = strlen(tag); | 1083 tag_len = strlen(tag); |
1093 value_len = 0; | 1084 value_len = 0; |
1094 } | 1085 } |
1095 for (size_t i = 0; | 1086 for (const CpuInfoEntry& entry : cpu_features_entries) { |
1096 i != sizeof(cpu_features_entries) / | 1087 if (tag_len == strlen(entry.tag) && |
1097 sizeof(cpu_features_entries[0]); | 1088 !memcmp(tag, entry.tag, tag_len)) { |
1098 ++i) { | 1089 sys_info->cpu.arm_cpu_info.elf_hwcaps |= entry.hwcaps; |
1099 const CpuFeaturesEntry* entry = &cpu_features_entries[i]; | |
1100 if (tag_len == strlen(entry->tag) && | |
1101 !memcmp(tag, entry->tag, tag_len)) { | |
1102 sys_info->cpu.arm_cpu_info.elf_hwcaps |= entry->hwcaps; | |
1103 break; | 1090 break; |
1104 } | 1091 } |
1105 } | 1092 } |
1106 } | 1093 } |
1107 } | 1094 } |
1108 } | 1095 } |
1109 sys_close(fd); | 1096 sys_close(fd); |
1110 } | 1097 } |
1111 | 1098 |
1112 return true; | 1099 return true; |
(...skipping 245 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... |
1358 const MappingList& mappings, | 1345 const MappingList& mappings, |
1359 const AppMemoryList& appmem, | 1346 const AppMemoryList& appmem, |
1360 LinuxDumper* dumper) { | 1347 LinuxDumper* dumper) { |
1361 MinidumpWriter writer(filename, -1, NULL, mappings, appmem, dumper); | 1348 MinidumpWriter writer(filename, -1, NULL, mappings, appmem, dumper); |
1362 if (!writer.Init()) | 1349 if (!writer.Init()) |
1363 return false; | 1350 return false; |
1364 return writer.Dump(); | 1351 return writer.Dump(); |
1365 } | 1352 } |
1366 | 1353 |
1367 } // namespace google_breakpad | 1354 } // namespace google_breakpad |
OLD | NEW |