| 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 |