blob: 3b86a83024d93ca14b8a2800bdc9fd7837508fa7 [file] [log] [blame]
Chris Lattner30fdc8d2010-06-08 16:52:24 +00001//===-- MachVMMemory.cpp ----------------------------------------*- C++ -*-===//
2//
3// The LLVM Compiler Infrastructure
4//
5// This file is distributed under the University of Illinois Open Source
6// License. See LICENSE.TXT for details.
7//
8//===----------------------------------------------------------------------===//
9//
10// Created by Greg Clayton on 6/26/07.
11//
12//===----------------------------------------------------------------------===//
13
14#include "MachVMMemory.h"
15#include "MachVMRegion.h"
16#include "DNBLog.h"
17#include <mach/mach_vm.h>
Han Ming Ongab3b8b22012-11-17 00:21:04 +000018#include <mach/shared_region.h>
Han Ming Ong8594ae82012-11-27 19:21:03 +000019#include <sys/sysctl.h>
Han Ming Ongb153c2f2013-05-22 21:32:42 +000020#include <dlfcn.h>
Chris Lattner30fdc8d2010-06-08 16:52:24 +000021
Bruce Mitchenerdcad05b2015-09-01 23:45:14 +000022static const vm_size_t kInvalidPageSize = ~0;
23
Chris Lattner30fdc8d2010-06-08 16:52:24 +000024MachVMMemory::MachVMMemory() :
25 m_page_size (kInvalidPageSize),
26 m_err (0)
27{
28}
29
30MachVMMemory::~MachVMMemory()
31{
32}
33
34nub_size_t
Jason Molendabecd6392013-04-06 07:16:15 +000035MachVMMemory::PageSize(task_t task)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000036{
37 if (m_page_size == kInvalidPageSize)
38 {
Jason Molendabecd6392013-04-06 07:16:15 +000039#if defined (TASK_VM_INFO) && TASK_VM_INFO >= 22
40 if (task != TASK_NULL)
41 {
42 kern_return_t kr;
43 mach_msg_type_number_t info_count = TASK_VM_INFO_COUNT;
44 task_vm_info_data_t vm_info;
45 kr = task_info (task, TASK_VM_INFO, (task_info_t) &vm_info, &info_count);
46 if (kr == KERN_SUCCESS)
47 {
Jason Molendabef3f862013-04-06 07:28:38 +000048 DNBLogThreadedIf(LOG_TASK, "MachVMMemory::PageSize task_info returned page size of 0x%x", (int) vm_info.page_size);
Jason Molenda63742f12013-04-06 20:30:59 +000049 m_page_size = vm_info.page_size;
50 return m_page_size;
Jason Molendabecd6392013-04-06 07:16:15 +000051 }
Jason Molenda272ee612013-04-06 07:26:59 +000052 else
53 {
54 DNBLogThreadedIf(LOG_TASK, "MachVMMemory::PageSize task_info call failed to get page size, TASK_VM_INFO %d, TASK_VM_INFO_COUNT %d, kern return %d", TASK_VM_INFO, TASK_VM_INFO_COUNT, kr);
55 }
Jason Molendabecd6392013-04-06 07:16:15 +000056 }
57#endif
Chris Lattner30fdc8d2010-06-08 16:52:24 +000058 m_err = ::host_page_size( ::mach_host_self(), &m_page_size);
59 if (m_err.Fail())
60 m_page_size = 0;
61 }
62 return m_page_size;
63}
64
65nub_size_t
Jason Molendabecd6392013-04-06 07:16:15 +000066MachVMMemory::MaxBytesLeftInPage(task_t task, nub_addr_t addr, nub_size_t count)
Chris Lattner30fdc8d2010-06-08 16:52:24 +000067{
Jason Molendabecd6392013-04-06 07:16:15 +000068 const nub_size_t page_size = PageSize(task);
Chris Lattner30fdc8d2010-06-08 16:52:24 +000069 if (page_size > 0)
70 {
71 nub_size_t page_offset = (addr % page_size);
72 nub_size_t bytes_left_in_page = page_size - page_offset;
73 if (count > bytes_left_in_page)
74 count = bytes_left_in_page;
75 }
76 return count;
77}
78
Greg Claytonfc5dd292011-12-12 18:51:14 +000079nub_bool_t
Greg Clayton46fb5582011-11-18 07:03:08 +000080MachVMMemory::GetMemoryRegionInfo(task_t task, nub_addr_t address, DNBRegionInfo *region_info)
Jason Molenda1f3966b2011-11-08 04:28:12 +000081{
82 MachVMRegion vmRegion(task);
83
Greg Clayton46fb5582011-11-18 07:03:08 +000084 if (vmRegion.GetRegionForAddress(address))
85 {
86 region_info->addr = vmRegion.StartAddress();
87 region_info->size = vmRegion.GetByteSize();
88 region_info->permissions = vmRegion.GetDNBPermissions();
Greg Clayton46fb5582011-11-18 07:03:08 +000089 }
Greg Claytonfc5dd292011-12-12 18:51:14 +000090 else
91 {
92 region_info->addr = address;
93 region_info->size = 0;
94 if (vmRegion.GetError().Success())
95 {
96 // vmRegion.GetRegionForAddress() return false, indicating that "address"
97 // wasn't in a valid region, but the "vmRegion" info was successfully
98 // read from the task which means the info describes the next valid
99 // region from which we can infer the size of this invalid region
100 mach_vm_address_t start_addr = vmRegion.StartAddress();
101 if (address < start_addr)
102 region_info->size = start_addr - address;
103 }
Greg Claytona2715cf2014-06-13 00:54:12 +0000104 // If we can't get any info about the size from the next region it means
105 // we asked about an address that was past all mappings, so the size
106 // of this region will take up all remaining address space.
Greg Claytonfc5dd292011-12-12 18:51:14 +0000107 if (region_info->size == 0)
Greg Claytona2715cf2014-06-13 00:54:12 +0000108 region_info->size = INVALID_NUB_ADDRESS - region_info->addr;
Greg Claytonfc5dd292011-12-12 18:51:14 +0000109
110 // Not readable, writeable or executable
111 region_info->permissions = 0;
112 }
113 return true;
Jason Molenda1f3966b2011-11-08 04:28:12 +0000114}
115
Han Ming Ong8594ae82012-11-27 19:21:03 +0000116// For integrated graphics chip, this makes the accounting info for 'wired' memory more like top.
Jason Molendabecd6392013-04-06 07:16:15 +0000117uint64_t
118MachVMMemory::GetStolenPages(task_t task)
Han Ming Ong8594ae82012-11-27 19:21:03 +0000119{
120 static uint64_t stolenPages = 0;
121 static bool calculated = false;
122 if (calculated) return stolenPages;
123
124 static int mib_reserved[CTL_MAXNAME];
125 static int mib_unusable[CTL_MAXNAME];
126 static int mib_other[CTL_MAXNAME];
127 static size_t mib_reserved_len = 0;
128 static size_t mib_unusable_len = 0;
129 static size_t mib_other_len = 0;
130 int r;
131
132 /* This can be used for testing: */
133 //tsamp->pages_stolen = (256 * 1024 * 1024ULL) / tsamp->pagesize;
134
135 if(0 == mib_reserved_len)
136 {
137 mib_reserved_len = CTL_MAXNAME;
138
139 r = sysctlnametomib("machdep.memmap.Reserved", mib_reserved,
140 &mib_reserved_len);
141
142 if(-1 == r)
143 {
144 mib_reserved_len = 0;
145 return 0;
146 }
147
148 mib_unusable_len = CTL_MAXNAME;
149
150 r = sysctlnametomib("machdep.memmap.Unusable", mib_unusable,
151 &mib_unusable_len);
152
153 if(-1 == r)
154 {
155 mib_reserved_len = 0;
156 return 0;
157 }
158
159
160 mib_other_len = CTL_MAXNAME;
161
162 r = sysctlnametomib("machdep.memmap.Other", mib_other,
163 &mib_other_len);
164
165 if(-1 == r)
166 {
167 mib_reserved_len = 0;
168 return 0;
169 }
170 }
171
172 if(mib_reserved_len > 0 && mib_unusable_len > 0 && mib_other_len > 0)
173 {
174 uint64_t reserved = 0, unusable = 0, other = 0;
175 size_t reserved_len;
176 size_t unusable_len;
177 size_t other_len;
178
179 reserved_len = sizeof(reserved);
180 unusable_len = sizeof(unusable);
181 other_len = sizeof(other);
182
183 /* These are all declared as QUAD/uint64_t sysctls in the kernel. */
184
Greg Claytonee2ed522015-03-09 19:45:23 +0000185 if (sysctl (mib_reserved,
186 static_cast<u_int>(mib_reserved_len),
187 &reserved,
188 &reserved_len,
189 NULL,
190 0))
Han Ming Ong8594ae82012-11-27 19:21:03 +0000191 {
192 return 0;
193 }
194
Greg Claytonee2ed522015-03-09 19:45:23 +0000195 if (sysctl (mib_unusable,
196 static_cast<u_int>(mib_unusable_len),
197 &unusable,
198 &unusable_len,
199 NULL,
200 0))
Han Ming Ong8594ae82012-11-27 19:21:03 +0000201 {
202 return 0;
203 }
204
Greg Claytonee2ed522015-03-09 19:45:23 +0000205 if (sysctl (mib_other,
206 static_cast<u_int>(mib_other_len),
207 &other,
208 &other_len,
209 NULL,
210 0))
Han Ming Ong8594ae82012-11-27 19:21:03 +0000211 {
212 return 0;
213 }
214
Greg Claytonee2ed522015-03-09 19:45:23 +0000215 if (reserved_len == sizeof(reserved) &&
216 unusable_len == sizeof(unusable) &&
217 other_len == sizeof(other))
Han Ming Ong8594ae82012-11-27 19:21:03 +0000218 {
219 uint64_t stolen = reserved + unusable + other;
220 uint64_t mb128 = 128 * 1024 * 1024ULL;
221
222 if(stolen >= mb128)
223 {
224 stolen = (stolen & ~((128 * 1024 * 1024ULL) - 1)); // rounding down
Jason Molendafe806902013-05-04 00:39:52 +0000225 stolenPages = stolen / PageSize (task);
Han Ming Ong8594ae82012-11-27 19:21:03 +0000226 }
227 }
228 }
229
230 calculated = true;
231 return stolenPages;
232}
233
234static uint64_t GetPhysicalMemory()
235{
236 // This doesn't change often at all. No need to poll each time.
237 static uint64_t physical_memory = 0;
238 static bool calculated = false;
239 if (calculated) return physical_memory;
240
Han Ming Ong8594ae82012-11-27 19:21:03 +0000241 size_t len = sizeof(physical_memory);
Han Ming Ong74c14812015-06-25 23:39:56 +0000242 sysctlbyname("hw.memsize", &physical_memory, &len, NULL, 0);
243
244 calculated = true;
Han Ming Ong8594ae82012-11-27 19:21:03 +0000245 return physical_memory;
246}
247
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000248// rsize and dirty_size is not adjusted for dyld shared cache and multiple __LINKEDIT segment, as in vmmap. In practice, dirty_size doesn't differ much but rsize may. There is performance penalty for the adjustment. Right now, only use the dirty_size.
Jason Molendabecd6392013-04-06 07:16:15 +0000249void
250MachVMMemory::GetRegionSizes(task_t task, mach_vm_size_t &rsize, mach_vm_size_t &dirty_size)
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000251{
Han Ming Ongb4e1d4c2013-06-26 22:52:37 +0000252#if defined (TASK_VM_INFO) && TASK_VM_INFO >= 22
253
254 task_vm_info_data_t vm_info;
255 mach_msg_type_number_t info_count;
256 kern_return_t kr;
257
258 info_count = TASK_VM_INFO_COUNT;
Han Ming Ongb4e1d4c2013-06-26 22:52:37 +0000259 kr = task_info(task, TASK_VM_INFO_PURGEABLE, (task_info_t)&vm_info, &info_count);
Han Ming Ongb4e1d4c2013-06-26 22:52:37 +0000260 if (kr == KERN_SUCCESS)
261 dirty_size = vm_info.internal;
Han Ming Ongb4e1d4c2013-06-26 22:52:37 +0000262#endif
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000263}
264
265// Test whether the virtual address is within the architecture's shared region.
266static bool InSharedRegion(mach_vm_address_t addr, cpu_type_t type)
267{
Jason Molendad251c9d2012-11-17 01:41:04 +0000268 mach_vm_address_t base = 0, size = 0;
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000269
Jason Molendad251c9d2012-11-17 01:41:04 +0000270 switch(type) {
Jason Molendaa3329782014-03-29 18:54:20 +0000271#if defined (CPU_TYPE_ARM64) && defined (SHARED_REGION_BASE_ARM64)
272 case CPU_TYPE_ARM64:
273 base = SHARED_REGION_BASE_ARM64;
274 size = SHARED_REGION_SIZE_ARM64;
275 break;
276#endif
277
Jason Molendad251c9d2012-11-17 01:41:04 +0000278 case CPU_TYPE_ARM:
279 base = SHARED_REGION_BASE_ARM;
280 size = SHARED_REGION_SIZE_ARM;
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000281 break;
Jason Molendaa3329782014-03-29 18:54:20 +0000282
Jason Molendad251c9d2012-11-17 01:41:04 +0000283 case CPU_TYPE_X86_64:
284 base = SHARED_REGION_BASE_X86_64;
285 size = SHARED_REGION_SIZE_X86_64;
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000286 break;
287
Jason Molendad251c9d2012-11-17 01:41:04 +0000288 case CPU_TYPE_I386:
289 base = SHARED_REGION_BASE_I386;
290 size = SHARED_REGION_SIZE_I386;
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000291 break;
292
Jason Molendad251c9d2012-11-17 01:41:04 +0000293 default: {
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000294 // Log error abut unknown CPU type
295 break;
Jason Molendad251c9d2012-11-17 01:41:04 +0000296 }
297 }
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000298
299
Jason Molendad251c9d2012-11-17 01:41:04 +0000300 return(addr >= base && addr < (base + size));
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000301}
302
Jason Molendabecd6392013-04-06 07:16:15 +0000303void
304MachVMMemory::GetMemorySizes(task_t task, cpu_type_t cputype, nub_process_t pid, mach_vm_size_t &rprvt, mach_vm_size_t &vprvt)
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000305{
306 // Collecting some other info cheaply but not reporting for now.
307 mach_vm_size_t empty = 0;
Jason Molendad251c9d2012-11-17 01:41:04 +0000308 mach_vm_size_t fw_private = 0;
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000309
Jason Molendad251c9d2012-11-17 01:41:04 +0000310 mach_vm_size_t aliased = 0;
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000311 bool global_shared_text_data_mapped = false;
Han Ming Ongb153c2f2013-05-22 21:32:42 +0000312 vm_size_t pagesize = PageSize (task);
Han Ming Ong6f7237d2013-03-25 20:44:40 +0000313
Jason Molendad251c9d2012-11-17 01:41:04 +0000314 for (mach_vm_address_t addr=0, size=0; ; addr += size)
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000315 {
Jason Molendad251c9d2012-11-17 01:41:04 +0000316 vm_region_top_info_data_t info;
317 mach_msg_type_number_t count = VM_REGION_TOP_INFO_COUNT;
318 mach_port_t object_name;
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000319
Jason Molendad251c9d2012-11-17 01:41:04 +0000320 kern_return_t kr = mach_vm_region(task, &addr, &size, VM_REGION_TOP_INFO, (vm_region_info_t)&info, &count, &object_name);
321 if (kr != KERN_SUCCESS) break;
322
323 if (InSharedRegion(addr, cputype))
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000324 {
Jason Molendad251c9d2012-11-17 01:41:04 +0000325 // Private Shared
326 fw_private += info.private_pages_resident * pagesize;
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000327
Jason Molendad251c9d2012-11-17 01:41:04 +0000328 // Check if this process has the globally shared text and data regions mapped in. If so, set global_shared_text_data_mapped to TRUE and avoid checking again.
329 if (global_shared_text_data_mapped == FALSE && info.share_mode == SM_EMPTY) {
Han Ming Ong6f7237d2013-03-25 20:44:40 +0000330 vm_region_basic_info_data_64_t b_info;
Jason Molendad251c9d2012-11-17 01:41:04 +0000331 mach_vm_address_t b_addr = addr;
332 mach_vm_size_t b_size = size;
333 count = VM_REGION_BASIC_INFO_COUNT_64;
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000334
Jason Molendad251c9d2012-11-17 01:41:04 +0000335 kr = mach_vm_region(task, &b_addr, &b_size, VM_REGION_BASIC_INFO, (vm_region_info_t)&b_info, &count, &object_name);
336 if (kr != KERN_SUCCESS) break;
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000337
Jason Molendad251c9d2012-11-17 01:41:04 +0000338 if (b_info.reserved) {
339 global_shared_text_data_mapped = TRUE;
340 }
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000341 }
Jason Molendad251c9d2012-11-17 01:41:04 +0000342
343 // Short circuit the loop if this isn't a shared private region, since that's the only region type we care about within the current address range.
344 if (info.share_mode != SM_PRIVATE)
345 {
346 continue;
347 }
348 }
349
350 // Update counters according to the region type.
351 if (info.share_mode == SM_COW && info.ref_count == 1)
352 {
353 // Treat single reference SM_COW as SM_PRIVATE
354 info.share_mode = SM_PRIVATE;
355 }
356
357 switch (info.share_mode)
358 {
359 case SM_LARGE_PAGE:
360 // Treat SM_LARGE_PAGE the same as SM_PRIVATE
361 // since they are not shareable and are wired.
362 case SM_PRIVATE:
363 rprvt += info.private_pages_resident * pagesize;
364 rprvt += info.shared_pages_resident * pagesize;
365 vprvt += size;
366 break;
367
368 case SM_EMPTY:
369 empty += size;
370 break;
371
372 case SM_COW:
373 case SM_SHARED:
374 {
375 if (pid == 0)
376 {
377 // Treat kernel_task specially
378 if (info.share_mode == SM_COW)
379 {
380 rprvt += info.private_pages_resident * pagesize;
381 vprvt += size;
382 }
383 break;
384 }
385
386 if (info.share_mode == SM_COW)
387 {
388 rprvt += info.private_pages_resident * pagesize;
389 vprvt += info.private_pages_resident * pagesize;
390 }
391 break;
392 }
393 default:
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000394 // log that something is really bad.
Jason Molendad251c9d2012-11-17 01:41:04 +0000395 break;
396 }
397 }
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000398
Jason Molendad251c9d2012-11-17 01:41:04 +0000399 rprvt += aliased;
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000400}
401
Han Ming Ongb153c2f2013-05-22 21:32:42 +0000402static void
403GetPurgeableAndAnonymous(task_t task, uint64_t &purgeable, uint64_t &anonymous)
404{
405#if defined (TASK_VM_INFO) && TASK_VM_INFO >= 22
406
407 kern_return_t kr;
Han Ming Ongb153c2f2013-05-22 21:32:42 +0000408 mach_msg_type_number_t info_count;
409 task_vm_info_data_t vm_info;
410
Han Ming Ongb153c2f2013-05-22 21:32:42 +0000411 info_count = TASK_VM_INFO_COUNT;
Han Ming Ong6db14a92013-06-26 20:46:27 +0000412 kr = task_info(task, TASK_VM_INFO_PURGEABLE, (task_info_t)&vm_info, &info_count);
Han Ming Ongb153c2f2013-05-22 21:32:42 +0000413 if (kr == KERN_SUCCESS)
414 {
Han Ming Ong6db14a92013-06-26 20:46:27 +0000415 purgeable = vm_info.purgeable_volatile_resident;
Han Ming Ongcd2d7972014-09-03 22:33:37 +0000416 anonymous = vm_info.internal + vm_info.compressed - vm_info.purgeable_volatile_pmap;
Han Ming Ongb153c2f2013-05-22 21:32:42 +0000417 }
Han Ming Ong6db14a92013-06-26 20:46:27 +0000418
Han Ming Ongb153c2f2013-05-22 21:32:42 +0000419#endif
420}
421
Han Ming Ong74c14812015-06-25 23:39:56 +0000422#if defined (HOST_VM_INFO64_COUNT)
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000423nub_bool_t
Han Ming Ong74c14812015-06-25 23:39:56 +0000424MachVMMemory::GetMemoryProfile(DNBProfileDataScanType scanType, task_t task, struct task_basic_info ti, cpu_type_t cputype, nub_process_t pid, vm_statistics64_data_t &vminfo, uint64_t &physical_memory, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size, mach_vm_size_t &purgeable, mach_vm_size_t &anonymous)
Han Ming Ong459a23e2015-06-26 00:04:51 +0000425#else
Han Ming Ong74c14812015-06-25 23:39:56 +0000426nub_bool_t
427MachVMMemory::GetMemoryProfile(DNBProfileDataScanType scanType, task_t task, struct task_basic_info ti, cpu_type_t cputype, nub_process_t pid, vm_statistics_data_t &vminfo, uint64_t &physical_memory, mach_vm_size_t &rprvt, mach_vm_size_t &rsize, mach_vm_size_t &vprvt, mach_vm_size_t &vsize, mach_vm_size_t &dirty_size, mach_vm_size_t &purgeable, mach_vm_size_t &anonymous)
428#endif
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000429{
Han Ming Ong8764fe72013-03-04 21:25:51 +0000430 if (scanType & eProfileHostMemory)
431 physical_memory = GetPhysicalMemory();
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000432
Han Ming Ong8764fe72013-03-04 21:25:51 +0000433 if (scanType & eProfileMemory)
434 {
435 static mach_port_t localHost = mach_host_self();
Han Ming Ong74c14812015-06-25 23:39:56 +0000436#if defined (HOST_VM_INFO64_COUNT)
437 mach_msg_type_number_t count = HOST_VM_INFO64_COUNT;
438 host_statistics64(localHost, HOST_VM_INFO64, (host_info64_t)&vminfo, &count);
Han Ming Ong459a23e2015-06-26 00:04:51 +0000439#else
Han Ming Ong8764fe72013-03-04 21:25:51 +0000440 mach_msg_type_number_t count = HOST_VM_INFO_COUNT;
Han Ming Ong74c14812015-06-25 23:39:56 +0000441 host_statistics(localHost, HOST_VM_INFO, (host_info_t)&vminfo, &count);
442 vminfo.wire_count += GetStolenPages(task);
443#endif
444
445 /* We are no longer reporting these. Let's not waste time.
Han Ming Ong8764fe72013-03-04 21:25:51 +0000446 GetMemorySizes(task, cputype, pid, rprvt, vprvt);
Han Ming Ong8764fe72013-03-04 21:25:51 +0000447 rsize = ti.resident_size;
448 vsize = ti.virtual_size;
Han Ming Ong0c27cb72013-03-13 22:51:04 +0000449
450 if (scanType & eProfileMemoryDirtyPage)
451 {
452 // This uses vmmap strategy. We don't use the returned rsize for now. We prefer to match top's version since that's what we do for the rest of the metrics.
453 GetRegionSizes(task, rsize, dirty_size);
454 }
Han Ming Ong74c14812015-06-25 23:39:56 +0000455 */
Han Ming Ongb153c2f2013-05-22 21:32:42 +0000456
457 if (scanType & eProfileMemoryAnonymous)
458 {
459 GetPurgeableAndAnonymous(task, purgeable, anonymous);
460 }
Han Ming Ong8764fe72013-03-04 21:25:51 +0000461 }
Han Ming Ongab3b8b22012-11-17 00:21:04 +0000462
463 return true;
464}
465
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000466nub_size_t
467MachVMMemory::Read(task_t task, nub_addr_t address, void *data, nub_size_t data_count)
468{
469 if (data == NULL || data_count == 0)
470 return 0;
471
472 nub_size_t total_bytes_read = 0;
473 nub_addr_t curr_addr = address;
474 uint8_t *curr_data = (uint8_t*)data;
475 while (total_bytes_read < data_count)
476 {
Jason Molendabecd6392013-04-06 07:16:15 +0000477 mach_vm_size_t curr_size = MaxBytesLeftInPage(task, curr_addr, data_count - total_bytes_read);
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000478 mach_msg_type_number_t curr_bytes_read = 0;
Bruce Mitchenera026de02015-07-22 17:31:44 +0000479 vm_offset_t vm_memory = 0;
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000480 m_err = ::mach_vm_read (task, curr_addr, curr_size, &vm_memory, &curr_bytes_read);
Jim Ingham70358852011-12-09 19:48:22 +0000481
Jim Ingham329617a2012-03-09 21:09:42 +0000482 if (DNBLogCheckLogBit(LOG_MEMORY))
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000483 m_err.LogThreaded("::mach_vm_read ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, data => %8.8p, dataCnt => %i )", task, (uint64_t)curr_addr, (uint64_t)curr_size, vm_memory, curr_bytes_read);
484
485 if (m_err.Success())
486 {
487 if (curr_bytes_read != curr_size)
488 {
489 if (DNBLogCheckLogBit(LOG_MEMORY))
490 m_err.LogThreaded("::mach_vm_read ( task = 0x%4.4x, addr = 0x%8.8llx, size = %llu, data => %8.8p, dataCnt=>%i ) only read %u of %llu bytes", task, (uint64_t)curr_addr, (uint64_t)curr_size, vm_memory, curr_bytes_read, curr_bytes_read, (uint64_t)curr_size);
491 }
492 ::memcpy (curr_data, (void *)vm_memory, curr_bytes_read);
493 ::vm_deallocate (mach_task_self (), vm_memory, curr_bytes_read);
494 total_bytes_read += curr_bytes_read;
495 curr_addr += curr_bytes_read;
496 curr_data += curr_bytes_read;
497 }
498 else
499 {
500 break;
501 }
502 }
503 return total_bytes_read;
504}
505
506
507nub_size_t
508MachVMMemory::Write(task_t task, nub_addr_t address, const void *data, nub_size_t data_count)
509{
510 MachVMRegion vmRegion(task);
511
512 nub_size_t total_bytes_written = 0;
513 nub_addr_t curr_addr = address;
514 const uint8_t *curr_data = (const uint8_t*)data;
515
516
517 while (total_bytes_written < data_count)
518 {
519 if (vmRegion.GetRegionForAddress(curr_addr))
520 {
521 mach_vm_size_t curr_data_count = data_count - total_bytes_written;
522 mach_vm_size_t region_bytes_left = vmRegion.BytesRemaining(curr_addr);
523 if (region_bytes_left == 0)
524 {
525 break;
526 }
527 if (curr_data_count > region_bytes_left)
528 curr_data_count = region_bytes_left;
529
530 if (vmRegion.SetProtections(curr_addr, curr_data_count, VM_PROT_READ | VM_PROT_WRITE))
531 {
532 nub_size_t bytes_written = WriteRegion(task, curr_addr, curr_data, curr_data_count);
533 if (bytes_written <= 0)
534 {
535 // Error should have already be posted by WriteRegion...
536 break;
537 }
538 else
539 {
540 total_bytes_written += bytes_written;
541 curr_addr += bytes_written;
542 curr_data += bytes_written;
543 }
544 }
545 else
546 {
547 DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS, "Failed to set read/write protections on region for address: [0x%8.8llx-0x%8.8llx)", (uint64_t)curr_addr, (uint64_t)(curr_addr + curr_data_count));
548 break;
549 }
550 }
551 else
552 {
553 DNBLogThreadedIf(LOG_MEMORY_PROTECTIONS, "Failed to get region for address: 0x%8.8llx", (uint64_t)address);
554 break;
555 }
556 }
557
558 return total_bytes_written;
559}
560
561
562nub_size_t
563MachVMMemory::WriteRegion(task_t task, const nub_addr_t address, const void *data, const nub_size_t data_count)
564{
565 if (data == NULL || data_count == 0)
566 return 0;
567
568 nub_size_t total_bytes_written = 0;
569 nub_addr_t curr_addr = address;
570 const uint8_t *curr_data = (const uint8_t*)data;
571 while (total_bytes_written < data_count)
572 {
Greg Claytonee2ed522015-03-09 19:45:23 +0000573 mach_msg_type_number_t curr_data_count = static_cast<mach_msg_type_number_t>(MaxBytesLeftInPage(task, curr_addr, data_count - total_bytes_written));
Chris Lattner30fdc8d2010-06-08 16:52:24 +0000574 m_err = ::mach_vm_write (task, curr_addr, (pointer_t) curr_data, curr_data_count);
575 if (DNBLogCheckLogBit(LOG_MEMORY) || m_err.Fail())
576 m_err.LogThreaded("::mach_vm_write ( task = 0x%4.4x, addr = 0x%8.8llx, data = %8.8p, dataCnt = %u )", task, (uint64_t)curr_addr, curr_data, curr_data_count);
577
578#if !defined (__i386__) && !defined (__x86_64__)
579 vm_machine_attribute_val_t mattr_value = MATTR_VAL_CACHE_FLUSH;
580
581 m_err = ::vm_machine_attribute (task, curr_addr, curr_data_count, MATTR_CACHE, &mattr_value);
582 if (DNBLogCheckLogBit(LOG_MEMORY) || m_err.Fail())
583 m_err.LogThreaded("::vm_machine_attribute ( task = 0x%4.4x, addr = 0x%8.8llx, size = %u, attr = MATTR_CACHE, mattr_value => MATTR_VAL_CACHE_FLUSH )", task, (uint64_t)curr_addr, curr_data_count);
584#endif
585
586 if (m_err.Success())
587 {
588 total_bytes_written += curr_data_count;
589 curr_addr += curr_data_count;
590 curr_data += curr_data_count;
591 }
592 else
593 {
594 break;
595 }
596 }
597 return total_bytes_written;
598}