1 : /*
2 : * Copyright (c) 2012 The Native Client Authors. All rights reserved.
3 : * Use of this source code is governed by a BSD-style license that can be
4 : * found in the LICENSE file.
5 : */
6 :
7 : #include "native_client/src/trusted/service_runtime/mmap_test_check.h"
8 :
9 : #include <mach/mach.h>
10 : #include <mach/mach_vm.h>
11 : #include <stdio.h>
12 :
13 : #include "native_client/src/include/nacl_assert.h"
14 :
15 :
16 : namespace {
17 :
18 : // Returns information about one or more VM region located at or above
19 : // |address| by calling |mach_vm_region| repeatedly to determine the size of a
20 : // contiguous region composed of multiple smaller regions that have the same
21 : // protection and sharing flags set. Returns the number of smaller regions
22 : // that were coalesced, which may be 0, in which case the out parameters are
23 : // not valid. |region_address|, |region_size|, |region_protection|, and
24 : // |region_share_mode| are set according to the characteristics of the large
25 : // region.
26 : //
27 : // This is necessary because a single anonymous mmap() for a large region will
28 : // be broken up into 128MB chunks in the kernel's VM map when allocated - see
29 : // ANON_CHUNK_SIZE in 10.8.2 xnu-2050.18.24/osfmk/vm/vm_map.c vm_map_enter.
30 14 : size_t CoalescedVMRegionInfo(mach_vm_address_t address,
31 14 : mach_vm_address_t *region_address,
32 14 : mach_vm_size_t *region_size,
33 14 : vm_prot_t *region_protection,
34 14 : unsigned char *region_share_mode) {
35 14 : mach_port_t self_task = mach_task_self();
36 :
37 14 : mach_vm_address_t this_region_address = address;
38 14 : mach_vm_size_t this_region_size;
39 14 : vm_region_extended_info_data_t info;
40 14 : mach_msg_type_number_t info_count = VM_REGION_EXTENDED_INFO_COUNT;
41 14 : mach_port_t object;
42 14 : kern_return_t kr = mach_vm_region(self_task,
43 : &this_region_address,
44 : &this_region_size,
45 : VM_REGION_EXTENDED_INFO,
46 : reinterpret_cast<vm_region_info_t>(&info),
47 : &info_count,
48 : &object);
49 14 : if (kr != KERN_SUCCESS) {
50 0 : return 0;
51 : }
52 :
53 14 : kr = mach_port_deallocate(self_task, object);
54 42 : ASSERT_EQ(kr, KERN_SUCCESS);
55 :
56 14 : size_t regions = 1;
57 14 : *region_address = this_region_address;
58 14 : *region_size = this_region_size;
59 14 : *region_protection = info.protection;
60 14 : *region_share_mode = info.share_mode;
61 :
62 14 : while (true) {
63 659 : this_region_address += this_region_size;
64 659 : mach_vm_address_t probe_address = this_region_address;
65 :
66 659 : kr = mach_vm_region(self_task,
67 : &this_region_address,
68 : &this_region_size,
69 : VM_REGION_EXTENDED_INFO,
70 : reinterpret_cast<vm_region_info_t>(&info),
71 : &info_count,
72 : &object);
73 659 : if (kr != KERN_SUCCESS) {
74 0 : break;
75 : }
76 :
77 659 : kr = mach_port_deallocate(self_task, object);
78 1977 : ASSERT_EQ(kr, KERN_SUCCESS);
79 :
80 1964 : if (this_region_address != probe_address ||
81 : *region_protection != info.protection ||
82 : *region_share_mode != info.share_mode) {
83 14 : break;
84 : }
85 :
86 645 : *region_size += this_region_size;
87 645 : ++regions;
88 645 : }
89 :
90 14 : return regions;
91 14 : }
92 :
93 : } // namespace
94 :
95 14 : void CheckMapping(uintptr_t addr, size_t size, int protect, int map_type) {
96 14 : uintptr_t end = addr + size - 1;
97 :
98 14 : mach_vm_address_t r_start;
99 14 : mach_vm_size_t r_size;
100 14 : vm_prot_t r_protection;
101 14 : unsigned char r_share_mode;
102 14 : size_t regions = CoalescedVMRegionInfo(addr,
103 : &r_start,
104 : &r_size,
105 : &r_protection,
106 : &r_share_mode);
107 42 : ASSERT_GT(regions, 0);
108 :
109 14 : mach_vm_address_t r_end = r_start + r_size - 1;
110 :
111 42 : ASSERT_LE(r_start, addr);
112 42 : ASSERT_GE(r_end, end);
113 42 : ASSERT_EQ(r_protection, protect);
114 : // TODO(phosek): not sure whether this check is correct
115 42 : ASSERT_EQ(r_share_mode, map_type);
116 14 : }
|