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 241 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 252 kern_return_t kr = | 252 kern_return_t kr = |
| 253 task_info(mach_task_self(), TASK_DYLD_INFO, | 253 task_info(mach_task_self(), TASK_DYLD_INFO, |
| 254 reinterpret_cast<task_info_t>(&dyld_info), &count); | 254 reinterpret_cast<task_info_t>(&dyld_info), &count); |
| 255 if (kr != KERN_SUCCESS) | 255 if (kr != KERN_SUCCESS) |
| 256 return false; | 256 return false; |
| 257 | 257 |
| 258 const struct dyld_all_image_infos* all_image_infos = | 258 const struct dyld_all_image_infos* all_image_infos = |
| 259 reinterpret_cast<const struct dyld_all_image_infos*>( | 259 reinterpret_cast<const struct dyld_all_image_infos*>( |
| 260 dyld_info.all_image_info_addr); | 260 dyld_info.all_image_info_addr); |
| 261 | 261 |
| 262 bool emitted_linkedit_from_dyld_shared_cache = false; | |
| 262 for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) { | 263 for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) { |
| 263 const char* image_name = all_image_infos->infoArray[i].imageFilePath; | 264 const char* image_name = all_image_infos->infoArray[i].imageFilePath; |
| 264 | 265 |
| 265 // The public definition for dyld_all_image_infos/dyld_image_info is wrong | 266 // 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 | 267 // 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. | 268 // though the public definition claims that this is a struct mach_header. |
| 268 const struct mach_header_64* const header = | 269 const struct mach_header_64* const header = |
| 269 reinterpret_cast<const struct mach_header_64* const>( | 270 reinterpret_cast<const struct mach_header_64* const>( |
| 270 all_image_infos->infoArray[i].imageLoadAddress); | 271 all_image_infos->infoArray[i].imageLoadAddress); |
| 271 | 272 |
| 272 uint64_t next_command = reinterpret_cast<uint64_t>(header + 1); | 273 uint64_t next_command = reinterpret_cast<uint64_t>(header + 1); |
| 273 uint64_t command_end = next_command + header->sizeofcmds; | 274 uint64_t command_end = next_command + header->sizeofcmds; |
| 274 for (unsigned int i = 0; i < header->ncmds; ++i) { | 275 uint64_t slide = 0; |
| 276 for (unsigned int j = 0; j < header->ncmds; ++j) { | |
| 275 // Ensure that next_command doesn't run past header->sizeofcmds. | 277 // Ensure that next_command doesn't run past header->sizeofcmds. |
| 276 if (next_command + sizeof(struct load_command) > command_end) | 278 if (next_command + sizeof(struct load_command) > command_end) |
| 277 return false; | 279 return false; |
| 278 const struct load_command* load_cmd = | 280 const struct load_command* load_cmd = |
| 279 reinterpret_cast<const struct load_command*>(next_command); | 281 reinterpret_cast<const struct load_command*>(next_command); |
| 280 next_command += load_cmd->cmdsize; | 282 next_command += load_cmd->cmdsize; |
| 281 | 283 |
| 282 if (load_cmd->cmd == LC_SEGMENT_64) { | 284 if (load_cmd->cmd == LC_SEGMENT_64) { |
| 283 if (load_cmd->cmdsize < sizeof(segment_command_64)) | 285 if (load_cmd->cmdsize < sizeof(segment_command_64)) |
| 284 return false; | 286 return false; |
| 285 const segment_command_64* seg = | 287 const segment_command_64* seg = |
| 286 reinterpret_cast<const segment_command_64*>(load_cmd); | 288 reinterpret_cast<const segment_command_64*>(load_cmd); |
| 287 if (strcmp(seg->segname, SEG_PAGEZERO) == 0) | 289 if (strcmp(seg->segname, SEG_PAGEZERO) == 0) |
| 288 continue; | 290 continue; |
| 291 if (strcmp(seg->segname, SEG_TEXT) == 0) { | |
| 292 slide = reinterpret_cast<uint64_t>(header) - seg->vmaddr; | |
| 293 } | |
| 294 | |
| 295 // Avoid emitting LINKEDIT regions in the dyld shared cache, since they | |
| 296 // all overlap. | |
| 297 if (IsAddressInSharedRegion(seg->vmaddr) && | |
| 298 strcmp(seg->segname, SEG_LINKEDIT) == 0) { | |
| 299 if (emitted_linkedit_from_dyld_shared_cache) { | |
| 300 continue; | |
| 301 } else { | |
| 302 emitted_linkedit_from_dyld_shared_cache = true; | |
| 303 image_name = "LinkEditDyldSharedCache"; | |
|
Mark Mentovai
2017/02/14 22:45:06
It’d be nice to use the actual proc_regionfilename
erikchen
2017/02/14 23:31:58
I went with "dyld shared cache combined __LINKEDIT
| |
| 304 } | |
| 305 } | |
| 289 | 306 |
| 290 uint32_t protection_flags = 0; | 307 uint32_t protection_flags = 0; |
| 291 if (seg->initprot & VM_PROT_READ) | 308 if (seg->initprot & VM_PROT_READ) |
| 292 protection_flags |= VMRegion::kProtectionFlagsRead; | 309 protection_flags |= VMRegion::kProtectionFlagsRead; |
| 293 if (seg->initprot & VM_PROT_WRITE) | 310 if (seg->initprot & VM_PROT_WRITE) |
| 294 protection_flags |= VMRegion::kProtectionFlagsWrite; | 311 protection_flags |= VMRegion::kProtectionFlagsWrite; |
| 295 if (seg->initprot & VM_PROT_EXECUTE) | 312 if (seg->initprot & VM_PROT_EXECUTE) |
| 296 protection_flags |= VMRegion::kProtectionFlagsExec; | 313 protection_flags |= VMRegion::kProtectionFlagsExec; |
| 297 | 314 |
| 298 VMRegion region; | 315 VMRegion region; |
| 299 region.size_in_bytes = seg->vmsize; | 316 region.size_in_bytes = seg->vmsize; |
| 300 region.protection_flags = protection_flags; | 317 region.protection_flags = protection_flags; |
| 301 region.mapped_file = image_name; | 318 region.mapped_file = image_name; |
| 302 region.start_address = | 319 region.start_address = slide + seg->vmaddr; |
| 303 reinterpret_cast<uint64_t>(header) + seg->fileoff; | |
| 304 | 320 |
| 305 // We intentionally avoid setting any page information, which is not | 321 // We intentionally avoid setting any page information, which is not |
| 306 // available from dyld. The fields will be populated later. | 322 // available from dyld. The fields will be populated later. |
| 307 regions->push_back(region); | 323 regions->push_back(region); |
| 308 } | 324 } |
| 309 } | 325 } |
| 310 } | 326 } |
| 311 return true; | 327 return true; |
| 312 } | 328 } |
| 313 | 329 |
| (...skipping 108 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 422 std::vector<VMRegion> dyld_regions; | 438 std::vector<VMRegion> dyld_regions; |
| 423 if (!GetDyldRegions(&dyld_regions)) | 439 if (!GetDyldRegions(&dyld_regions)) |
| 424 return false; | 440 return false; |
| 425 std::vector<VMRegion> all_regions; | 441 std::vector<VMRegion> all_regions; |
| 426 if (!GetAllRegions(&all_regions)) | 442 if (!GetAllRegions(&all_regions)) |
| 427 return false; | 443 return false; |
| 428 | 444 |
| 429 // Cache information from dyld_regions in a data-structure more conducive to | 445 // Cache information from dyld_regions in a data-structure more conducive to |
| 430 // fast lookups. | 446 // fast lookups. |
| 431 std::unordered_map<uint64_t, VMRegion*> address_to_vm_region; | 447 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) { | 448 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; | 449 address_to_vm_region[region.start_address] = ®ion; |
| 437 } | 450 } |
| 438 | 451 |
| 439 // Merge information from dyld regions and all regions. | 452 // Merge information from dyld regions and all regions. |
| 440 for (const VMRegion& region : all_regions) { | 453 for (const VMRegion& region : all_regions) { |
| 441 // Check to see if the region already has a VMRegion created from a dyld | 454 // 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. | 455 // load command. If so, copy the byte stats and move on. |
| 443 auto it = address_to_vm_region.find(region.start_address); | 456 auto it = address_to_vm_region.find(region.start_address); |
| 444 if (it != address_to_vm_region.end() && | 457 if (it != address_to_vm_region.end() && |
| 445 it->second->size_in_bytes == region.size_in_bytes) { | 458 it->second->size_in_bytes == region.size_in_bytes) { |
| 446 CopyRegionByteStats(it->second, region); | 459 CopyRegionByteStats(it->second, region); |
| 447 continue; | 460 continue; |
| 448 } | 461 } |
| 449 | 462 |
| 450 // Check to see if the region is likely used for the dyld shared cache. | 463 // Check to see if the region is likely used for the dyld shared cache. |
| 451 if (IsAddressInSharedRegion(region.start_address)) { | 464 if (IsAddressInSharedRegion(region.start_address)) { |
| 452 uint64_t end_address = region.start_address + region.size_in_bytes; | 465 uint64_t end_address = region.start_address + region.size_in_bytes; |
| 453 for (uint64_t address : addresses_in_shared_region) { | 466 bool skip = false; |
| 467 for (const VMRegion& dyld_region : dyld_regions) { | |
| 454 // This region is likely used for the dyld shared cache. Don't record | 468 // This region is likely used for the dyld shared cache. Don't record |
| 455 // any byte stats since: | 469 // any byte stats since: |
| 456 // 1. It's not possible to figure out which dyld regions the byte | 470 // 1. It's not possible to figure out which dyld regions the byte |
| 457 // stats correspond to. | 471 // stats correspond to. |
| 458 // 2. The region is likely shared by non-Chrome processes, so there's | 472 // 2. The region is likely shared by non-Chrome processes, so there's |
| 459 // no point in charging the pages towards Chrome. | 473 // no point in charging the pages towards Chrome. |
| 460 if (address >= region.start_address && address < end_address) { | 474 if (dyld_region.start_address >= region.start_address && |
| 461 continue; | 475 dyld_region.start_address < end_address) { |
| 476 skip = true; | |
| 477 break; | |
| 478 } | |
| 479 uint64_t dyld_end_address = | |
| 480 dyld_region.start_address + dyld_region.size_in_bytes; | |
| 481 if (dyld_end_address >= region.start_address && | |
| 482 dyld_end_address < end_address) { | |
| 483 skip = true; | |
| 484 break; | |
| 462 } | 485 } |
| 463 } | 486 } |
| 487 if (skip) | |
| 488 continue; | |
| 464 } | 489 } |
| 465 pmd->process_mmaps()->AddVMRegion(region); | 490 pmd->process_mmaps()->AddVMRegion(region); |
| 466 } | 491 } |
| 467 | 492 |
| 468 for (VMRegion& region : dyld_regions) { | 493 for (VMRegion& region : dyld_regions) { |
| 469 pmd->process_mmaps()->AddVMRegion(region); | 494 pmd->process_mmaps()->AddVMRegion(region); |
| 470 } | 495 } |
| 471 | 496 |
| 472 pmd->set_has_process_mmaps(); | 497 pmd->set_has_process_mmaps(); |
| 473 return true; | 498 return true; |
| (...skipping 148 matching lines...) Expand 10 before | Expand all | Expand 10 after Loading... | |
| 622 #endif | 647 #endif |
| 623 } | 648 } |
| 624 | 649 |
| 625 void ProcessMetricsMemoryDumpProvider::SuspendFastMemoryPolling() { | 650 void ProcessMetricsMemoryDumpProvider::SuspendFastMemoryPolling() { |
| 626 #if defined(OS_LINUX) || defined(OS_ANDROID) | 651 #if defined(OS_LINUX) || defined(OS_ANDROID) |
| 627 fast_polling_statm_fd_.reset(); | 652 fast_polling_statm_fd_.reset(); |
| 628 #endif | 653 #endif |
| 629 } | 654 } |
| 630 | 655 |
| 631 } // namespace tracing | 656 } // namespace tracing |
| OLD | NEW |