+
+static int
+sysctl_get_owned_vmobjects SYSCTL_HANDLER_ARGS
+{
+#pragma unused(oidp, arg1, arg2)
+
+ /* validate */
+ if (req->newlen != sizeof(mach_port_name_t) || req->newptr == USER_ADDR_NULL ||
+ req->oldidx != 0 || req->newidx != 0 || req->p == NULL) {
+ return EINVAL;
+ }
+
+ int error;
+ mach_port_name_t task_port_name;
+ task_t task;
+ int buffer_size = (req->oldptr != USER_ADDR_NULL) ? req->oldlen : 0;
+ vmobject_list_output_t buffer;
+ size_t output_size;
+
+ if (buffer_size) {
+ const int min_size = sizeof(vm_object_query_data_t) + sizeof(int64_t);
+
+ if (buffer_size < min_size) {
+ buffer_size = min_size;
+ }
+
+ buffer = kalloc(buffer_size);
+
+ if (!buffer) {
+ error = ENOMEM;
+ goto sysctl_get_vmobject_list_exit;
+ }
+ } else {
+ buffer = NULL;
+ }
+
+ /* we have a "newptr" (for write) we get a task port name from the caller. */
+ error = SYSCTL_IN(req, &task_port_name, sizeof(mach_port_name_t));
+
+ if (error != 0) {
+ goto sysctl_get_vmobject_list_exit;
+ }
+
+ task = port_name_to_task(task_port_name);
+ if (task == TASK_NULL) {
+ error = ESRCH;
+ goto sysctl_get_vmobject_list_exit;
+ }
+
+ /* copy the vmobjects and vmobject data out of the task */
+ if (buffer_size == 0) {
+ int64_t __size;
+ task_copy_vmobjects(task, NULL, 0, &__size);
+ output_size = (__size > 0) ? __size * sizeof(vm_object_query_data_t) + sizeof(int64_t) : 0;
+ } else {
+ task_copy_vmobjects(task, &buffer->data[0], buffer_size - sizeof(int64_t), &buffer->entries);
+ output_size = buffer->entries * sizeof(vm_object_query_data_t) + sizeof(int64_t);
+ }
+
+ task_deallocate(task);
+
+ error = SYSCTL_OUT(req, (char*) buffer, output_size);
+
+sysctl_get_vmobject_list_exit:
+ if (buffer) {
+ kfree(buffer, buffer_size);
+ }
+
+ return error;
+}
+
+SYSCTL_PROC(_vm, OID_AUTO, get_owned_vmobjects, CTLTYPE_OPAQUE | CTLFLAG_RD | CTLFLAG_WR | CTLFLAG_MASKED | CTLFLAG_KERN | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
+ 0, 0, sysctl_get_owned_vmobjects, "A", "get owned vmobjects in task");