Chromium Code Reviews| Index: components/tracing/common/process_metrics_memory_dump_provider.cc |
| diff --git a/components/tracing/common/process_metrics_memory_dump_provider.cc b/components/tracing/common/process_metrics_memory_dump_provider.cc |
| index 593755bada11899c83bd93f32689d819cd09fae7..5a5d16d4cbb51952f1959f4fe3f144ebef53618a 100644 |
| --- a/components/tracing/common/process_metrics_memory_dump_provider.cc |
| +++ b/components/tracing/common/process_metrics_memory_dump_provider.cc |
| @@ -24,6 +24,14 @@ |
| #include "base/trace_event/process_memory_totals.h" |
| #include "build/build_config.h" |
| +#if defined(OS_MACOSX) |
| +#include <mach/mach.h> |
| +#include <mach-o/loader.h> |
| +#include <mach-o/dyld_images.h> |
| + |
| +#include "base/mac/mach_logging.h" |
| +#endif // defined(OS_MACOSX) |
| + |
| namespace tracing { |
| namespace { |
| @@ -219,6 +227,73 @@ bool ProcessMetricsMemoryDumpProvider::DumpProcessMemoryMaps( |
| } |
| #endif // defined(OS_LINUX) || defined(OS_ANDROID) |
| +#if defined(OS_MACOSX) |
| +bool ProcessMetricsMemoryDumpProvider::DumpProcessMemoryMaps( |
| + const base::trace_event::MemoryDumpArgs& args, |
| + base::trace_event::ProcessMemoryDump* pmd) { |
| + using VMRegion = base::trace_event::ProcessMemoryMaps::VMRegion; |
| + task_dyld_info_data_t dyld_info; |
| + mach_msg_type_number_t count = TASK_DYLD_INFO_COUNT; |
| + kern_return_t kr = |
| + task_info(mach_task_self(), TASK_DYLD_INFO, |
| + reinterpret_cast<task_info_t>(&dyld_info), &count); |
| + if (kr != KERN_SUCCESS) { |
| + MACH_LOG(WARNING, kr) << "task_info"; |
| + return false; |
| + } |
| + |
| + const struct dyld_all_image_infos* all_image_infos = |
| + reinterpret_cast<const struct dyld_all_image_infos*>( |
| + dyld_info.all_image_info_addr); |
| + |
| + for (size_t i = 0; i < all_image_infos->infoArrayCount; i++) { |
| + const char* image_name = all_image_infos->infoArray[i].imageFilePath; |
| + |
| + // The public definition for dyld_all_image_infos/dyld_image_info is wrong |
| + // for 64-bit platforms. We explicitly cast to struct mach_header_64 even |
| + // though the public definition claims that this is a struct mach_header. |
| + const struct mach_header_64* const header = |
| + reinterpret_cast<const struct mach_header_64* const>( |
| + all_image_infos->infoArray[i].imageLoadAddress); |
| + |
| + const struct load_command* load_cmd = |
| + reinterpret_cast<const struct load_command*>(header + 1); |
| + VMRegion region; |
| + for (unsigned int i = 0; load_cmd && (i < header->ncmds); ++i) { |
| + if (load_cmd->cmd == LC_SEGMENT_64) { |
| + const segment_command_64* seg = |
| + reinterpret_cast<const segment_command_64*>(load_cmd); |
| + |
| + if (!strcmp(seg->segname, "__TEXT")) { |
|
Mark Mentovai
2017/01/03 20:07:46
You can use SEG_TEXT as a symbolic name for __TEXT
|
| + region.size_in_bytes = seg->vmsize; |
| + |
| + // It's not clear what "protection_flags" means for an entire |
|
Mark Mentovai
2017/01/03 20:07:46
They’re the access bits set when the region is ini
|
| + // VMRegion, since pages can have their own protection flags. |
| + // segment_command_64 exposes "initprot" and "maxprot". We use |
| + // "maxprot". |
| + if (seg->maxprot & VM_PROT_READ) |
| + region.protection_flags |= VMRegion::kProtectionFlagsRead; |
| + if (seg->maxprot & VM_PROT_WRITE) |
| + region.protection_flags |= VMRegion::kProtectionFlagsWrite; |
| + if (seg->maxprot & VM_PROT_EXECUTE) |
| + region.protection_flags |= VMRegion::kProtectionFlagsExec; |
| + break; |
| + } |
| + } |
| + |
| + load_cmd = reinterpret_cast<const struct load_command*>( |
| + reinterpret_cast<const char*>(load_cmd) + load_cmd->cmdsize); |
|
Mark Mentovai
2017/01/03 20:07:46
Avoid running beyond header->sizeofcmds, bearing i
|
| + } |
| + |
| + region.mapped_file = image_name; |
| + region.start_address = reinterpret_cast<uint64_t>(header); |
|
Mark Mentovai
2017/01/03 20:07:46
For this to be valid, __TEXT needs to be at offset
|
| + pmd->process_mmaps()->AddVMRegion(region); |
| + } |
| + pmd->set_has_process_mmaps(); |
|
Mark Mentovai
2017/01/03 20:07:46
This only gets things that dyld knows about, inclu
Primiano Tucci (use gerrit)
2017/01/06 10:43:44
On Linux/Android we deliberately decided to grab a
|
| + return true; |
| +} |
| +#endif // defined(OS_MACOSX) |
| + |
| // static |
| void ProcessMetricsMemoryDumpProvider::RegisterForProcess( |
| base::ProcessId process) { |
| @@ -267,11 +342,11 @@ bool ProcessMetricsMemoryDumpProvider::OnMemoryDump( |
| base::trace_event::ProcessMemoryDump* pmd) { |
| bool res = DumpProcessTotals(args, pmd); |
| -#if defined(OS_LINUX) || defined(OS_ANDROID) |
| +#if defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MACOSX) |
| if (args.level_of_detail == |
| base::trace_event::MemoryDumpLevelOfDetail::DETAILED) |
| res &= DumpProcessMemoryMaps(args, pmd); |
| -#endif |
| +#endif // defined(OS_LINUX) || defined(OS_ANDROID) || defined(OS_MACOSX) |
| return res; |
| } |