]>
Commit | Line | Data |
---|---|---|
cb323159 A |
1 | #include <darwintest.h> |
2 | #include <darwintest_utils.h> | |
3 | #include <mach/mach.h> | |
4 | #include <mach/task_info.h> | |
5 | #include <mach/vm_region.h> | |
6 | #include <mach/mach_vm.h> | |
7 | #include <sys/kern_sysctl.h> | |
8 | #include <errno.h> | |
9 | ||
10 | static const char* g_sysctl_name = "vm.get_owned_vmobjects"; | |
11 | ||
12 | static void | |
13 | main_test(void) | |
14 | { | |
15 | int ret; | |
16 | mach_port_name_t task_name; | |
17 | vmobject_list_output_t out_buffer; | |
18 | size_t out_size; | |
19 | size_t output_size; | |
20 | const vm_size_t tmp_size = 16 * 1024 * 1024; /* arbitrary size */ | |
21 | vm_address_t tmp_buf; | |
22 | vm_address_t tmp_buf2; | |
23 | mach_vm_size_t addr_size; | |
24 | mach_vm_address_t addr; | |
25 | kern_return_t kr; | |
26 | mach_port_t __self = mach_task_self(); | |
27 | vm_region_submap_info_data_64_t regionInfo; | |
28 | uint32_t nestingDepth; | |
29 | mach_msg_type_number_t count; | |
30 | ||
31 | /* allocate a temporary buffer */ | |
32 | kr = vm_allocate(__self, &tmp_buf, tmp_size, VM_FLAGS_ANYWHERE | VM_FLAGS_PURGABLE); | |
33 | T_QUIET; | |
34 | T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_allocate(%zu) error 0x%x (%s)", | |
4ba76501 | 35 | (size_t) tmp_size, kr, mach_error_string(kr)); |
cb323159 | 36 | T_QUIET; |
4ba76501 | 37 | T_EXPECT_NE(tmp_buf, (vm_address_t) 0, "failed to allocate temporary purgable buffer\n"); |
cb323159 A |
38 | |
39 | kr = vm_allocate(__self, &tmp_buf2, tmp_size, VM_FLAGS_ANYWHERE | VM_FLAGS_PURGABLE); | |
40 | T_QUIET; | |
41 | T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_allocate(%zu) error 0x%x (%s)", | |
4ba76501 | 42 | (size_t) tmp_size, kr, mach_error_string(kr)); |
cb323159 | 43 | T_QUIET; |
4ba76501 | 44 | T_EXPECT_NE(tmp_buf2, (vm_address_t) 0, "failed to allocate temporary purgable buffer\n"); |
cb323159 A |
45 | |
46 | /* expected failures */ | |
47 | out_size = tmp_size; | |
48 | ret = sysctlbyname(g_sysctl_name, NULL, 0, NULL, 0); | |
49 | T_EXPECT_EQ(ret, -1, "expected failure with 0 parameters\n"); | |
50 | T_EXPECT_EQ(errno, EINVAL, "expected EINVAL with 0 parameters\n"); | |
51 | ||
52 | ret = sysctlbyname(g_sysctl_name, (void*) tmp_buf, &out_size, NULL, 0); | |
53 | T_EXPECT_EQ(ret, -1, "expected failure with no new parameters\n"); | |
54 | T_EXPECT_EQ(errno, EINVAL, "expected EINVAL with 0 new parameters\n"); | |
55 | ||
56 | out_size = tmp_size; | |
57 | ret = sysctlbyname(g_sysctl_name, NULL, 0, (void*) tmp_buf, out_size); | |
58 | T_EXPECT_EQ(ret, -1, "expected failure with no old parameters\n"); | |
59 | T_EXPECT_EQ(errno, EINVAL, "expected EINVAL with 0 old parameters\n"); | |
60 | ||
61 | task_name = MACH_PORT_NULL; | |
62 | ret = sysctlbyname(g_sysctl_name, (void*) tmp_buf, &out_size, &task_name, sizeof(task_name)); | |
63 | T_EXPECT_EQ(ret, -1, "expected failure with task_name == MACH_PORT_NULL in new parameters\n"); | |
64 | T_EXPECT_EQ(errno, ESRCH, "expected ESRCH with invalid task port name\n"); | |
65 | ||
66 | /* we should get the number of entries we should allocate for */ | |
67 | out_size = 0; | |
68 | output_size = 0; | |
69 | task_name = mach_task_self(); | |
70 | ret = sysctlbyname(g_sysctl_name, NULL, &out_size, &task_name, sizeof(task_name)); | |
71 | T_QUIET; | |
72 | T_EXPECT_EQ(ret, 0, "failed getting the number of entries\n"); | |
73 | T_EXPECT_EQ(out_size, 2 * sizeof(vm_object_query_data_t) + sizeof(int64_t), "expeccted one entry\n"); | |
74 | ||
75 | /* calculcate and allocate the proper sized output buffer */ | |
76 | output_size = out_size; | |
77 | out_buffer = (vmobject_list_output_t)calloc(output_size, 1); | |
78 | T_QUIET; | |
79 | T_EXPECT_NE(out_buffer, NULL, "failed to allocate the output buffer for sysctlbyname\n"); | |
80 | ||
81 | /* get the truncated list for the current process */ | |
82 | memset(out_buffer, 0, output_size); | |
83 | out_size = 1 * sizeof(vm_object_query_data_t) + sizeof(int64_t); | |
84 | ret = sysctlbyname(g_sysctl_name, out_buffer, &out_size, &task_name, sizeof(task_name)); | |
85 | ||
86 | T_QUIET; | |
87 | T_EXPECT_EQ(ret, 0, "sysctlbyname failed\n"); | |
88 | T_EXPECT_EQ(out_size, 1 * sizeof(vm_object_query_data_t) + sizeof(int64_t), "sysctl return size is incorrect\n"); | |
89 | T_EXPECT_EQ(out_buffer->entries, 1ULL, "should have 1 vm object\n"); | |
90 | T_EXPECT_NE(out_buffer->data[0].object_id, 0ULL, "vm_object_id should not be 0\n"); | |
91 | ||
92 | /* get the list for the current process */ | |
93 | out_size = output_size; | |
94 | memset(out_buffer, 0, output_size); | |
95 | ret = sysctlbyname(g_sysctl_name, out_buffer, &out_size, &task_name, sizeof(task_name)); | |
96 | ||
97 | T_QUIET; | |
98 | T_EXPECT_EQ(ret, 0, "sysctlbyname failed\n"); | |
99 | T_EXPECT_EQ(out_size, 2 * sizeof(vm_object_query_data_t) + sizeof(int64_t), "sysctl return size is incorrect\n"); | |
100 | T_EXPECT_EQ(out_buffer->entries, 2ULL, "should have 2 vm objects\n"); | |
101 | T_EXPECT_NE(out_buffer->data[0].object_id, 0ULL, "vm_object_id should not be 0\n"); | |
102 | ||
103 | addr = tmp_buf; | |
104 | addr_size = tmp_size; | |
105 | nestingDepth = UINT_MAX; | |
106 | count = VM_REGION_SUBMAP_INFO_V2_COUNT_64; | |
107 | kr = mach_vm_region_recurse(__self, &addr, &addr_size, &nestingDepth, (vm_region_info_t)®ionInfo, &count); | |
108 | T_QUIET; | |
109 | T_EXPECT_EQ(kr, KERN_SUCCESS, "mach_vm_region_recurse(%zu) error 0x%x (%s)\n", | |
110 | tmp_size, kr, mach_error_string(kr)); | |
111 | T_EXPECT_EQ(regionInfo.object_id_full, out_buffer->data[0].object_id, "object_id_full does not match out_buffer->object[0]\n"); | |
112 | ||
113 | addr = tmp_buf2; | |
114 | addr_size = tmp_size; | |
115 | nestingDepth = UINT_MAX; | |
116 | count = VM_REGION_SUBMAP_INFO_V2_COUNT_64; | |
117 | kr = mach_vm_region_recurse(__self, &addr, &addr_size, &nestingDepth, (vm_region_info_t)®ionInfo, &count); | |
118 | T_QUIET; | |
119 | T_EXPECT_EQ(kr, KERN_SUCCESS, "mach_vm_region_recurse(%zu) error 0x%x (%s)\n", | |
120 | tmp_size, kr, mach_error_string(kr)); | |
121 | T_EXPECT_EQ(regionInfo.object_id_full, out_buffer->data[1].object_id, "object_id_full does not match out_buffer->object[1]\n"); | |
122 | ||
123 | kr = vm_deallocate(__self, tmp_buf, tmp_size); | |
124 | T_QUIET; | |
125 | T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate(%zu) error 0x%x (%s)\n", | |
126 | tmp_size, kr, mach_error_string(kr)); | |
127 | ||
128 | kr = vm_deallocate(__self, tmp_buf2, tmp_size); | |
129 | T_QUIET; | |
130 | T_EXPECT_EQ(kr, KERN_SUCCESS, "vm_deallocate(%zu) error 0x%x (%s)\n", | |
131 | tmp_size, kr, mach_error_string(kr)); | |
132 | ||
133 | free(out_buffer); | |
134 | out_buffer = NULL; | |
135 | } | |
136 | ||
137 | T_DECL(test_get_vmobject_list, "Get owned vm_objects for process") | |
138 | { | |
139 | main_test(); | |
140 | } |