1 #include <darwintest.h>
2 #include <darwintest_utils.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>
10 static const char* g_sysctl_name
= "vm.get_owned_vmobjects";
16 mach_port_name_t task_name
;
17 vmobject_list_output_t out_buffer
;
20 const vm_size_t tmp_size
= 16 * 1024 * 1024; /* arbitrary size */
22 vm_address_t tmp_buf2
;
23 mach_vm_size_t addr_size
;
24 mach_vm_address_t addr
;
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
;
31 /* allocate a temporary buffer */
32 kr
= vm_allocate(__self
, &tmp_buf
, tmp_size
, VM_FLAGS_ANYWHERE
| VM_FLAGS_PURGABLE
);
34 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_allocate(%zu) error 0x%x (%s)",
35 (size_t) tmp_size
, kr
, mach_error_string(kr
));
37 T_EXPECT_NE(tmp_buf
, (vm_address_t
) 0, "failed to allocate temporary purgable buffer\n");
39 kr
= vm_allocate(__self
, &tmp_buf2
, tmp_size
, VM_FLAGS_ANYWHERE
| VM_FLAGS_PURGABLE
);
41 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_allocate(%zu) error 0x%x (%s)",
42 (size_t) tmp_size
, kr
, mach_error_string(kr
));
44 T_EXPECT_NE(tmp_buf2
, (vm_address_t
) 0, "failed to allocate temporary purgable buffer\n");
46 /* expected failures */
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");
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");
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");
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");
66 /* we should get the number of entries we should allocate for */
69 task_name
= mach_task_self();
70 ret
= sysctlbyname(g_sysctl_name
, NULL
, &out_size
, &task_name
, sizeof(task_name
));
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");
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);
79 T_EXPECT_NE(out_buffer
, NULL
, "failed to allocate the output buffer for sysctlbyname\n");
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
));
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");
92 /* get the list for the current process with an overly large size */
94 memset(out_buffer
, 0, output_size
);
95 ret
= sysctlbyname(g_sysctl_name
, out_buffer
, &out_size
, &task_name
, sizeof(task_name
));
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");
103 /* get the list for the current process with the correct output size */
104 out_size
= output_size
;
105 memset(out_buffer
, 0, output_size
);
106 ret
= sysctlbyname(g_sysctl_name
, out_buffer
, &out_size
, &task_name
, sizeof(task_name
));
109 T_EXPECT_EQ(ret
, 0, "sysctlbyname failed\n");
110 T_EXPECT_EQ(out_size
, 2 * sizeof(vm_object_query_data_t
) + sizeof(int64_t), "sysctl return size is incorrect\n");
111 T_EXPECT_EQ(out_buffer
->entries
, 2ULL, "should have 2 vm objects\n");
112 T_EXPECT_NE(out_buffer
->data
[0].object_id
, 0ULL, "vm_object_id should not be 0\n");
115 addr_size
= tmp_size
;
116 nestingDepth
= UINT_MAX
;
117 count
= VM_REGION_SUBMAP_INFO_V2_COUNT_64
;
118 kr
= mach_vm_region_recurse(__self
, &addr
, &addr_size
, &nestingDepth
, (vm_region_info_t
)®ionInfo
, &count
);
120 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "mach_vm_region_recurse(%zu) error 0x%x (%s)\n",
121 tmp_size
, kr
, mach_error_string(kr
));
122 T_EXPECT_EQ(regionInfo
.object_id_full
, out_buffer
->data
[0].object_id
, "object_id_full does not match out_buffer->object[0]\n");
125 addr_size
= tmp_size
;
126 nestingDepth
= UINT_MAX
;
127 count
= VM_REGION_SUBMAP_INFO_V2_COUNT_64
;
128 kr
= mach_vm_region_recurse(__self
, &addr
, &addr_size
, &nestingDepth
, (vm_region_info_t
)®ionInfo
, &count
);
130 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "mach_vm_region_recurse(%zu) error 0x%x (%s)\n",
131 tmp_size
, kr
, mach_error_string(kr
));
132 T_EXPECT_EQ(regionInfo
.object_id_full
, out_buffer
->data
[1].object_id
, "object_id_full does not match out_buffer->object[1]\n");
134 kr
= vm_deallocate(__self
, tmp_buf
, tmp_size
);
136 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_deallocate(%zu) error 0x%x (%s)\n",
137 tmp_size
, kr
, mach_error_string(kr
));
139 kr
= vm_deallocate(__self
, tmp_buf2
, tmp_size
);
141 T_EXPECT_EQ(kr
, KERN_SUCCESS
, "vm_deallocate(%zu) error 0x%x (%s)\n",
142 tmp_size
, kr
, mach_error_string(kr
));
148 T_DECL(test_get_vmobject_list
, "Get owned vm_objects for process")