Chromium Code Reviews| OLD | NEW |
|---|---|
| 1 // Copyright 2015 The Chromium Authors. All rights reserved. | 1 // Copyright 2015 The Chromium Authors. All rights reserved. |
| 2 // Use of this source code is governed by a BSD-style license that can be | 2 // Use of this source code is governed by a BSD-style license that can be |
| 3 // found in the LICENSE file. | 3 // found in the LICENSE file. |
| 4 | 4 |
| 5 #include "components/tracing/common/process_metrics_memory_dump_provider.h" | 5 #include "components/tracing/common/process_metrics_memory_dump_provider.h" |
| 6 | 6 |
| 7 #include <fcntl.h> | 7 #include <fcntl.h> |
| 8 #include <stdint.h> | 8 #include <stdint.h> |
| 9 | 9 |
| 10 #include <map> | 10 #include <map> |
| (...skipping 253 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 264 | 264 |
| 265 // The public definition for dyld_all_image_infos/dyld_image_info is wrong | 265 // The public definition for dyld_all_image_infos/dyld_image_info is wrong |
| 266 // for 64-bit platforms. We explicitly cast to struct mach_header_64 even | 266 // for 64-bit platforms. We explicitly cast to struct mach_header_64 even |
| 267 // though the public definition claims that this is a struct mach_header. | 267 // though the public definition claims that this is a struct mach_header. |
| 268 const struct mach_header_64* const header = | 268 const struct mach_header_64* const header = |
| 269 reinterpret_cast<const struct mach_header_64* const>( | 269 reinterpret_cast<const struct mach_header_64* const>( |
| 270 all_image_infos->infoArray[i].imageLoadAddress); | 270 all_image_infos->infoArray[i].imageLoadAddress); |
| 271 | 271 |
| 272 uint64_t next_command = reinterpret_cast<uint64_t>(header + 1); | 272 uint64_t next_command = reinterpret_cast<uint64_t>(header + 1); |
| 273 uint64_t command_end = next_command + header->sizeofcmds; | 273 uint64_t command_end = next_command + header->sizeofcmds; |
| 274 for (unsigned int i = 0; i < header->ncmds; ++i) { | 274 uint64_t slide = 0; |
| 275 for (unsigned int j = 0; j < header->ncmds; ++j) { | |
| 275 // Ensure that next_command doesn't run past header->sizeofcmds. | 276 // Ensure that next_command doesn't run past header->sizeofcmds. |
| 276 if (next_command + sizeof(struct load_command) > command_end) | 277 if (next_command + sizeof(struct load_command) > command_end) |
| 277 return false; | 278 return false; |
| 278 const struct load_command* load_cmd = | 279 const struct load_command* load_cmd = |
| 279 reinterpret_cast<const struct load_command*>(next_command); | 280 reinterpret_cast<const struct load_command*>(next_command); |
| 280 next_command += load_cmd->cmdsize; | 281 next_command += load_cmd->cmdsize; |
| 281 | 282 |
| 282 if (load_cmd->cmd == LC_SEGMENT_64) { | 283 if (load_cmd->cmd == LC_SEGMENT_64) { |
| 283 if (load_cmd->cmdsize < sizeof(segment_command_64)) | 284 if (load_cmd->cmdsize < sizeof(segment_command_64)) |
| 284 return false; | 285 return false; |
| 285 const segment_command_64* seg = | 286 const segment_command_64* seg = |
| 286 reinterpret_cast<const segment_command_64*>(load_cmd); | 287 reinterpret_cast<const segment_command_64*>(load_cmd); |
| 287 if (strcmp(seg->segname, SEG_PAGEZERO) == 0) | 288 if (strcmp(seg->segname, SEG_PAGEZERO) == 0) |
| 288 continue; | 289 continue; |
| 290 if (strcmp(seg->segname, SEG_TEXT) == 0) { | |
| 291 slide = reinterpret_cast<uint64_t>(header) - seg->vmaddr; | |
| 292 } | |
| 293 | |
| 294 // Avoid emitting LINKEDIT regions in the dyld shared cache, since they | |
|
Mark Mentovai
2017/02/14 22:18:58
Perhaps just emit it one time, then? Show it as be
erikchen
2017/02/14 22:33:47
Done.
| |
| 295 // all overlap. | |
| 296 if (IsAddressInSharedRegion(seg->vmaddr) && | |
| 297 strcmp(seg->segname, SEG_LINKEDIT) == 0) { | |
| 298 continue; | |
| 299 } | |
| 289 | 300 |
| 290 uint32_t protection_flags = 0; | 301 uint32_t protection_flags = 0; |
| 291 if (seg->initprot & VM_PROT_READ) | 302 if (seg->initprot & VM_PROT_READ) |
| 292 protection_flags |= VMRegion::kProtectionFlagsRead; | 303 protection_flags |= VMRegion::kProtectionFlagsRead; |
| 293 if (seg->initprot & VM_PROT_WRITE) | 304 if (seg->initprot & VM_PROT_WRITE) |
| 294 protection_flags |= VMRegion::kProtectionFlagsWrite; | 305 protection_flags |= VMRegion::kProtectionFlagsWrite; |
| 295 if (seg->initprot & VM_PROT_EXECUTE) | 306 if (seg->initprot & VM_PROT_EXECUTE) |
| 296 protection_flags |= VMRegion::kProtectionFlagsExec; | 307 protection_flags |= VMRegion::kProtectionFlagsExec; |
| 297 | 308 |
| 298 VMRegion region; | 309 VMRegion region; |
| 299 region.size_in_bytes = seg->vmsize; | 310 region.size_in_bytes = seg->vmsize; |
| 300 region.protection_flags = protection_flags; | 311 region.protection_flags = protection_flags; |
| 301 region.mapped_file = image_name; | 312 region.mapped_file = image_name; |
| 302 region.start_address = | 313 region.start_address = slide + seg->vmaddr; |
| 303 reinterpret_cast<uint64_t>(header) + seg->fileoff; | |
| 304 | 314 |
| 305 // We intentionally avoid setting any page information, which is not | 315 // We intentionally avoid setting any page information, which is not |
| 306 // available from dyld. The fields will be populated later. | 316 // available from dyld. The fields will be populated later. |
| 307 regions->push_back(region); | 317 regions->push_back(region); |
| 308 } | 318 } |
| 309 } | 319 } |
| 310 } | 320 } |
| 311 return true; | 321 return true; |
| 312 } | 322 } |
| 313 | 323 |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 422 std::vector<VMRegion> dyld_regions; | 432 std::vector<VMRegion> dyld_regions; |
| 423 if (!GetDyldRegions(&dyld_regions)) | 433 if (!GetDyldRegions(&dyld_regions)) |
| 424 return false; | 434 return false; |
| 425 std::vector<VMRegion> all_regions; | 435 std::vector<VMRegion> all_regions; |
| 426 if (!GetAllRegions(&all_regions)) | 436 if (!GetAllRegions(&all_regions)) |
| 427 return false; | 437 return false; |
| 428 | 438 |
| 429 // Cache information from dyld_regions in a data-structure more conducive to | 439 // Cache information from dyld_regions in a data-structure more conducive to |
| 430 // fast lookups. | 440 // fast lookups. |
| 431 std::unordered_map<uint64_t, VMRegion*> address_to_vm_region; | 441 std::unordered_map<uint64_t, VMRegion*> address_to_vm_region; |
| 432 std::vector<uint64_t> addresses_in_shared_region; | |
| 433 for (VMRegion& region : dyld_regions) { | 442 for (VMRegion& region : dyld_regions) { |
| 434 if (IsAddressInSharedRegion(region.start_address)) | |
| 435 addresses_in_shared_region.push_back(region.start_address); | |
| 436 address_to_vm_region[region.start_address] = ®ion; | 443 address_to_vm_region[region.start_address] = ®ion; |
| 437 } | 444 } |
| 438 | 445 |
| 439 // Merge information from dyld regions and all regions. | 446 // Merge information from dyld regions and all regions. |
| 440 for (const VMRegion& region : all_regions) { | 447 for (const VMRegion& region : all_regions) { |
| 441 // Check to see if the region already has a VMRegion created from a dyld | 448 // Check to see if the region already has a VMRegion created from a dyld |
| 442 // load command. If so, copy the byte stats and move on. | 449 // load command. If so, copy the byte stats and move on. |
| 443 auto it = address_to_vm_region.find(region.start_address); | 450 auto it = address_to_vm_region.find(region.start_address); |
| 444 if (it != address_to_vm_region.end() && | 451 if (it != address_to_vm_region.end() && |
| 445 it->second->size_in_bytes == region.size_in_bytes) { | 452 it->second->size_in_bytes == region.size_in_bytes) { |
| 446 CopyRegionByteStats(it->second, region); | 453 CopyRegionByteStats(it->second, region); |
| 447 continue; | 454 continue; |
| 448 } | 455 } |
| 449 | 456 |
| 450 // Check to see if the region is likely used for the dyld shared cache. | 457 // Check to see if the region is likely used for the dyld shared cache. |
| 451 if (IsAddressInSharedRegion(region.start_address)) { | 458 if (IsAddressInSharedRegion(region.start_address)) { |
| 452 uint64_t end_address = region.start_address + region.size_in_bytes; | 459 uint64_t end_address = region.start_address + region.size_in_bytes; |
| 453 for (uint64_t address : addresses_in_shared_region) { | 460 bool skip = false; |
| 461 for (const VMRegion& dyld_region : dyld_regions) { | |
| 454 // This region is likely used for the dyld shared cache. Don't record | 462 // This region is likely used for the dyld shared cache. Don't record |
| 455 // any byte stats since: | 463 // any byte stats since: |
| 456 // 1. It's not possible to figure out which dyld regions the byte | 464 // 1. It's not possible to figure out which dyld regions the byte |
| 457 // stats correspond to. | 465 // stats correspond to. |
| 458 // 2. The region is likely shared by non-Chrome processes, so there's | 466 // 2. The region is likely shared by non-Chrome processes, so there's |
| 459 // no point in charging the pages towards Chrome. | 467 // no point in charging the pages towards Chrome. |
| 460 if (address >= region.start_address && address < end_address) { | 468 if (dyld_region.start_address >= region.start_address && |
| 461 continue; | 469 dyld_region.start_address < end_address) { |
| 470 skip = true; | |
| 471 break; | |
| 472 } | |
| 473 uint64_t dyld_end_address = | |
| 474 dyld_region.start_address + dyld_region.size_in_bytes; | |
| 475 if (dyld_end_address >= region.start_address && | |
| 476 dyld_end_address < end_address) { | |
| 477 skip = true; | |
| 478 break; | |
| 462 } | 479 } |
| 463 } | 480 } |
| 481 if (skip) | |
| 482 continue; | |
| 464 } | 483 } |
| 465 pmd->process_mmaps()->AddVMRegion(region); | 484 pmd->process_mmaps()->AddVMRegion(region); |
| 466 } | 485 } |
| 467 | 486 |
| 468 for (VMRegion& region : dyld_regions) { | 487 for (VMRegion& region : dyld_regions) { |
| 469 pmd->process_mmaps()->AddVMRegion(region); | 488 pmd->process_mmaps()->AddVMRegion(region); |
| 470 } | 489 } |
| 471 | 490 |
| 472 pmd->set_has_process_mmaps(); | 491 pmd->set_has_process_mmaps(); |
| 473 return true; | 492 return true; |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 622 #endif | 641 #endif |
| 623 } | 642 } |
| 624 | 643 |
| 625 void ProcessMetricsMemoryDumpProvider::SuspendFastMemoryPolling() { | 644 void ProcessMetricsMemoryDumpProvider::SuspendFastMemoryPolling() { |
| 626 #if defined(OS_LINUX) || defined(OS_ANDROID) | 645 #if defined(OS_LINUX) || defined(OS_ANDROID) |
| 627 fast_polling_statm_fd_.reset(); | 646 fast_polling_statm_fd_.reset(); |
| 628 #endif | 647 #endif |
| 629 } | 648 } |
| 630 | 649 |
| 631 } // namespace tracing | 650 } // namespace tracing |
| OLD | NEW |